1

问题

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

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

请注意,代码是从已在 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);
}
}
4

3 回答 3

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 。我现在正在阅读它。

于 2009-12-31T17:29:41.717 回答
0

问题不在于标签组件的文本没有改变。重绘已经安排好了,但还没有发生。那和Linux打开窗口的速度非常慢(窗口管理器或类似问题有问题吗?)。按优先级排列的java.awt.EventQueue时间表,虽然我不记得细节了。

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

于 2009-10-13T11:46:25.627 回答
0

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

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

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

于 2009-12-30T20:12:36.030 回答