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

时间:2009-10-13 09:49:02

标签: java swing edt

问题

我在swing中创建一个对话框(JRE 6 update 10,Ubuntu linux)。当用户使用完对话框后,它将被隐藏。当用户点击另一个框架中的按钮时,框中的标签会根据按钮发生变化,然后再次显示该框。

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

请注意,代码是从已经在EDT上执行的按钮单击调用的,因此无法使用 SwingUtilities.invokeAndWait 。我尝试过使用 invokeLater 方法,但EDT仍会重新安排它。

重现

在调试模式下在IDE中运行以下代码,并在显示和隐藏“对话框”框后中断 showButton 的操作代码。标签的 setText(....)更改不会立即对GUI产生影响,但框架的 setVisible(true)将会立即生效。然后逐步完成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);
}
}

3 个答案:

答案 0 :(得分:1)

我不认为这是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开发,我强烈建议您阅读Filthy Rich Clients。我现在正在阅读它。

答案 1 :(得分:0)

问题不在于标签组件的文本没有改变。这是重新安排已经安排但尚未发生。那和Linux有打开窗口极度慢的倾向(窗口管理器或类似的问题?)。 java.awt.EventQueue按优先级排定,但我不记得细节。

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

答案 2 :(得分:0)

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

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

这似乎强制摆动以在显示之前重新绘制内存中的帧。