让Java程序重新布局自己

让Java程序重新布局自己,java,swing,layout,Java,Swing,Layout,我在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;

我在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的引用,当组件是单独的类时,JFrame会变得混乱。让这个示例工作的首选方法是什么?

首先,关于您的假设,您可以通过获取顶级anscestor(组件上有这样一种方法)来调用pack,并解决调用pack的问题。您可以创建一个静态方法,并从任何需要的地方调用它。那就行了


另一个选项(可能是真正喜欢的选项)是使用一个布局管理器来实现这一点。GridBagLayout当然可以做到这一切,但也有人声称它不是供凡人使用的。MigLayout是一个开源的布局管理器,它更明智。

revalidate
而不是
invalidate
<代码>无效仅将容器标记为需要布局<代码>重新验证执行此操作,然后安排一次
验证


顺便说一句:我建议:避免从
JFrame
和其他组件扩展;避免接口的多重继承并避免(可变)静态永远不会失败

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

但是,如果确实需要动态更改帧,则应使用pack()。您可以使用:

SwingUtilities.windowForComponent(...) 

如果组件是ActionEvent的源组件,则要查找要打包的窗口()。

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


我使用了与你的第一个建议类似的黑客技术,但感觉不太好。关于第二个选项:通常大小更改的字段被分层到一系列布局管理器中,因此我必须将它们全部更改为sane布局管理器。我看过MigLayout,它看起来很棒(除了名称),但我不知道如何更改示例以使用MigLayout并自动工作。动态布局管理器(与默认设置不同)用于在组件的增长和收缩以及框架的增长和收缩时更改组件的位置,这样您就不必显式地为其编写代码。我尝试过这样做,但不起作用。我将其制作成JPanel all=new JPanel(new MigLayout());但是这个示例仍然不起作用。您能发布一个完整的示例吗?我在当前环境中没有MigLayout设置来测试一个示例,但是您需要做的是将字符串参数传递给MigLayout构造函数,以定义组件所在的网格可以扩展,以及扩展的程度,然后在面板上的add方法中传递作为第二个参数的字符串,用于指定组件可以增长多少。这在《快速入门指南》中有记录(包括字符串的内容)。您可以在最后一段中详细介绍Tom吗?特别是,您为什么要避免扩展组件?如果我将invalidate()更改为revalidate()在我的源代码中,它仍然不起作用——或者你是在建议其他东西吗?我知道我的代码很难看(虽然我可能不知道你给出的所有建议——我会看一看),因为我想把我的示例放在一个类中:)。@Pool我不确定接口的多重继承(这似乎是接口的一半)。但是,扩展组件往往会污染您的API,这使得每个人都难以使用。相反,您希望组件成为类的成员,并在必要时提供类似于
getUI
的方法来访问它。updateUI()用于LAF更改。这不是LAF更改,不应使用。到目前为止,这似乎是我的最佳选择
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();
        }
    });
}
}