0

まず第一に、この質問は数百万回尋ねられているようですが、他の質問に対する回答はどれも私にはうまくいかないようです.

以下のコードを実行Message.popup(String, int)すると、テキストが正しく表示されることがありますが、コンポーネントがまったく追加されていない場合など、JDialog が空になることがあります。

public class Message extends JDialog {
    private int width;
    private int height;

    private JLabel content;

    public Message(String _content, int _margin) {
        super();
        this.content = new JLabel(_content);
        content.setFont(new Font("Monospaced", Font.BOLD, 20));
        this.margin = _margin;
        this.width = content.getPreferredSize().width + _margin;
        this.height = content.getPreferredSize().height + _margin;

        createComponents();
        setProperties();
    }

    public static void popup(String _content, int _time) {
      if (SwingUtilities.isEventDispatchThread()) {
        runPopup(_content, _time);
      }
      else {
        SwingUtilities.invokeLater(new Runnable() {
          @Override
          public void run() {
            runPopup(_content, _time);
          }
        });
      }
    }

    private static void runPopup(String _content, int _time) {
      final Message message = new Message(_content);
      new Timer(_time, new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
          message.dispose();
        }
      }).start();
    }

    private void createComponents() {
        setLayout(new BorderLayout());

        Box box = Box.createHorizontalBox();
        box.add(Box.createHorizontalGlue());
        box.add(content, BorderLayout.CENTER);
        box.add(Box.createHorizontalGlue());
        add(box);
    }

    private void setProperties() {
        setSize(width, height);
        setLocation(Coordinator.calculateCenteredWindowLocation(width, height));
        setUndecorated(true);
        setResizable(false);
        setTitle(content.getText());
        setVisible(true);
        update(getGraphics());
    }
}

がないとupdate(getGraphics());、フレームは常に空ですが、あると、風がどの方向に吹いているかによって異なります... (図を見てください!)

4

3 に答える 3

4

コードがEDTで実行されていますか? 実際、そうでない場合 (現在のスレッドなので、Swing が通常好まないものであることを期待していsleepます)、フレームのレンダリングに問題が発生します。

これらの典型的な Swing スレッド化の問題を回避するにSwingUtilitiesは、EDT で確実に実行するためのメソッドを提供するクラスを確認してください。さらに、スレッドを直接スリープ状態にする代わりに、Swing に置き換えることもできますjavax.swing.Timer( と混同しないように注意してくださいjava.util.Timer)。

于 2011-06-17T09:55:26.727 に答える
4

@Riduidel が述べたように、イベント ディスパッチ スレッドで Swing 関連が発生することが重要ですEDT。これは、Swing がスレッドセーフではないためです。を呼び出すときpopup()は、次のことを行う必要があります

if(SwingUtilities.isEventDispatchThread()){
    Message.popup(...);
}
else{
    SwingUtilities.invokeLater(new Runnable(){
        @Override
        public void run(){
            Message.popup(...);
        }
    });
}

これにより、 が に確実にJFrame作成されますEDT。また、投稿したコード スニペットから、Messageプライベート コンストラクターが必要なようです。さらに、カスタム レンダリングを行っていないのであればJFrame、クラスを拡張する代わりにメンバー変数を作成してみませんか? -- 私には少し余分なようです。

いずれにしても、GUI が「フリーズ」したように見え、キューに入れられた他のイベントの実行がブロックされるため、どちらsleepも決して使用しないでください。EDT長時間実行されるタスクを実行するときはSwingWorker、または @Riduidel が言及したように を使用しますjavax.swing.Timer。ただし、 を使用する場合は、上記のようにユーティリティ クラスをjava.util.Timer使用して、で実行されるタスクを にポストします。SwingUtilitiesRunnableEventQueueEDT

編集

これが私がすることです(そして、はい、それは機能します)

public class Message {

    // Private constructor to prevent external instantiation
    private Message(){
    }

    public static void createAndShowDialog(final String content, final int time){
        final JDialog dialog = new JDialog();
        dialog.setLayout(new BorderLayout());
        dialog.setUndecorated(true);

        JLabel label = new JLabel(content);
        label.setFont(new Font("Monospaced", Font.BOLD, 20));

        Box b = Box.createHorizontalBox();
        b.add(Box.createHorizontalGlue());
        b.add(label, BorderLayout.CENTER);
        b.add(Box.createHorizontalGlue());

        dialog.add(b);
        dialog.pack();
        dialog.setLocationRelativeTo(null);
        dialog.setVisible(true);

        // kick-off timer
        Timer t = new Timer(time, new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
              dialog.dispose();
            }
        });
        t.setRepeats(false);
        t.start();
    }
}

どこで を呼び出しcreateAndShowDialog(...)ても、次の操作を行います。

SwingUtilities.invokeLater(new Runnable(){
    @Override
    public void run(){
        Message.createAndShowDialog("Content", 5000); // wait 5 seconds before disposing dialog
    }
});
于 2011-06-17T10:25:24.017 に答える
2
update(getGraphics()); 

update() メソッドまたは getGraphics() メソッドを使用しないでください。

update() の呼び出しは、AWT NOT Swing に使用されます。

カスタム ペイントを行う必要がある場合は、既にグラフィックス オブジェクトにアクセスできるコンポーネントの paintComponent() メソッドをオーバーライドします。

于 2011-06-17T15:13:28.930 に答える