8

ドロップダウンスタイルメニューが添付されたJButtonが必要でした。そこで、JPopupMenuを取得し、以下のコードで確認できるようにJButtonにアタッチしました。それがする必要があるのはこれです:

  • クリックするとポップアップが表示されます
  • もう一度クリックすると非表示になります
  • ポップアップでアイテムが選択されている場合は非表示にします
  • ユーザーが画面内の別の場所をクリックした場合は非表示にします

これらの4つのことは機能しますが、私が使用しているブールフラグのため、ユーザーが別の場所をクリックしたり、アイテムを選択したりすると、ボタンが再び表示される前にボタンを2回クリックする必要があります。そのため、FocusListener(絶対に応答しない)を追加して修正し、これらの場合にフラグをfalseに設定しようとしました。

編集:回答投稿の最後の試み...

リスナーは次のとおりです(JButtonを拡張するクラスにあるため、2番目のリスナーはJButtonにあります)。

// Show popup on left click.
menu.addFocusListener(new FocusListener() {
 @Override
 public void focusLost(FocusEvent e) {
  System.out.println("LOST FOCUS");
  isShowingPopup = false;
 }

 @Override
 public void focusGained(FocusEvent e) {
  System.out.println("GAINED FOCUS");
 }
});

addActionListener(new ActionListener() {
 @Override
 public void actionPerformed(ActionEvent e) {
  System.out.println("isShowingPopup: " + isShowingPopup);
  if (isShowingPopup) {
   isShowingPopup = false;
  } else {
   Component c = (Component) e.getSource();
   menu.show(c, -1, c.getHeight());
   isShowingPopup = true;
  }
 }
});

私はこれとずっと長い間戦ってきました。誰かがこれの何が悪いのかについて私に手がかりを与えることができれば、それは素晴らしいことです!

ありがとう!

コード:

public class Button extends JButton {

    // Icon.
    private static final ImageIcon ARROW_SOUTH = new ImageIcon("ArrowSouth.png");

    // Unit popup menu.
    private final JPopupMenu menu;

    // Is the popup showing or not?
    private boolean isShowingPopup = false;

    public Button(int height) {
        super(ARROW_SOUTH);
        menu = new JPopupMenu(); // menu is populated somewhere else

        // FocusListener on the JPopupMenu
        menu.addFocusListener(new FocusListener() {
            @Override
            public void focusLost(FocusEvent e) {
                System.out.println("LOST FOCUS");
                isShowingPopup = false;
            }

            @Override
            public void focusGained(FocusEvent e) {
                System.out.println("GAINED FOCUS");
            }
        });

        // ComponentListener on the JPopupMenu
        menu.addComponentListener(new ComponentListener() {
            @Override
            public void componentShown(ComponentEvent e) {
                System.out.println("SHOWN");
            }

            @Override
            public void componentResized(ComponentEvent e) {
                System.out.println("RESIZED");
            }

            @Override
            public void componentMoved(ComponentEvent e) {
                System.out.println("MOVED");
            }

            @Override
            public void componentHidden(ComponentEvent e) {
                System.out.println("HIDDEN");
            }
        });

        // ActionListener on the JButton
        addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("isShowingPopup: " + isShowingPopup);
                if (isShowingPopup) {
                    menu.requestFocus();
                    isShowingPopup = false;
                } else {
                    Component c = (Component) e.getSource();
                    menu.show(c, -1, c.getHeight());
                    isShowingPopup = true;
                }
            }
        });

        // Skip when navigating with TAB.
        setFocusable(true); // Was false first and should be false in the end.

        menu.setFocusable(true);
    }

}
4

7 に答える 7

3

これは、私が今行ったAmberShahの「ビッグハック」提案の変形です。isShowingPopupフラグなし...

防弾ではありませんが、誰かが非常に遅いクリックでポップアップを閉じるまで(または、非常に速い2回目のクリックで再度開くまで...)、非常にうまく機能します。

public class Button extends JButton {

 // Icon.
 private static final ImageIcon ARROW_SOUTH = new ImageIcon("ArrowSouth.png");

 // Popup menu.
 private final JPopupMenu menu;

 // Last time the popup closed.
 private long timeLastShown = 0;

 public Button(int height) {
  super(ARROW_SOUTH);
  menu = new JPopupMenu(); // Populated somewhere else.

  // Show and hide popup on left click.
  menu.addPopupMenuListener(new PopupMenuListener() {
   @Override
   public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) {
    timeLastShown = System.currentTimeMillis();
   }
   @Override public void popupMenuWillBecomeVisible(PopupMenuEvent arg0) {}
   @Override public void popupMenuCanceled(PopupMenuEvent arg0) {}
  });
  addActionListener(new ActionListener() {
   @Override
   public void actionPerformed(ActionEvent e) {
    if ((System.currentTimeMillis() - timeLastShown) > 300) {
     Component c = (Component) e.getSource();
     menu.show(c, -1, c.getHeight());
    }
   }
  });

  // Skip when navigating with TAB.
  setFocusable(false);
 }

}

コメントで述べたように、これは最も洗練されたソリューションではありませんが、非常に単純で、98%のケースで機能します。

提案を受け付けます!

于 2010-03-11T20:42:14.650 に答える
1

ブール変数の代わりにJPopupMenu.isVisible()を使用して、ポップアップメニューの現在の状態を確認できます。

于 2010-03-11T03:17:32.543 に答える
1

に を追加しComponentListenerて、JPopupMenuいつ表示および非表示になったかがわかるようにしましたか (isShowingPopupそれに応じてフラグを更新しますか)。フォーカスの変更をリッスンすることが必ずしも正しいアプローチであるかどうかはわかりません。

于 2010-03-11T10:16:22.540 に答える
1

必要なのは PopupMenuListener です。

        menu.addPopupMenuListener(new PopupMenuListener() {

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent arg0) {

            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent arg0) {
                System.out.println("MENU INVIS"); 
                isShowingPopup = false;     
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent arg0) {
                System.out.println("MENU CANCELLED"); 
                isShowingPopup = false;                     
            }
        });

これをコードに挿入し、動作することを確認しました。

于 2010-03-11T17:42:53.717 に答える
0

すべてのコードを見ないとわかりませんが、ポップアップが実際にまったくフォーカスされない可能性はありますか? 以前、Swing で適切にフォーカスされないという問題があったため、それが原因である可能性があります。setFocusable(true)メニューで呼び出してから、メニューを表示させたときに呼び出してみてくださいrequestFocus()

于 2010-03-11T05:05:00.300 に答える
0

Tikhon Jelvis の Answer を試しました (focusListener と mouseListener のスマートな組み合わせを紹介します)。Linux (Java7/gtk) では動作しません。:-(

http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#requestFocus%28%29を読むと、「このメソッドの動作はプラットフォームに依存しているため、このメソッドの使用はお勧めできません。依存。"

Java7でリスナー呼び出しの順番が変わったのか、GTK vs Windowsで変わったのかもしれません。プラットフォームに依存しないようにしたい場合、このソリューションはお勧めしません。

ところで: このヒントを得るために、stackoverflow で新しいアカウントを作成しました。彼の答えにコメントすることは許可されていないようです(評判のため)。しかし、編集するためのボタンがあるようです。このスタックオーバーフローは非常に面白いものです。:-)

于 2013-01-24T08:26:03.297 に答える