Swing组件setSize()/setBounds()问题

发布于 2025-01-01 10:22:51 字数 6649 浏览 0 评论 0原文

内容


  1. 概述 问题
  2. 示例代码
  3. 屏幕截图

1. 问题概述


因此,我正在为正在开发的复杂程序编写 GUI,并且我厌倦了在调整窗口大小时尝试让组件正确缩放。

起初,我在 jframe 和每个 jpanel 中使用了多个布局,以尝试正确放置组件并适当缩放它们。自然地,我厌倦了它们,我开始尝试动态缩放和设置组件的 x,y 位置(这更容易:D)。

基本上我试图将屏幕分为三个部分:左边距(JSplitPane)、中心(JTabbedPane)和右边距(JSplitPane)。我认为目前内部组件并不重要。 主要问题是右侧的 JSplitPane 会在整个窗口上缩放,尽管我使用 setBounds() 将 x,y 放在右侧并将大小设置为总宽度的 21%。它与其他面板的交互似乎很奇怪。


2. 示例代码


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;

import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Dimension;

@SuppressWarnings("deprecation")
public class test extends JFrame implements WindowListener {

/* Constants =========================================================================*/
    private         final   double      LEFT_SIZE           =   .21;
    private         final   double      CENTER_SIZE         =   .58;
    private         final   double      RIGHT_SIZE          =   .21;
    private         final   int         TOP_PADDING         =   50;
    private         final   int         LEFT_PADDING        =   4;
    private         final   int         RIGHT_PADDING       =   4;
    private         final   int         BOTTOM_PADDING      =   4;
    private         final   int         MIN_WIDTH           =   640;
    private         final   int         MIN_HEIGHT          =   480;

    public  static  final   String      INIT_TITLE          =   "TestFrame v0.01";
/* End Constants =====================================================================*/

/* Instance Variables ================================================================*/
    private                 int         contentWidth;
    private                 int         contentHeight;
/* End Instance Variables ============================================================*/

/* Objects ===========================================================================*/        
    public  static  test        window;     

    /* Begin Frame Design =========================================================== */
        private         JSplitPane      left;
        private         JButton           button1;  private     JButton     button2;            
        private         JTabbedPane     center;
        private         JPanel            panel1;       private     JPanel      panel2;         
        private         JSplitPane      right;
        private         JButton           button3;  private     JButton     button4;
    /* End Frame Design ============================================================= */

/* End Objects ====================================================================== */

/** Initializes and Places all GUI elements **/
public test ( String windowName ) {
    super(windowName);              //call parent constructor
    this.addWindowListener(this);   //adds window event functionality such as close

    this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH); //Starts program maximized
    this.setMinimumSize(new Dimension(MIN_WIDTH,MIN_HEIGHT));
    this.setVisible(true);
    this.setMaximumSize(this.getSize());        

    /* Begin Init JFrame this ------------------------------------------------------------ */       
            button1 = new JButton("button1");               
            button2 = new JButton("button2");               
        left = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button1, button2);
        left.setResizeWeight(1);

            button3 = new JButton("button3");               
            button4 = new JButton("button4");               
        right = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button3, button4);
        right.setResizeWeight(.25);

            panel1 = new JPanel();              
            panel2 = new JPanel();              
        center = new JTabbedPane();
        center.addTab("Panel1", panel1);
        center.addTab("Panel2", panel2);

        this.add(left);
        this.add(center);
        this.add(right);

        this.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized    (ComponentEvent e) {
                window.contentWidth = window.getWidth() - window.LEFT_PADDING - window.RIGHT_PADDING;
                window.contentHeight = window.getHeight() - window.TOP_PADDING - window.BOTTOM_PADDING;

                window.left.setBounds               (   0,                                                  0,  (int)(window.contentWidth * window.LEFT_SIZE),      window.contentHeight);
                window.center.setBounds             (   window.left.getWidth(),                             0,  (int)(window.contentWidth * window.CENTER_SIZE),    window.contentHeight);
                window.panel1.setBounds             (   0,                                                  0,  (int)(window.contentWidth * window.CENTER_SIZE),    window.contentHeight);
                window.panel2.setBounds             (   0,                                                  0,  (int)(window.contentWidth * window.CENTER_SIZE),    window.contentHeight);
                window.right.setBounds              (   window.left.getWidth() + window.center.getWidth(),  0,  (int)(window.contentWidth * window.RIGHT_SIZE),     window.contentHeight);
             }
            public void componentHidden     (ComponentEvent e) {}
            public void componentMoved      (ComponentEvent e) {}
            public void componentShown      (ComponentEvent e) {}    

        });
        /* End Init JFrame this -------------------------------------------------------------- */
}

// window event abstracts
@Override
public void windowClosing       (WindowEvent event)     { window.dispose(); System.exit(0); } 
public void windowClosed        (WindowEvent event)     {}
public void windowDeiconified   (WindowEvent event)     {} 
public void windowIconified     (WindowEvent event)     {} 
public void windowActivated     (WindowEvent event)     {} 
public void windowDeactivated   (WindowEvent event)     {} 
public void windowOpened        (WindowEvent event)     {}

public static void main(String[] args){     
    window = new test(INIT_TITLE); 
    window.setVisible(true);
}
}

3. 屏幕截图


Screenshot1 Screenshot2

Contents


  1. Overview
  2. Example Code
  3. Screenshots of Problem

1. Overview of problem


So I'm writing a GUI for a complicated program I'm developing, and I get tired of trying to get components to scale correctly when the window is resized.

At first I was using several layouts inside the jframe, and each jpanel to try and place the components correctly and scale them appropriately. Naturally, I got fed up with them, and I started trying to scale and set the x,y positions of the components dynamically (it's so much easier :D).

Basically I'm trying to divide the screen into three sections left margin (JSplitPane), center (JTabbedPane), and right margin (JSplitPane). I don't think the internal components matter at this point. The main problem is the right JSplitPane scales over the whole window despite my using setBounds() to place the x,y over on the right and set the size to 21% of the total width. It seems to interact weird with the other panels.


2. Example Code


import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;

import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import java.awt.Dimension;

@SuppressWarnings("deprecation")
public class test extends JFrame implements WindowListener {

/* Constants =========================================================================*/
    private         final   double      LEFT_SIZE           =   .21;
    private         final   double      CENTER_SIZE         =   .58;
    private         final   double      RIGHT_SIZE          =   .21;
    private         final   int         TOP_PADDING         =   50;
    private         final   int         LEFT_PADDING        =   4;
    private         final   int         RIGHT_PADDING       =   4;
    private         final   int         BOTTOM_PADDING      =   4;
    private         final   int         MIN_WIDTH           =   640;
    private         final   int         MIN_HEIGHT          =   480;

    public  static  final   String      INIT_TITLE          =   "TestFrame v0.01";
/* End Constants =====================================================================*/

/* Instance Variables ================================================================*/
    private                 int         contentWidth;
    private                 int         contentHeight;
/* End Instance Variables ============================================================*/

/* Objects ===========================================================================*/        
    public  static  test        window;     

    /* Begin Frame Design =========================================================== */
        private         JSplitPane      left;
        private         JButton           button1;  private     JButton     button2;            
        private         JTabbedPane     center;
        private         JPanel            panel1;       private     JPanel      panel2;         
        private         JSplitPane      right;
        private         JButton           button3;  private     JButton     button4;
    /* End Frame Design ============================================================= */

/* End Objects ====================================================================== */

/** Initializes and Places all GUI elements **/
public test ( String windowName ) {
    super(windowName);              //call parent constructor
    this.addWindowListener(this);   //adds window event functionality such as close

    this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH); //Starts program maximized
    this.setMinimumSize(new Dimension(MIN_WIDTH,MIN_HEIGHT));
    this.setVisible(true);
    this.setMaximumSize(this.getSize());        

    /* Begin Init JFrame this ------------------------------------------------------------ */       
            button1 = new JButton("button1");               
            button2 = new JButton("button2");               
        left = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button1, button2);
        left.setResizeWeight(1);

            button3 = new JButton("button3");               
            button4 = new JButton("button4");               
        right = new JSplitPane(JSplitPane.VERTICAL_SPLIT, button3, button4);
        right.setResizeWeight(.25);

            panel1 = new JPanel();              
            panel2 = new JPanel();              
        center = new JTabbedPane();
        center.addTab("Panel1", panel1);
        center.addTab("Panel2", panel2);

        this.add(left);
        this.add(center);
        this.add(right);

        this.addComponentListener(new ComponentListener() {
            @Override
            public void componentResized    (ComponentEvent e) {
                window.contentWidth = window.getWidth() - window.LEFT_PADDING - window.RIGHT_PADDING;
                window.contentHeight = window.getHeight() - window.TOP_PADDING - window.BOTTOM_PADDING;

                window.left.setBounds               (   0,                                                  0,  (int)(window.contentWidth * window.LEFT_SIZE),      window.contentHeight);
                window.center.setBounds             (   window.left.getWidth(),                             0,  (int)(window.contentWidth * window.CENTER_SIZE),    window.contentHeight);
                window.panel1.setBounds             (   0,                                                  0,  (int)(window.contentWidth * window.CENTER_SIZE),    window.contentHeight);
                window.panel2.setBounds             (   0,                                                  0,  (int)(window.contentWidth * window.CENTER_SIZE),    window.contentHeight);
                window.right.setBounds              (   window.left.getWidth() + window.center.getWidth(),  0,  (int)(window.contentWidth * window.RIGHT_SIZE),     window.contentHeight);
             }
            public void componentHidden     (ComponentEvent e) {}
            public void componentMoved      (ComponentEvent e) {}
            public void componentShown      (ComponentEvent e) {}    

        });
        /* End Init JFrame this -------------------------------------------------------------- */
}

// window event abstracts
@Override
public void windowClosing       (WindowEvent event)     { window.dispose(); System.exit(0); } 
public void windowClosed        (WindowEvent event)     {}
public void windowDeiconified   (WindowEvent event)     {} 
public void windowIconified     (WindowEvent event)     {} 
public void windowActivated     (WindowEvent event)     {} 
public void windowDeactivated   (WindowEvent event)     {} 
public void windowOpened        (WindowEvent event)     {}

public static void main(String[] args){     
    window = new test(INIT_TITLE); 
    window.setVisible(true);
}
}

3. Screenshots


Screenshot1
Screenshot2

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡写薰衣草的香 2025-01-08 10:22:51

我认为目前内部组件并不重要。

正如我应该避免在 Java Swing 中使用 set[Preferred|Maximum|Minimum]Size 方法吗?中讨论的,事实并非如此。布局的正确使用依赖取决于组件的首选尺寸。该尺寸是根据内容仔细计算的。正如您的示例所示,第二次猜测注定会失败。

相反,添加组件和 pack() 框架。在下面的示例中,中心面板返回任意结果以显示 pack() 是如何工作的。

附录:@mKorbel 提出的另外两点很有帮助:

  • Swing GUI 对象应该事件调度线程

  • 另请参阅此示例,该示例展示了如何在 中使用 setDividerLocation() invokeLater()

在此处输入图像描述

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import java.awt.Dimension;
import java.awt.EventQueue;

public class Test extends JFrame {

    public static final String INIT_TITLE = "TestFrame v0.02";
    public static Test window;
    private JSplitPane left;
    private JTabbedPane center;
    private JSplitPane right;

    public Test(String windowName) {
        super(windowName);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        left = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            new JButton("button1"), new JButton("button2"));
        left.setResizeWeight(0.5);

        right = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            new JButton("button3"), new JButton("button4"));
        right.setResizeWeight(0.5);

        center = new JTabbedPane();
        center.addTab("Panel1", new MyPanel());
        center.addTab("Panel2", new MyPanel());

        this.add(left, BorderLayout.WEST);
        this.add(center, BorderLayout.CENTER);
        this.add(right, BorderLayout.EAST);

        this.pack();
        this.setLocationByPlatform(true);
        this.setVisible(true);
    }

    private static class MyPanel extends JPanel {

        private Dimension d = new Dimension(320, 240);

        @Override
        public Dimension getPreferredSize() {
            return d;
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                window = new Test(INIT_TITLE);
                window.setVisible(true);
            }
        });
    }
}

I don't think the internal components matter at this point.

As discussed in Should I avoid the use of set[Preferred|Maximum|Minimum]Size methods in Java Swing?, nothing could be further from the truth. Correct use of layouts relies on a component's preferred size. That size is carefully calculated based on the contents. Second guessing, as shown in your example, is doomed to fail.

Instead, add components and pack() the frame. In the example below, the center panel returns an arbitrary result to show how pack() does its work.

Addendum: Two additional points helpfully adduced by @mKorbel:

  • Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

  • See also this example that shows how to use setDividerLocation() in invokeLater().

enter image description here

import java.awt.BorderLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import java.awt.Dimension;
import java.awt.EventQueue;

public class Test extends JFrame {

    public static final String INIT_TITLE = "TestFrame v0.02";
    public static Test window;
    private JSplitPane left;
    private JTabbedPane center;
    private JSplitPane right;

    public Test(String windowName) {
        super(windowName);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        left = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            new JButton("button1"), new JButton("button2"));
        left.setResizeWeight(0.5);

        right = new JSplitPane(JSplitPane.VERTICAL_SPLIT,
            new JButton("button3"), new JButton("button4"));
        right.setResizeWeight(0.5);

        center = new JTabbedPane();
        center.addTab("Panel1", new MyPanel());
        center.addTab("Panel2", new MyPanel());

        this.add(left, BorderLayout.WEST);
        this.add(center, BorderLayout.CENTER);
        this.add(right, BorderLayout.EAST);

        this.pack();
        this.setLocationByPlatform(true);
        this.setVisible(true);
    }

    private static class MyPanel extends JPanel {

        private Dimension d = new Dimension(320, 240);

        @Override
        public Dimension getPreferredSize() {
            return d;
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                window = new Test(INIT_TITLE);
                window.setVisible(true);
            }
        });
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文