2010-03-11 8 views
7

मुझे एक संलग्न ड्रॉपडाउन शैली मेनू के साथ एक जेबटन की आवश्यकता थी। इसलिए मैंने एक जेपीओपमेनू लिया और इसे नीचे दिए गए कोड में जिस तरह से देख सकते हैं उसमें जेबटन से जुड़ा हुआ है।जेबटन से जेपीओपअपमेनू दिखा रहा/छुपा रहा है; फोकस लिस्टनर काम नहीं कर रहा है?

  • जब क्लिक
  • छिपाने यह पॉपअप दिखाई दे, तो दूसरी बार
  • छिपाने यह है कि कोई आइटम
  • यह छिपाने उपयोगकर्ता अगर पॉपअप में चयन किया जाता है पर क्लिक किया: क्या यह करने की जरूरत यह है स्क्रीन

ये 4 चीजें काम करती हैं, लेकिन बूलियन ध्वज के कारण मैं उपयोग कर रहा हूं, अगर उपयोगकर्ता कहीं और क्लिक करता है या किसी आइटम का चयन करता है, तो मुझे दिखाए जाने से पहले बटन पर दो बार क्लिक करना होगा फिर से ऊपर। यही कारण है कि मैंने फोकस लिस्टनर (जो बिल्कुल जवाब नहीं दे रहा है) को ठीक करने और इन मामलों में झंडा झूठा सेट करने की कोशिश की।

संपादित करें: एक उत्तर पोस्ट में अंतिम प्रयास ...

यहाँ श्रोताओं हैं: (। यह एक वर्ग JButton विस्तार में है, इसलिए दूसरा श्रोता 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); 
    } 

} 
+0

तो, मेरी मुख्य समस्या यह है कि फोकस प्राप्त() और फोकस लॉस्ट() कभी ट्रिगर नहीं होता है, भले ही मैं पॉपअप प्रकट करता हूं और गायब हो जाता हूं। – Joanis

उत्तर

1

यहां एक और दृष्टिकोण है जो एक हैक का बहुत बुरा नहीं है, अगर सुरुचिपूर्ण नहीं है, और जहां तक ​​मैं कह सकता हूं, काम करता है। सबसे पहले, शीर्ष पर, मैंने showPopup नामक दूसरा बूलियन जोड़ा। - यह ध्यान देने के लाभ हैं, तो यह मान लिया गया है यह दिखाया गया है और अगर यह ध्यान केंद्रित खो देता है, यह यह नहीं मानता '

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"); 
      isShowingPopup = true; 
     } 
    }); 

isShowingPopup बूलियन कहीं और बदल जाओ नहीं करता है:

FocusListener इस प्रकार हो गया है टी।

आगे स्थित बटन पर ActionListener अलग है:

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

अब वास्तव में नया सा आता है। इसलिए isShowingPopup प्रतिबिंबित करती है कि पॉपअप से पहले बटन दबाने दिखाया गया था

addMouseListener(new MouseAdapter() { 
     @Override 
     public void mousePressed(MouseEvent e) { 
      System.out.println("ispopup?: " + isShowingPopup); 
      if (isShowingPopup) { 
       showPopup = false; 
      } 
     } 

     @Override 
     public void mouseReleased(MouseEvent e) { 
      showPopup = true; 
     } 
    }); 

असल में, mousePressed से पहले मेनू ध्यान केंद्रित खो देता है बुलाया जाता है,: यह बटन पर एक MouseListener है। फिर, यदि मेनू वहां था, तो हमने showPopup से false पर सेट किया है, ताकि actionPerformed विधि मेनू को जाने के बाद मेनू को नहीं दिखाए (माउस जाने के बाद)।

यह हर मामले में अपेक्षित व्यवहार करता है लेकिन एक: यदि मेनू दिखा रहा था और उपयोगकर्ता ने बटन पर माउस दबाया लेकिन इसे इसके बाहर छोड़ दिया, actionPerformed कभी नहीं कहा गया था। इसका मतलब था कि showPopup झूठ बना रहा और अगली बार बटन दबाए जाने पर मेनू नहीं दिखाया गया था। इसे ठीक करने के लिए, mouseReleased विधि showPopup रीसेट करता है। mouseReleased विधि को actionPerformed के बाद कॉल किया जाता है, जहां तक ​​मैं कह सकता हूं।

मैंने बटन के बारे में सोचने वाली सभी चीजों को करने के लिए परिणामस्वरूप बटन के साथ चारों ओर खेला, और यह अपेक्षा के अनुसार काम किया। हालांकि, मुझे 100% यकीन नहीं है कि घटनाएं हमेशा एक ही क्रम में होती रहेंगी।

आखिरकार, मुझे लगता है कि कम से कम, कोशिश करने लायक है।

+0

वाह, मुझे नहीं पता कि फोकस लिस्टनर अब क्यों काम करता है (मैंने requestFocus() भी कहा है!) ... लेकिन मैंने अभी यह सब परीक्षण किया है और ऐसा लगता है कि यह पूरी तरह से काम करता है! वही है जो लापता था! अच्छा कार्य! आपका बहुत बहुत धन्यवाद! – Joanis

+1

मुझे लगता है कि समस्या जहां आपने अनुरोध कहा था फोकस() - मैंने इसे मेनू.शो() के बाद बुलाया था, जिसने इसे दिखाए जाने के ठीक बाद फोकस किया था, जबकि आपने इसे ब्लॉक में बुलाया था, अगर मेनू पहले ही था दिखा रहा है "अगर (isShowingPopup) ..." जो गलत समय पर ध्यान केंद्रित करने का प्रयास करता है। –

+0

परीक्षण नहीं करेगा, अब आप शायद काम कर रहे हैं क्योंकि यह अब काम करता है! एक बार फिर धन्यवाद। – Joanis

1

आप पॉपअप मेनू की वर्तमान स्थिति जांचने के लिए अपने बूलियन चर के बजाय JPopupMenu.isVisible() इस्तेमाल कर सकते हैं।

+1

मैंने इसे पहले करने की कोशिश की, लेकिन समस्या यह है: जैसे ही आप पॉपअप दिखाई दे रहे हैं बटन (या कहीं और) पर क्लिक करते हैं, पॉपअप स्वचालित रूप से तुरंत बंद हो जाता है। तो दृश्यमान() झूठी वापसी करता है इससे कोई फर्क नहीं पड़ता। यह समस्या (जाहिर है) isFocusOwner() और isShowing() पर भी लागू होती है। – Joanis

0

ठीक है, मैं आपके सभी कोड को देखे बिना सुनिश्चित नहीं हो सकता, लेकिन क्या यह संभव है कि पॉपअप वास्तव में कभी भी ध्यान केंद्रित न हो? मुझे चीजों के साथ समस्याएं थीं जो पहले स्विंग में ठीक से ध्यान नहीं दे रही थी, इसलिए यह अपराधी हो सकता है। मेनू पर setFocusable(true) पर कॉल करने का प्रयास करें और फिर मेनू दिखाई देने पर requestFocus() पर कॉल करें।

+0

बस कोशिश की; या तो काम नहीं कर रहा है। मैं कोड को एक सेकंड में पोस्ट करूंगा। – Joanis

1

जब यह पता चला गया है और छिपा हुआ (और उसके अनुसार अपनी isShowingPopup झंडा अद्यतन) ताकि आप जानते हैं, आप JPopupMenu करने के लिए एक ComponentListener जोड़ने की कोशिश की है? मुझे यकीन नहीं है कि फोकस परिवर्तनों को सुनना जरूरी सही दृष्टिकोण है।

 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;      
      } 
     }); 

मैं अपने कोड में यह डाला जाता है और पता लगाया कि यह काम करता है:

+0

यह एक बहुत अच्छा विचार प्रतीत होता है, लेकिन फोकस लिस्टनर की तरह, घटक लिस्टनर प्रतिक्रिया नहीं दे रहा है (ठीक है, केवल एक बार: जब पॉपअप पहली बार दिखाया जाता है तो मुझे "आकार बदलना" कहा जाता है)। मैंने एक प्रिंटलएन ("") अपनी प्रत्येक विधियों में कॉल किया है और कुछ भी मुद्रित नहीं किया गया है। मैं पूरा कोड पोस्ट करूंगा। – Joanis

1

आप क्या जरूरत है एक PopupMenuListener है।

+0

आपके इनपुट के लिए धन्यवाद। मैंने पहले से ही इस दृष्टिकोण की कोशिश की ... यह ऊपर चर्चा की गई समस्याओं को हल करता है, लेकिन एक नया बनाता है। इसके साथ, हम बटन पर पॉपअप क्लिक को बंद नहीं कर सकते हैं, क्योंकि यह पहले से बंद या खोला गया है, इससे कोई फर्क नहीं पड़ता। – Joanis

+0

जब पॉपअप मेनू दिखाई देता है, तो आप बटन पर एक्शन श्रोता को संशोधित कर सकते हैं ताकि वह पॉपअप नहीं खोल सके (यानी, श्रोता को हटा दें)। फिर जब मेनू अदृश्य हो जाता है, इसे वापस सेट करें (श्रोता को वापस जोड़ें)। – Dave

+0

आप सही हैं। मुझे यकीन नहीं है कि क्या यह "सही" करने का कोई तरीका है क्योंकि जेपीओप्यूमेनू पॉपअपमेनूवेंट में अन्य सभी माउस ईवेंट को सहारा देता है। यहां एक (बीआईजी) हैक: प्रत्येक पॉपअप के अंदर System.currentTimeMillis() को सहेजें, और फिर कार्रवाई के अंदर, और फिर कार्रवाई के अंदर, "if (isShowingPopup || (System.currentTimeMillis() - savedTime) <100) फिर दिखाएं ... ठीक है, मैं सुझाव नहीं दे रहा हूं कि आप इसे इस तरह से रखें लेकिन अगर इसे इस तरह काम करना है ... केवल एक और चीज जिसे मैं इसके बारे में सोच सकता हूं, अपना खुद का जेपीओपअपमेनू कार्यान्वयन लिखो और माउस ईवेंट को जिस तरह से आप चाहते हैं उसे संभाल लें। –

3

यहां एम्बर शाह के "बड़े हैक" सुझाव का एक रूप है जो मैंने अभी बनाया है। IsShowingPopup ध्वज के बिना ...

यह बुलेटप्रूफ नहीं है, लेकिन यह पॉपअप को बंद करने के लिए अविश्वसनीय धीमी क्लिक के साथ आता है (या इसे फिर से खोलने के लिए एक बहुत तेज़ दूसरा क्लिक ...) तक यह बहुत अच्छा काम करता है।

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% में काम करता है।

सुझावों के लिए खोलें!

0

मैंने टिखॉन जेल्विस के उत्तर की कोशिश की (फोकस लिस्टर और माउस लिस्टनर का एक स्मार्ट संयोजन पेश किया)। यह लिनक्स (जावा 7/gtk) पर मेरे लिए काम नहीं करता है। :-(

http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#requestFocus%28%29 वहाँ लिखा है पढ़ना "ध्यान दें कि इस विधि के प्रयोग को प्रोत्साहित किया जाता है क्योंकि अपने व्यवहार मंच निर्भर है।"

हो सकता है कि श्रोता कॉल के आदेश Java7 साथ बदल गया है या इसके साथ बदलता है जीटीके बनाम विंडोज़। यदि आप मंच को स्वतंत्र बनाना चाहते हैं तो मैं इस समाधान की अनुशंसा नहीं करता।

बीटीडब्ल्यू: मैंने इस संकेत देने के लिए स्टैक ओवरफ्लो पर एक नया खाता बनाया। ऐसा लगता है कि मुझे उनके जवाब पर टिप्पणी करने की अनुमति नहीं है (क्योंकि प्रतिष्ठा)। लेकिन ऐसा लगता है कि मेरे पास इसे संपादित करने के लिए एक बटन है। यह स्टैक ओवरफ्लो एक बहुत मजेदार बात है।:-)