繁体   English   中英

JPanel的子组件绘制/布局问题

[英]JPanel's child components paint/layout problem

我遇到的问题是,当我的框架显示时(登录对话框后)按钮不在正确的位置,然后在几毫秒内它们会到达正确的位置(带有边框布局的面板中心)。

- 更新

在我的机器中,这个SSCCE在我运行它的10次中显示了布局问题:

import java.awt.BorderLayout;
import java.awt.Dimension;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TEST {

    public static void main(String[] args) throws Exception {

    SwingUtilities.invokeAndWait(new Runnable() {

        public void run() {

        System.out.println("Debug test...");

        JPanel btnPnl = new JPanel();
        btnPnl.add(new JButton("TEST"));

        JFrame f = new JFrame("TEST");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(btnPnl);
        f.setPreferredSize(new Dimension(800, 600));
        f.pack();
        f.setExtendedState(JFrame.MAXIMIZED_BOTH);
        f.setVisible(true);

        System.out.println("End debug test!");

        }
    });

    }

}

按钮首先出现在左上角,然后进入中心。 这是一个java bug吗?

--update

看起来SSCCE没有为每个尝试的人显示问题。 也许这是我的电脑性能问题。 我仍然认为Java Swing正在创建用于在幕后进行布局的新线程。 但我不确定。

--update

问题只发生在f.setExtendedState(JFrame.MAXIMIZED_BOTH);

你的问题引起了我的兴趣。 经过一些调查后,我想我确认了一些我记得设置窗口状态(最大化,恢复等)的东西,即设置状态是对操作系统的请求,并留给操作系统处理请求的一时兴起。 这意味着它在设置后是异步的,或者至少在稍后完成。 我确认使用日志记录并添加调整大小的侦听器,您可以看到在您的代码块退出后调整框架的大小。 因此,pack()会将组件布局为其首选大小。 因此,想象一下框架的尺寸为800x600,组件的位置如此(按钮水平居中于400左右)。 然后,操作系统将帧的大小更改为全屏(例如1024x768) - 片刻,您​​将看到按钮仍为400.然后帧处理新的大小并重新布置组件并使按钮居中在512左右。所以你会看到在此过程中转换的闪烁。 也许解决方案是不打包() - 它将保持零大小,用户将看到最小闪烁。

首先尝试此更改:

// pack()

如果看起来不错,那么您可能会遇到下一个问题...如果用户单击还原按钮,则整个框架会缩小为黑洞。 因此,尝试调整包后帧由于最大化而可预测地调整大小。 像这样的东西:

f.addComponentListener( new ComponentAdapter( ComponentEvent e ) {
  public void componentResized( Component) {
     if( f.getSize().getWidth() > 0 ) {
        e.getComponent().removeComponentListener( this );
        ((JFrame)e.getComponent()).pack();
     }
  }
}

因此,如果用户稍后单击“恢复”按钮,则框架将具有准备好的包装尺寸。

--update

好的,最后一次尝试。 虽然我认为我对问题的描述有一些道理,但我提供的解决方案却没有做任何事情。 这是最后一次尝试。 删除pack()和setPreferredSize()并替换为将大小设置为屏幕大小。 这似乎可以减少我的系统上的闪烁。 这是因为初始布局和稍后完成的最大化布局之间应该没有区别。 如果在还原和最大化之间切换,则可以看到此信息。 虽然切换两者时仍然看到一个非常轻微的闪烁,但至少在首次显示时看起来更好看。

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class TEST {

    public static void main(String[] args) throws Exception {

    SwingUtilities.invokeAndWait(new Runnable() {

        public void run() {

        System.out.println("Debug test...");

        JPanel btnPnl = new JPanel();
        btnPnl.add(new JButton("TEST"));

        JFrame f = new JFrame("TEST");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.getContentPane().setLayout(new BorderLayout());
        f.getContentPane().add(btnPnl);
//        f.setPreferredSize(new Dimension(800, 600));
//        f.pack();
        f.setSize( Toolkit.getDefaultToolkit().getScreenSize() );
        f.setExtendedState(JFrame.MAXIMIZED_BOTH);
        f.setVisible(true);

        System.out.println("End debug test!");

        }
    });

-麦克风

我猜你需要在让你的框架可见之前调用pack()。

如果你不在事件线程上调用上面的代码,那么你就有竞争条件并且所有的赌注都关闭了 - 你只能从EDT(事件派遣线程)操纵GUI。


编辑:我在我的系统上尝试了你的SSCCE,它没有表现出你所看到的行为。 我尝试了大约50次,并尝试通过循环代码创建10个窗口。 我在Windows XP SP3上运行1.6.0_18。

也许你错过了一个frameThatContainsCentralPanel.pack()

好吧,如果它适用于SSCCE,那么你已经证明问题不在于基本逻辑。 SSCCE和您的真实代码之间必定存在不同之处。 由于我们无法访问您的真实代码,因此您需要自己进行调试以了解其中的区别。

但是,在这种情况下,更好的解决方案是使用CardLayout,它旨在让您轻松交换面板。 阅读Swing教程以获取一个工作示例。

或者另一种方法是使用“登录对话框”。 登录成功后,您将使用适用于您的应用程序的面板显示主框架。

“然后在几毫秒内”部分听起来像你需要在你的框架上调用validate() 此外,如果使用f.pack() ,则面板需要首选大小,因为pack()为父组件提供了首选大小,并根据它们调整大小。

如果我复制了你的代码,我遇到了同样的问题,但不是那么重。

我通过在包装前为您的框架设置首选尺寸来解决它。 所以:

import java.awt.Dimension;

System.out.println("Debug test...");

JPanel btnPnl = new JPanel();
btnPnl.add(new JButton("TEST"));

JFrame f = new JFrame("TEST");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
f.getContentPane().add(btnPnl);
f.setPreferredSize(new Dimension(800, 600));
f.pack();
f.setVisible(true);
System.out.println("End debug test!");

我在Linux上运行。

这确实很奇怪......我确信这是关于摇摆树中所有容器大小的东西。

我希望在显示之前框架最大化,但在检查之后我确信在显示后,linux框架上的框架最大化。 在调用setVisible之前,可以使帧大小等于屏幕大小,或者可以使组件不可见,直到您知道它具有首选的初始大小。 这是修改后的示例,它显示了帧激活后的元素(在linux激活的事件来得太晚,不显示“跳跃按钮”):

import javax.swing.JButton;

import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities;

公共课TEST {

public static void main(String[] args) throws Exception {

    SwingUtilities.invokeAndWait(new Runnable() {

        public void run() {

            final JPanel btnPnl = new JPanel();
            btnPnl.add(new JButton("TEST"));

            final JFrame f = new JFrame("TEST");
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setContentPane(btnPnl);
            // calculate preferred size for TEST frame
            // f.isDisplayable() will become true
            f.pack();

            // extended state, if can be applied, needs to be called after f.isDisplayable()
            WindowListener maxBoth = new WindowAdapter() {

                @Override
                public void windowOpened(WindowEvent e) {
                    f.setExtendedState(Frame.MAXIMIZED_BOTH);
                }
            };

            // after windows has been opened - maximize both
            f.addWindowListener(maxBoth);

            // initially hide the elements
            // after maximized state has been applied show them
            f.getContentPane().setVisible(false);
            f.addWindowListener(new WindowAdapter() {

                @Override
                public void windowActivated(WindowEvent e) {
                    f.getContentPane().setVisible(true);
                    // remove this listener
                    f.removeWindowStateListener(this);
                }
            });

            // set the frame visible
            f.setVisible(true);
        }
    });
}

}

看起来像一个java bug。 我已经报告了它(但由于某些原因它仍然没有显示错误报告)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM