【问题标题】:Why does my box Layout change size even after setting Sizes of JPanels为什么即使在设置 JPanel 的大小后我的框布局也会改变大小
【发布时间】:2021-10-27 04:15:12
【问题描述】:

我一直在尝试调整我的 JPanel 大小,同时使用 LayoutManager(例如 BoxLayout)以特定顺序排列该布局内的组件,我通过 NOT USING Box 实现了我希望它的外观布局管理器。

我想要在这张图片中的原始想法:

但我想在为面板使用 Box Layout Manager 时实现这一点,当我这样做时,我会得到以下输出:

我添加 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) {

}
}

MenuButton.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;
}
}

【问题讨论】:

  • 使用布局管理器的重点是避免使用this.Width = 1600; this.Height = 900;之类的东西。
  • 我一直在尝试调整我的 JPanel 尺寸 - 怎么做?对期望的行为进行口头描述。图像有助于显示发生的情况,但无法解释要求。您也不应该使用 ComponentListener。基本上,您的整个代码都在尝试创建自己的布局管理器,并且不允许布局管理器完成其工作。
  • 但是布局管理器会根据组件属性对 r8 进行布局,我如何为窗口提供大小会中断布局管理器的工作?????

标签: java swing size layout-manager boxlayout


【解决方案1】:

通过阅读MenuButton 的源代码,我意识到它根据鼠标事件绘制边框和背景。由于JButtons 支持Borders 和背景颜色,因此您不必自己执行此操作。因此,您可以改为创建一个 MouseListener 来更新这些属性并让它用这些属性重新绘制自己(我将在下面的代码示例中进行演示)。

不管怎样,回到你的主要问题,你可以这样做,只使用BoxLayouts:

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);
        });
    }
}

基本上,内容窗格包含BoxLayoutX_AXIS 中的两个彩色面板。然后左侧面板包含另一个带有标签和第一个按钮的BoxLayout 面板。然后就是处理每个Component 的最小、首选和最大大小。

如果您想避免嵌套面板,我想您可以在自定义绘制面板上使用GridBagLayout(绘制不同的背景颜色),这也将让您更有能力使用权重微调调整大小的行为因素。不过我没试过。

当你运行它时,记得用鼠标调整框架的大小,看看它的行为。

稍后您可以将两个createNonOpaqueVerticalGlue 方法调用替换为您想要的Components,因为我假设您稍后需要在黑色和绿色面板中添加更多内容。如果您需要一些垂直间隙,请使用vertical strut

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-05-30
    相关资源
    最近更新 更多