問題
Swing でダイアログ ボックスを作成します (JRE 6 update 10、Ubuntu Linux)。ユーザーがダイアログ ボックスの使用を終了すると、ダイアログ ボックスは非表示になります。ユーザーが別のフレームのボタンをクリックすると、ボックスのラベルがボタンに応じて変更され、ボックスが再び表示されます。
私が抱えている問題は、プログラム的には逆の順序で呼び出しを行っているにもかかわらず、ラベルが変更される前にボックスが表示されることです。これにより、ボックスが表示され、続いてラベルが変更され、低速のターゲット HW では「グリッチ」に見えます。EDT はフレームsetVisible(true)をラベルsetText(....)の前にスケジュールしているようです。この呼び出しを優先します。setText(....)の後にsetVisible(true)を実行するように EDT をスケジュールする方法はありますか?
コードは 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);
}
}