Java Swing:更改隐藏帧上的标签,然后在EDT上以相反的顺序显示帧 问题

Java Swing:更改隐藏帧上的标签,然后在EDT上以相反的顺序显示帧 问题,java,swing,edt,Java,Swing,Edt,我在swing中创建了一个对话框(JRE 6 update 10,Ubuntu linux)。用户使用完对话框后,该对话框将隐藏。当用户单击另一帧中的按钮时,框上的标签将根据按钮进行更改,然后再次显示框 我遇到的问题是,在标签更改之前显示该框,即使在编程上,我以相反的顺序进行调用。这会导致框出现,然后标签会发生变化,这在我们的慢速目标硬件上看起来“有问题”。EDT似乎将帧setVisible(true)安排在标签setText(…)之前;它优先考虑这个电话。有没有办法让EDT将setVisibl

我在swing中创建了一个对话框(JRE 6 update 10,Ubuntu linux)。用户使用完对话框后,该对话框将隐藏。当用户单击另一帧中的按钮时,框上的标签将根据按钮进行更改,然后再次显示框

我遇到的问题是,在标签更改之前显示该框,即使在编程上,我以相反的顺序进行调用。这会导致框出现,然后标签会发生变化,这在我们的慢速目标硬件上看起来“有问题”。EDT似乎将帧setVisible(true)安排在标签setText(…)之前;它优先考虑这个电话。有没有办法让EDT将setVisible(true)安排在setText(..)之后执行

请注意,该代码是通过已在EDT上执行的按钮单击调用的,因此不能使用SwingUtilities.invokeAndWait。我尝试过使用invokeLater方法,但EDT仍然会重新调度它

复制 在调试模式下在IDE中运行以下代码,并在显示和隐藏“对话框”框架后打断showButton的操作代码。标签的setText(..)更改不会立即影响GUI,但框架的setVisible(true)会立即影响GUI。然后逐步完成EDT,您将看到setText最终发生在EDT时间表的较低位置

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

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.WindowConstants;

public class DemonstrateFramePaintEDTPriority {

static class MyFrame extends JFrame {

    private JFrame frame;
    private JLabel label;
    int i = 0;

    public MyFrame() {
        // Some label strings
        final String string[] = new String[] { "label text one",
                "label 2222222", "3 3 3 3 3 3 3" };

        // Create GUI components.
        frame = new JFrame("Dialog");
        label = new JLabel("no text set on this label yet");
        frame.setSize(500, 200);
        frame.setLayout(new FlowLayout());
        frame.add(label);

        // Add show and hide buttons.
        JButton showButton = new JButton("show dialog");
        showButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // Set the label text - THIS HAPPENS AFTER frame.setVisible
                label.setText(string[i]);

                // Select new label text for next time.
                i++;
                if (i >= string.length) {
                    i = 0;
                }

                // Show dialog - THIS HAPPENS BEFORE label.setText
                frame.setVisible(true);
            }

        });

        JButton hideButton = new JButton("hide dialog");
        hideButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                label.setText("label removed");
                frame.setVisible(false);
            }

        });
        setSize(500, 200);
        setLayout(new FlowLayout());
        add(showButton);
        add(hideButton);
    }
}

public static void main(String[] args) {
    JFrame frame = new MyFrame();
    frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
    frame.setVisible(true);
}
}

问题不在于标签组件的文本没有更改。很遗憾,重新油漆已经安排好了,但还没有进行。而且Linux打开windows的速度非常慢(windows管理器或类似软件有问题?)。
java.awt.EventQueue
按优先级进行调度,尽管我记不起细节


JComponent.paintinstallent
看起来是一种可能的方法。您可能希望在Swing/AWT中找到一个关于动画的(好)文本。(或在没有窗口管理器的情况下运行。)

问题不在于标签组件的文本没有更改。很遗憾,重新油漆已经安排好了,但还没有进行。而且Linux打开windows的速度非常慢(windows管理器或类似软件有问题?)。
java.awt.EventQueue
按优先级进行调度,尽管我记不起细节


JComponent.paintinstallent
看起来是一种可能的方法。您可能希望在Swing/AWT中找到一个关于动画的(好)文本。(这或在没有窗口管理器的情况下运行。)

我在OS X上遇到了类似的问题。我的解决方案是:

frame.invalidate()
frame.pack()
frame.setVisible(true)

这似乎迫使swing在显示帧之前在内存中重新绘制帧。

我在OS X上遇到了类似的问题。我的解决方案是:

frame.invalidate()
frame.pack()
frame.setVisible(true)

这似乎迫使swing在显示帧之前在内存中重新绘制帧。

我不认为这是Linux绘制中的问题。我可以在Windows 7 64位(JDK 1.6.0_18(早期访问))上重现您的问题。你已经非常接近答案了——你知道SwingUtilities.invokeLater,但是你没有考虑在需要的地方使用它

跟我说:

必须在EDT上初始化和修改Swing组件

如果你不这样做,坏事就会发生。在这种情况下,奇怪的重新绘制行为是由于没有在EDT上创建JFrame和包含的组件造成的。如果将此行包装在SwingUtilities.invokeLater中,它将解决您的问题:

JFrame frame = new MyFrame();
您是正确的-setText发生在EDT上,但是组件本身的初始化没有发生在EDT上,这是根本原因

如果对给定代码是否发生在EDT上有疑问,可以使用SwingUtilities.isEventDispatchThread()来确定


如果你打算进行大量的Swing开发,我强烈推荐阅读。我现在正在阅读它。

我不认为这是Linux绘画中的一个问题。我可以在Windows 7 64位(JDK 1.6.0_18(早期访问))上重现您的问题。你已经非常接近答案了——你知道SwingUtilities.invokeLater,但是你没有考虑在需要的地方使用它

跟我说:

必须在EDT上初始化和修改Swing组件

如果你不这样做,坏事就会发生。在这种情况下,奇怪的重新绘制行为是由于没有在EDT上创建JFrame和包含的组件造成的。如果将此行包装在SwingUtilities.invokeLater中,它将解决您的问题:

JFrame frame = new MyFrame();
您是正确的-setText发生在EDT上,但是组件本身的初始化没有发生在EDT上,这是根本原因

如果对给定代码是否发生在EDT上有疑问,可以使用SwingUtilities.isEventDispatchThread()来确定


如果你打算进行大量的Swing开发,我强烈推荐阅读。我现在正在阅读它。

在我的电脑(Windows 7和JDK 6.16)上不会出现。在我的电脑(Windows 7和JDK 6.16)上不会出现。好的,是的,我也这么认为。感谢您的确认——我希望有一种更干净、更少黑客的方式来完成这项工作,而不是强制立即绘制,但您说得很对:linux的绘制才是问题所在。但仍然困扰我的是,只有在展示了画框之后才能立即进行喷漆。在显示帧之前,没有办法绘制内存缓冲区吗?不是Linux-事实上Swing不是线程安全的。Swing通常知道何时进行绘制-问题在于EDT下完成的组件初始化。这种情况下可能发生的问题可能非常奇怪,很难诊断。好吧,是的,我也这么认为。感谢您的确认——我希望有一种更干净、更少黑客的方式来完成这项工作,而不是强制立即绘制,但您说得很对:这是linux的绘制,这是我的第一步