0

私は Java で作業しており、JFrame に JPanel があります。そのJPanelには、とりわけ、自由に表示および非表示にしたいJLabelがあります。可視性を true/false に設定し、JFrame と JPanel に追加したり削除したりしてみました。また、オンラインで調べて、validate()ing と revalidate()ing を無限に試しました。この問題を解決するには、ここで何ができますか?

4

2 に答える 2

7

setVisible一般に、Swing コンポーネントを表示または非表示にするには、このメソッドを呼び出すだけで十分です。

それが機能することを確認するために、次のことを試しました。

public class Visibility {
  private void makeGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    final JLabel l = new JLabel("Hello");
    final JButton b = new JButton("Hide Label");
    b.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        l.setVisible(false);
      }
    });

    f.getContentPane().setLayout(new BorderLayout());
    f.getContentPane().add(l, BorderLayout.CENTER);
    f.getContentPane().add(b, BorderLayout.SOUTH);
    f.setSize(200, 200);
    f.setLocation(200, 200);
    f.validate();
    f.setVisible(true);
  }

  public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Visibility().makeGUI();
      }
    }); 
  }
}

上記のプログラムは、 をクリックすることで可視性に影響を与えることができJButtonます。

それはスレッドの問題でしょうか?

次に疑ったのは、おそらくイベント ディスパッチ スレッド (EDT)にない が表示にすぐに影響しないのではないかということでした。そのため、 と を初期化した後に次を追加しThreadました。JLabelJButton

Thread t = new Thread(new Runnable() {
  public void run() {
    while (true) {
      b.setVisible(!b.isVisible());

      try {
        Thread.sleep(100);
      } catch (InterruptedException e) { /* Handle exception /* }
    }
  }
});

t.start();

新しい実行では、100 ミリ秒ごとThreadのトグル表示を変更しましたが、これも問題なく動作しました。JLabel

Swing はスレッドセーフではないため、イベント ディスパッチ スレッド (EDT)から Swing コンポーネントを呼び出すのは良くありません。私はそれが機能したことに少し驚きました.それが機能するという事実はまぐれかもしれません.

JPanel?を再描画します。

JLabel可視性がサイズ変更時にのみ影響を受けている場合は、 が再描画JLabelされているときにのみ が描画されている可能性がJPanelあります。

JPanel試してみるべきことの 1 つは、のメソッドを呼び出して、repaintの可視性JLabelが変化するかどうかを確認することです。

しかし、主な原因が EDT からのスレッドが GUI に変更を加えようとしていることが原因である場合、この方法は状況に対する応急処置に過ぎないようです。(メモとして、repaintメソッドはスレッドセーフであるため、EDT 以外のスレッドから呼び出すことができますが、に依存するrepaintことは解決策ではなく回避策です。)

使ってみてSwingUtilities.invokeLater

最後に、おそらく私が試みることはSwingUtilities.invokeLater、GUI に影響を与えたい場合に、EDT とは別に実行されているスレッドから呼び出すことができる (そして呼び出す必要がある) メソッドです。

したがって、前のThread例は次のように記述します。

Thread t = new Thread(new Runnable() {
  public void run() {
    while (true) {
      try {
        SwingUtilities.invokeLater(new Runnable() {
          public void run() {
            b.setVisible(!b.isVisible());
          }
        });
      } catch (Exception e1) { /* Handle exception */ }

      try  {
        Thread.sleep(100);
      } catch (InterruptedException e) { /* Handle exception */ }
    }
  }
});

t.start();

GUI への変更が実際に別のスレッドで発生している場合は、Swing を使用して正常に動作するマルチスレッド コードを作成する方法について詳しく知るために、Java チュートリアルのレッスン: Swing の同時実行を読むことをお勧めします

于 2009-06-03T03:08:36.397 に答える
2

setVisible() またはそれを削除しても問題なく動作するはずですが、イベントディスパッチスレッドから実行していることを確認してください。EventQueue には、そのスレッドでブロックを実行するためのユーティリティ メソッドがあります。

http://helpdesk.objects.com.au/java/how-do-i-update-my-gui-from-any-thread

コンポーネントを再レイアウトする必要がある場合は、親 JPanel で revalidate() を呼び出す必要があります。

問題を示す例を投稿できる場合は、それを見てみましょう。

于 2009-06-03T03:26:48.950 に答える