我一直在尝试调整我的 JPanel 大小,同时使用 LayoutManager(例如 BoxLayout)以特定顺序排列该布局内的组件,我通过不使用 Box 实现了我想要的外观布局管理器。
我想要在这张图片中的原始想法:
但我想在使用面板的框布局管理器时实现这一点,当我这样做时,我得到以下输出:
添加 BoxLayout 时得到的输出:
这是代码:
AppPanel.java:
import javax.swing.*;
import java.awt.*;
public class AppPanel extends JPanel {
int Width, Height;
MenuButton mb;
AppPanel(int width, int height)
{
this.Width = width;
this.Height = height;
this.setMinimumSize(new Dimension(this.Width/ 4, this.Height));
this.setPreferredSize(new Dimension(3 * this.Width/ 4, this.Height));
this.setMaximumSize(new Dimension(this.Width/ 4, this.Height));
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
this.setBackground(Color.GREEN);
this.mb = new MenuButton("HELLO",this.getPreferredSize());
this.add(mb);
}
public void update(int width, int height){
this.Width = width;
this.Height = height;
this.setPreferredSize(new Dimension(3 * this.Width/ 4, this.Height));
// this.mb.update(this.mb.getGraphics());
}
}
MenuPanel.java:
import javax.swing.*;
import java.awt.*;
public class MenuPanel extends JPanel {
JLabel l_AppMenu;
int Width, Height;
MenuButton mb;
MenuPanel(int width, int height)
{
this.Width = width;
this.Height = height;
this.setMinimumSize(new Dimension(this.Width/ 4, this.Height));
this.setPreferredSize(new Dimension(this.Width/ 4, this.Height));
this.setMaximumSize(new Dimension(this.Width/ 4, this.Height));
this.setLayout(new BoxLayout(this,BoxLayout.Y_AXIS));
this.setBackground(Color.BLACK);
this.mb = new MenuButton("HELLO 1",this.getPreferredSize());
l_AppMenu = new JLabel("App Menu");
l_AppMenu.setForeground(Color.GRAY);
this.add(l_AppMenu);
this.add(mb);
}
public void update(int width, int height){
this.Width = width;
this.Height = height;
this.setPreferredSize(new Dimension(3 * this.Width/ 4, this.Height));
// this.mb.update(this.mb.getGraphics());
}
}
MainFrame.java:
import javax.swing.*;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
public class MainFrame extends JFrame implements ComponentListener {
int Width, Height;
MenuPanel mp;
AppPanel ap;
public MainFrame()
{
this.Width = 1600;
this.Height = 900;
mp = new MenuPanel(this.Width, this.Height);
ap = new AppPanel(this.Width, this.Height);
this.setSize(this.Width, this.Height);
this.setVisible(true);
this.setTitle("ToolKit");
this.setDefaultCloseOperation(this.EXIT_ON_CLOSE );
this.add(mp);
this.add(ap);
addComponentListener(this);
this.getContentPane().setLayout(new BoxLayout(this.getContentPane(),BoxLayout.X_AXIS));
}
public static void main(String[] args)
{
MainFrame m = new MainFrame();
}
@Override
public void componentResized(ComponentEvent componentEvent) {
System.out.println(this.getWidth() + " " + this.getHeight());
mp.update(this.getWidth(), this.getHeight());
ap.update(this.getWidth(), this.getHeight());
// this.setSize(this.getHeight() * 16 / 9 , this.getHeight());
}
@Override
public void componentMoved(ComponentEvent componentEvent) {
}
@Override
public void componentShown(ComponentEvent componentEvent) {
}
@Override
public void componentHidden(ComponentEvent componentEvent) {
}
}
菜单按钮.java:
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
public class MenuButton extends JButton implements MouseListener {
String Text;
int Entered = 0;
int Pressed = 0;
MenuButton(String str, Dimension d)
{
super(str);
this.Text = str;
addMouseListener(this);
this.setMinimumSize(new Dimension((int) d.getWidth() - 20,40));
this.setMaximumSize(new Dimension((int) d.getWidth() - 20,40));
this.setPreferredSize(new Dimension((int) d.getWidth() - 20,40));
this.setBorder(null);
}
public void paintComponent(Graphics g)
{
if(this.Pressed == 0) {
g.setColor(new Color(182, 25, 25));
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(new Color(255, 107, 107));
g.fillRect(10, 10, this.getWidth() - 20, this.getHeight() - 20);
}
else{
g.setColor(new Color(255, 107, 107));
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(new Color(255, 107, 107));
g.fillRect(10, 10, this.getWidth() - 20, this.getHeight() - 20);
}
if(this.Entered == 0) {
g.setColor(new Color(253, 210, 199));
g.drawString(this.Text, this.getWidth() / 2 - g.getFontMetrics().stringWidth(this.Text) / 2, 25);
}
else{
g.setColor(new Color(1, 36, 67));
g.drawString(this.Text, this.getWidth() / 2 - g.getFontMetrics().stringWidth(this.Text) / 2, 25);
}
}
@Override
public void mouseClicked(MouseEvent mouseEvent) {
}
@Override
public void mousePressed(MouseEvent mouseEvent) {
this.Pressed = 1;
}
@Override
public void mouseReleased(MouseEvent mouseEvent) {
this.Pressed = 0;
}
@Override
public void mouseEntered(MouseEvent mouseEvent) {
this.Entered = 1;
}
@Override
public void mouseExited(MouseEvent mouseEvent) {
this.Entered = 0;
}
}
最佳答案
通过阅读MenuButton
的源代码,我意识到它根据鼠标事件绘制边框和背景。您不必自己执行此操作,因为 JButton
支持 Border
和背景颜色。因此,您可以创建一个 MouseListener
来更新这些属性并让它用这些属性重新绘制自身(我将在下面的代码示例中进行演示)。
无论如何,回到你的主要问题,这里是你可以如何做到这一点,只使用 BoxLayout
:
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Objects;
import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.border.Border;
public class BoxLayoutTest {
public static final class MainButtonAdapter extends MouseAdapter {
private final Color fgOnEntered, fgOnNotEntered, bgOnPressed, bgOnNotPressed;
private final Border onPressed, onNotPressed;
public MainButtonAdapter(final Color fgOnEntered,
final Color fgOnNotEntered,
final Color bgOnPressed,
final Color bgOnNotPressed,
final Border onPressed,
final Border onNotPressed) {
this.fgOnEntered = Objects.requireNonNull(fgOnEntered);
this.fgOnNotEntered = Objects.requireNonNull(fgOnNotEntered);
this.bgOnPressed = Objects.requireNonNull(bgOnPressed);
this.bgOnNotPressed = Objects.requireNonNull(bgOnNotPressed);
this.onPressed = Objects.requireNonNull(onPressed);
this.onNotPressed = Objects.requireNonNull(onNotPressed);
}
private void inside(final Component src) {
if (src != null) {
src.setForeground(fgOnEntered);
src.repaint();
}
}
private void released(final Component src) {
if (src != null) {
if (src instanceof JComponent)
((JComponent) src).setBorder(onNotPressed);
src.setBackground(bgOnNotPressed);
src.repaint();
}
}
//@Override
//public void mouseWheelMoved(final MouseWheelEvent e) {
// inside(e.getComponent());
//}
//
//@Override
//public void mouseDragged(final MouseEvent e) {
// inside(e.getComponent());
//}
@Override
public void mouseMoved(final MouseEvent e) {
inside(e.getComponent());
}
@Override
public void mouseClicked(final MouseEvent e) {
released(e.getComponent());
}
@Override
public void mousePressed(final MouseEvent e) {
final Component src = e.getComponent();
if (src != null) {
if (src instanceof JComponent)
((JComponent) src).setBorder(onPressed);
src.setBackground(bgOnPressed);
src.repaint();
}
}
@Override
public void mouseReleased(final MouseEvent e) {
released(e.getComponent());
}
@Override
public void mouseEntered(final MouseEvent e) {
inside(e.getComponent());
}
@Override
public void mouseExited(final MouseEvent e) {
final Component src = e.getComponent();
if (src != null) {
src.setForeground(fgOnNotEntered);
src.repaint();
}
}
}
public static JButton createMainButton(final String text,
final MouseAdapter adapter,
final Border border,
final Color background,
final Color foreground,
final ActionListener aL) {
final JButton button = (text == null)? new JButton(): new JButton(text);
if (adapter != null) {
button.addMouseListener(adapter);
button.addMouseMotionListener(adapter);
button.addMouseWheelListener(adapter);
}
if (border != null)
button.setBorder(border);
if (background != null) {
button.setContentAreaFilled(false);
button.setOpaque(true);
button.setBackground(background);
}
if (foreground != null)
button.setForeground(foreground);
if (aL != null)
button.addActionListener(aL);
button.setFocusPainted(false);
return button;
}
public static JPanel createBoxLayoutPanel(final int axis,
final Component... components) {
final JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, axis));
if (components != null)
for (final Component c: components) {
if (!c.isMinimumSizeSet())
c.setMinimumSize(c.getPreferredSize());
if (!c.isMaximumSizeSet())
c.setMaximumSize(new Dimension(Short.MAX_VALUE, Short.MAX_VALUE));
panel.add(c);
}
return panel;
}
public static JLabel label(final String text,
final Component labelFor,
final Color foreground) {
final JLabel jLabel = new JLabel(text, JLabel.CENTER);
jLabel.setForeground(foreground);
jLabel.setLabelFor(labelFor);
return jLabel;
}
public static Box.Filler createNonOpaqueVerticalGlue() {
final Box.Filler vglue = new Box.Filler(new Dimension(0,0), new Dimension(0,0), new Dimension(0, Short.MAX_VALUE));
vglue.setOpaque(false);
return vglue;
}
public static void main(final String[] args) {
SwingUtilities.invokeLater(() -> {
final int buttonBorderThickness = 10,
paddingThickness = 20;
final Color borderOnPressed = new Color(182, 25, 25),
borderOnNotPressed = new Color(255, 107, 107),
backgroundOnPressed = new Color(255, 107, 107),
backgroundOnNotPressed = new Color(255, 107, 107),
foregroundOnEntered = new Color(253, 210, 199),
foregroundOnNotEntered = new Color(1, 36, 67),
leftBackground = Color.BLACK,
rightBackground = Color.GREEN,
labelForeground = Color.LIGHT_GRAY;
final String firstButtonText = "Main button with long text as label",
secondButtonText = "Short",
labelText = "Some random text.";
final Border onPressed = BorderFactory.createLineBorder(borderOnPressed, buttonBorderThickness),
onNotPressed = BorderFactory.createLineBorder(borderOnNotPressed, buttonBorderThickness),
padding = BorderFactory.createEmptyBorder(paddingThickness, paddingThickness, paddingThickness, paddingThickness);
final MainButtonAdapter mainButtonAdapter = new MainButtonAdapter(foregroundOnEntered, foregroundOnNotEntered, backgroundOnPressed, backgroundOnNotPressed, onPressed, onNotPressed);
final JButton firstButton = createMainButton(firstButtonText, mainButtonAdapter, onNotPressed, backgroundOnNotPressed, foregroundOnNotEntered, null),
secondButton = createMainButton(secondButtonText, mainButtonAdapter, onNotPressed, backgroundOnNotPressed, foregroundOnNotEntered, null);
final Dimension secondButtonPreferredSize = secondButton.getPreferredSize();
secondButton.setMaximumSize(new Dimension(Short.MAX_VALUE, secondButtonPreferredSize.height));
final JLabel lbl = label(labelText, firstButton, labelForeground);
lbl.setMaximumSize(lbl.getPreferredSize());
final JPanel firstPanel = createBoxLayoutPanel(BoxLayout.X_AXIS, lbl, Box.createHorizontalStrut(paddingThickness), firstButton);
firstPanel.setOpaque(false);
firstPanel.setMaximumSize(new Dimension(Short.MAX_VALUE, firstPanel.getPreferredSize().height));
//Ucomment the following lines to get bigger size proportion for the right (green) panel...
//secondButtonPreferredSize.width = Math.max(500, secondButtonPreferredSize.width);
//secondButton.setMinimumSize(secondButtonPreferredSize);
//secondButton.setPreferredSize(secondButtonPreferredSize);
final JPanel left = createBoxLayoutPanel(BoxLayout.Y_AXIS, firstPanel, createNonOpaqueVerticalGlue() /*replace this "glue" with your components...*/);
left.setBorder(padding);
left.setBackground(leftBackground);
final JPanel right = createBoxLayoutPanel(BoxLayout.Y_AXIS, secondButton, createNonOpaqueVerticalGlue() /*replace this "glue" with your components...*/);
right.setBorder(padding);
right.setOpaque(false); //Could almost be 'right.setBackground(rightBackground);' instead.
final JPanel contents = createBoxLayoutPanel(BoxLayout.X_AXIS, left, right);
contents.setBackground(rightBackground); //That's why we called 'right.setOpaque(false);' previously.
final JFrame frame = new JFrame("BoxLayout test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(contents);
frame.pack();
//frame.setSize(Math.max(1600, frame.getWidth()), Math.max(900, frame.getHeight()));
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
}
基本上,内容 Pane 包含 X_AXIS
上 BoxLayout
中的两个彩色面板。然后左侧面板包含另一个带有标签和第一个按钮的 BoxLayout
面板。然后就是处理每个组件
的最小、首选和最大尺寸。
如果你想避免嵌套面板,我想你可以在自定义绘制的面板上使用GridBagLayout
(以绘制不同的背景颜色),这也将为你提供更多的微调能力使用权重因子的调整大小行为。不过我还没试过。
运行时,请记住用鼠标调整框架大小以查看其行为。
稍后您可以将两个 createNonOpaqueVerticalGlue
方法调用替换为您想要的 Component
,因为我假设您稍后需要黑色和绿色面板中的更多内容。如果您需要一些垂直间隙,请使用 vertical strut .
关于java - 为什么即使在设置 JPanel 的大小后,我的框布局也会更改大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68949746/