【问题标题】:Letting a Java Swing program layout itself again让 Java Swing 程序重新布局自身
【发布时间】:2009-07-17 11:59:24
【问题描述】:

我总是对 Java 布局有问题,但现在困扰我的主要问题是,当内容发生变化时,尤其是大小发生变化时,它的布局又不正确。举个例子:

package layouttest;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

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

public class LayoutTestStart extends JFrame implements ActionListener
{
    static JButton button= new JButton("Expand");
    static JTextArea f = new JTextArea("A medium sized text");
    static LayoutTestStart lst;

    public static void main(String[] args) {
        //Schedule a job for the event-dispatching thread:
        //creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGUI();
            }
        });
    }

    public static void createAndShowGUI()
    {
         lst  = new LayoutTestStart();
        lst.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel all = new JPanel();

        button.addActionListener(lst);

        all.add(button);
        all.add(f);
        lst.getContentPane().add(all);

        lst.setVisible(true);
        lst.pack();
    }
    @Override
    public void actionPerformed(ActionEvent e)
    {
        f.setText(f.getText()+"\n"+f.getText());

        // this doesn't work
        f.invalidate();

        // this does but it's cheating
//      lst.pack();
    }
}

我让它工作的唯一方法是调用 lst.pack(),但这是作弊,因为每个组件都应该有一个对其 JFrame 的引用,当一个组件是一个单独的类时,它会变得混乱。让这个示例运行的首选方法是什么?

【问题讨论】:

    标签: java swing layout


    【解决方案1】:

    revalidate 而不是invalidateinvalidate 只是将容器标记为需要布局。 revalidate 执行此操作,然后安排 validate

    BTW:我建议:避免从JFrame 和其他组件扩展;避免接口的多重继承并避免(可变)静态。

    【讨论】:

    • 你能在最后一段汤姆更详细地介绍一下吗?特别是,为什么要避免扩展组件?
    • 如果我在我的源代码中将 invalidate() 更改为 revalidate() ,它仍然无法正常工作——或者你是在建议别的什么吗?我知道我的代码很丑(尽管我可能不知道你给出的所有建议——我会看看),因为我想把我的例子放在一个类中:)。
    • @Pool 我不确定接口的多重继承(这似乎是接口的一半)。然而,扩展组件往往会污染你的 API,这使得每个人都更难使用。相反,您可能希望该组件成为您的类的成员,并提供像 getUI 这样的方法来在必要时访问它。
    【解决方案2】:

    嗯,一般来说,用户不喜欢每次按 Enter 时都会改变框架的大小。框架的设计应适应增长。因此,您可以将文本区域定义为具有给定数量的行和列。然后将文本区域添加到滚动窗格并将滚动窗格添加到框架。然后随着数据的变化,滚动条会根据需要出现或消失。

    但是,如果您确实需要动态变化的框架,那么您应该使用 pack()。您可以使用:

    SwingUtilities.windowForComponent(...) 
    

    这里的Component是ActionEvent的源组件,要找到Window to pack()。

    【讨论】:

    • 到目前为止,这似乎是我最好的选择
    【解决方案3】:

    首先,关于您的假设,您可以通过获取顶级祖先(组件上有这样的方法)来调用 pack 并计算出调用 pack.您可以创建一个静态方法并从需要的任何地方调用它。那会起作用的。

    另一个选项(也许是真正首选的选项)是使用一个布局管理器来适应这一点。 GridBagLayout 当然可以做到这一切,但有些人声称它不适合凡人使用。 MigLayout 是一个更加理智的开源布局管理器。

    【讨论】:

    • 我使用了类似于您的第一个建议的黑客攻击,但感觉不是很好。关于第二个选项:通常大小变化的字段被分层到一系列布局管理器中,所以我必须将它们全部更改为合理的布局管理器。
    • 我查看了 MigLayout,它看起来很棒(名称除外),但我不知道如何更改我的示例以使用 MigLayout 并自动工作。
    • 动态布局管理器(与默认不同)用于在组件增长和缩小以及框架增长和缩小时更改组件的位置,因此您不必为它显式编码.
    • 我试过这样做,但它不起作用。我把它变成了 JPanel all = new JPanel(new MigLayout());但这个例子仍然不起作用。你能发布一个完整的例子吗?
    • 我在当前环境中没有设置 MigLayout 来测试示例,但是您需要将字符串参数传递给 MigLayout 构造函数以定义组件所在的网格可以扩展,和多少,然后在面板上的 add 方法中,传递一个字符串作为第二个参数来指定组件可以增长多少。这在快速入门指南中有记录(包括字符串的内容)。 miglayout.com/QuickStart.pdf
    【解决方案4】:

    仅在 JTextArea 上的无效或验证不起作用,您必须更改顶部框架的大小,因为它不会自动更新它的大小。例如,您可以这样做(稍微更改代码,以删除静态变量):

    package layouttest;
    
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.JTextArea;    
    
    public class LayoutTestStart extends JFrame implements ActionListener{
    
    private JTextArea f = new JTextArea("A medium sized text");
    
    public LayoutTestStart(){
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        JPanel all = new JPanel();
        JButton button = new JButton("Expand");
        button.addActionListener(this);
    
        all.add(button);
        all.add(f);
        getContentPane().add(all);
    }
    
    @Override
    public void actionPerformed(ActionEvent e){
        javax.swing.SwingUtilities.invokeLater(new Runnable(){           
            @Override
            public void run(){
                f.setText(f.getText() + "\n" + f.getText());
                setSize(getPreferredSize());                
            }
        });
    
    }
    
    public static void main(String[] args){
        // Schedule a job for the event-dispatching thread:
        // creating and showing this application's GUI.
        javax.swing.SwingUtilities.invokeLater(new Runnable(){
            public void run(){
                LayoutTestStart lst = new LayoutTestStart();
                lst.setVisible(true);
                lst.pack();
            }
        });
    }
    }
    

    【讨论】:

      【解决方案5】:

      updateUI(); 永远不会失败!

      【讨论】:

      • updateUI() 用于 LAF 更改。这不是 LAF 更改,不应使用。
      猜你喜欢
      • 1970-01-01
      • 2014-10-08
      • 2012-01-29
      • 2019-04-04
      • 2018-05-03
      • 2014-12-20
      • 2016-08-26
      • 1970-01-01
      相关资源
      最近更新 更多