2010-11-16 8 views
6

मैं मूल रूप से क्या पूछा स्पष्ट रूप से मेरे सवाल/समस्या राज्य नहीं था के रूप में संचालित बटन एक निरीक्षण गुण खिड़की बनाएं,, इसलिए मैं इसे बेहतर समझा जाएगा। मेरे पास JButton है जो दृश्य के लिए JDialog सेट करता है। JDialog में WindowListener है जो इसे windowDeactivated() ईवेंट पर दिखाई नहीं देता है, जो किसी भी समय उपयोगकर्ता द्वारा संवाद के बाहर क्लिक करने पर ट्रिगर किया जाता है। बटन ActionListener जांचता है कि क्या संवाद सत्य है, यदि सत्य है तो इसे छुपाता है, तो गलत लगता है।एक JDialog

windowDeactivated() हमेशा या नहीं बटन पर क्लिक या, जब तक संवाद बाहर उपयोगकर्ता क्लिक करता है के रूप में ट्रिगर किया जाएगा। मेरी समस्या यह है कि जब उपयोगकर्ता संवाद बंद करने के लिए बटन क्लिक करता है। संवाद WindowListener द्वारा बंद किया गया है और फिर ActionListener इसे प्रदर्शित करने का प्रयास करता है।

यदि windowDeactivated()setVisible(false) नहीं है, तो संवाद अभी भी खुला है, लेकिन मूल विंडो के पीछे है। मैं जो पूछ रहा हूं वह है कि windowDeactivated() के अंदर क्लिक के स्थान तक पहुंच कैसे प्राप्त करें। यदि मुझे पता है कि उपयोगकर्ता बटन और विंडो पर क्लिक किया गया है (सक्रिय) संवाद को छिपा सकता है, ताकि बटन ActionListener देख सके कि यह अभी भी दिखाई दे रहा है और इसे छुपा रहा है।

 
public PropertiesButton extends JButton { 

    private JDialog theWindow; 

    public PropertiesButton() { 
     theWindow = new JDialog(); 
     theWindow.setUndecorated(true); 
     theWindow.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
     theWindow.add(new JMenuCheckBoxItem("Something")); 
     theWindow.addWindowListener(new WindowListener() { 
      // just an example, need to implement other methods 
      public void windowDeactivated(WindowEvent e) { 
       theWindow.setVisible(false); 
      } 
     }); 
     this.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       if (theWindow.isVisible()) { 
        theWindow.setVisible(false); 
       } else { 
        JButton btn = (JButton)e.getSource(); 
        theWindow.setLocation(btn.getLocationOnScreen.x,btn.getLocationOnScreen.x-50); 
        theWindow.setVisible(true); 
       } 
      } 
     }); 
     theWindow.setVisible(false); 
    } 

} 
+0

सुनिश्चित नहीं है कि सवाल क्या है। ऐसा लगता है कि आप इसे समझ चुके हैं। यह सही दिखता है। (पहली नज़र में) – jjnguy

+0

जो मैंने ऊपर किया है वह सब कुछ करेगा जो मैं चाहता था, सिवाय इसके कि जब संवाद के बाहर क्लिक किया जाए। बाहर क्लिक करने से संवाद बंद हो जाता है, जो ठीक है, लेकिन जब मैं संवाद खोलने के लिए बटन क्लिक करता हूं, तो यह पहली बार नहीं खुलता है।जो मैं समझता हूं, से विंडोलिस्टर एक्शनलिस्टर से पहले ट्रिगर करता है और भले ही एक्शनलिस्टर ट्रिगर होने पर संवाद वास्तव में दिखाई नहीं दे रहा है, तो .isVisible() कॉल एक सत्य देता है। तो, बटन होगा .setVisible (झूठा) भले ही यह दिखाई नहीं दे रहा है। – Brian

+2

ब्रायन, आप विंडो श्रोता के बजाय 'विंडो एडाप्टर' का उपयोग कर सकते हैं। फिर आपको केवल अपनी इच्छित विधियों को लागू करना होगा। – jjnguy

उत्तर

0

आप ड्रॉपडाउन संपत्ति सूची के लिए जेडीअलॉग के बजाय जेपीनल का उपयोग करने का प्रयास कर सकते हैं। कुछ इस तरह:

public class PropertiesButton extends JButton { 

    private JPanel theWindow; 

    public PropertiesButton() { 
     theWindow = new JPanel(); 
     theWindow.add(new JMenuCheckBoxItem("Something")); 

     this.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       if (theWindow.isVisible()) { 
        theWindow.setVisible(false); 
        getParent().remove(theWindow); 
       } else { 
        JButton btn = (JButton)e.getSource(); 
        getParent().add(theWindow);    
        theWindow.setBounds(
         btn.getX(), 
         btn.getY() + btn.getHeight(), 100, 100); 

        theWindow.setVisible(true); 
       } 
      } 
     }); 
     theWindow.setVisible(false); 
    } 

} 

JDialog तरह दिग्गजों की बजाय हल्के घटकों का उपयोग करते हुए हमेशा स्विंग में बेहतर है, और एक आप रिपोर्ट की तरह कम अवांछनीय प्रभाव है। इस दृष्टिकोण का एकमात्र मुद्दा यह है कि पैनल की स्थिति और आकार माता-पिता में सक्रिय लेआउट प्रबंधक द्वारा प्रभावित किया जा सकता है।

0

एक आसान, अगर कुछ हद तक हैक, जिस तरह से इसे हल किया जा सकता है, तो प्रॉपर्टीबटन के पास बुलियन ध्वज है जो इंगित करता है कि हमें अगली बटन कार्रवाई को संभालने से परेशान होना चाहिए या नहीं। यदि विंडो विंडो सक्रिय घटना के कारण संवाद छिपा हुआ है तो हम इस ध्वज को फ़्लिप करते हैं।

public PropertiesButton extends JButton { 

    private JDialog theWindow; 
    private boolean ignoreNextAction; 

(स्निप)

theWindow.addWindowListener(new WindowAdapter() { 
     @Override 
     public void windowDeactivated(WindowEvent e) { 
      ignoreNextAction = true; 
      theWindow.setVisible(false); 
     } 
    }); 
    this.addActionListener(new ActionListener() { 
     public void actionPerformed(ActionEvent e) { 
      if (ignoreNextAction) { 
       ignoreNextAction = false; 
       return; 
      } 
      // ...normal action handling follows 
     } 
    }); 

ध्यान दें कि मैं नहीं कर रहा हूँ 100% इस चाल के साथ आराम: वहाँ कुछ सूक्ष्म मामले मैं याद किया जहां दृष्टिकोण में विफल रहता है हो सकता है।

0

awheel की सलाह पर विस्तार, मैं निम्न उदाहरण जो स्विंग के कांच फलक कार्यक्षमता का उपयोग करता लिखा है। दृष्टिकोण थोड़ा गन्दा है, लेकिन जब आप स्विंग में कुछ सामान्य रूप से उन्नत प्रयास कर रहे हैं तो यह असामान्य नहीं है।

विचार एक पारदर्शी ओवरले पैनल (पूरे विंडो सामग्री को कवर करने वाला ग्लास फलक) प्रदर्शित करना है, जब कोई बटन क्लिक करता है, और जब उपयोगकर्ता या तो विंडो में कहीं भी क्लिक करता है या कुंजी दबाता है तो इसका निपटान करना होता है।

इस कांच फलक के शीर्ष पर, मैं एक JPanel ("पॉपअप") प्रदर्शित करने और बस बटन कि उसकी दृश्यता चलाता है ऊपर स्थित करने के लिए प्रयास करें।

यह दृष्टिकोण एक सीमा आप मूल संवाद आधारित समाधान नहीं करती है: जो कुछ भी कांच फलक के ऊपर बनाए है फ्रेम की सामग्री क्षेत्र के अंदर फिट होगा (सभी के बाद, यह एक खिड़की है)। यही कारण है कि मैं नीचे दिए गए कोड में कुछ समायोजन करता हूं ताकि यह सुनिश्चित किया जा सके कि पॉपअप < के निर्देशांक सामग्री फलक की सीमाओं के भीतर हैं (अन्यथा जेएलएबल को फ्रेम के किनारों पर फसल लगाया जाएगा)।

यह भी सीमा यह है कि माउस कांच फलक से पकड़ा प्रेस किसी भी अंतर्निहित घटकों को प्रत्यायोजित नहीं कर रहे हैं है। तो यदि आप ग्लास फलक दिखाई देने पर एक बटन पर क्लिक करते हैं, तो ग्लास फलक दूर चलेगा लेकिन क्लिक का उपभोग भी करेगा, और जिस बटन को आपने सोचा था, उस पर क्लिक नहीं करेगा। यदि कोई चाहें तो इसके चारों ओर जाना संभव है, लेकिन फिर यह भी गड़बड़ हो जाता है और मैं अपना उदाहरण अपेक्षाकृत सरल रखना चाहता था। :-)

import java.awt.Color; 
import java.awt.Container; 
import java.awt.FlowLayout; 
import java.awt.KeyEventDispatcher; 
import java.awt.KeyboardFocusManager; 
import java.awt.Point; 
import java.awt.Window; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.JButton; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JRootPane; 
import javax.swing.SwingUtilities; 
import javax.swing.border.BevelBorder; 
import javax.swing.border.CompoundBorder; 
import javax.swing.border.EmptyBorder; 

public class GlassPaneTest extends JFrame { 

    public static class PropertiesButton extends JButton { 

     /** The currently displayed glass pane. 
     * Should be null if nothing is displayed. */ 
     private JPanel theGlassPane; 
     /** Root pane of connected window. Used to attach the glass pane. */ 
     private final JRootPane rootPane; 
     /** Content pane of the connected window. Used for coordinate calculation. */ 
     private final Container contentPane; 
     /* A "key hook" that allows us to intercept any key press when the glass pane is visible, 
     * so we can hide the glass pane. */ 
     private final KeyEventDispatcher keyHook = new KeyEventDispatcher() { 

      public boolean dispatchKeyEvent(KeyEvent e) { 
       if (theGlassPane == null || e.getID() != KeyEvent.KEY_PRESSED) { 
        return false; 
       } 
       setGlassPaneVisible(false); 
       return true; 
      } 
     }; 

     public PropertiesButton(Window parentWindow) { 
      if (!(parentWindow instanceof JFrame || parentWindow instanceof JDialog)) { 
       throw new IllegalArgumentException("only JFrame or JDialog instances are accepted"); 
      } 
      if (parentWindow instanceof JDialog) { 
       rootPane = ((JDialog) parentWindow).getRootPane(); 
       contentPane = ((JDialog) parentWindow).getContentPane(); 
      } else { 
       rootPane = ((JFrame) parentWindow).getRootPane(); 
       contentPane = ((JFrame) parentWindow).getContentPane(); 
      } 

      addActionListener(new ActionListener() { 

       public void actionPerformed(ActionEvent e) { 
        setGlassPaneVisible(theGlassPane == null); 
       } 
      }); 
     } 

     private JPanel createGlassPane() { 
      // Create the glass pane as a transparent, layout-less panel 
      // (to allow absolute positioning), covering the whole content pane. 
      // Make it go away on any mouse press. 
      JPanel gp = new JPanel(); 
      gp = new JPanel(); 
      gp.setOpaque(false); 
      gp.setLayout(null); 
      gp.setBounds(contentPane.getBounds()); 
      gp.addMouseListener(new MouseAdapter() { 

       @Override 
       public void mousePressed(MouseEvent e) { 
        setGlassPaneVisible(false); 
       } 
      }); 

      // Create the "popup" - a component displayed on the transparent 
      // overlay. 
      JPanel popup = new JPanel(); 
      popup.setBorder(new CompoundBorder(
        new BevelBorder(BevelBorder.RAISED), 
        new EmptyBorder(5, 5, 5, 5))); 
      popup.setBackground(Color.YELLOW); 
      popup.add(new JLabel("Some info for \"" + getText() + "\".")); 
      // Needed since the glass pane has no layout manager. 
      popup.setSize(popup.getPreferredSize()); 

      // Position the popup just above the button that triggered 
      // its visibility. 
      Point buttonLocationInContentPane = SwingUtilities.convertPoint(this, 0, 0, contentPane); 
      int x = buttonLocationInContentPane.x; 
      int horizOverlap = x + popup.getWidth() - contentPane.getWidth(); 
      if (horizOverlap > 0) { 
       x -= horizOverlap; 
      } 
      int y = buttonLocationInContentPane.y - popup.getHeight(); 
      if (y < 0) { 
       y = 0; 
      } 
      popup.setLocation(x, y); 

      gp.add(popup); 

      return gp; 
     } 

     private void setGlassPaneVisible(boolean visible) { 
      KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 
      if (visible) { 
       theGlassPane = createGlassPane(); 
       rootPane.setGlassPane(theGlassPane); 
       theGlassPane.setVisible(true); 
       kfm.addKeyEventDispatcher(keyHook); 
      } else { 
       theGlassPane.setVisible(false); 
       kfm.removeKeyEventDispatcher(keyHook); 
       theGlassPane = null; 
      } 

     } 
    } 

    // A simple test program 
    public GlassPaneTest() { 
     setTitle("A glass pane example"); 
     setLayout(new FlowLayout(FlowLayout.CENTER)); 
     for (int i = 1; i <= 10; ++i) { 
      PropertiesButton pb = new PropertiesButton(this); 
      pb.setText("Properties button " + i); 
      add(pb); 
     } 
     setSize(400, 300); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       JFrame f = new GlassPaneTest(); 
       f.setDefaultCloseOperation(EXIT_ON_CLOSE); 
       f.setVisible(true); 
      } 
     }); 

    } 
} 
0

मेरा सुझाव है मई के बजाये WindowListener का उपयोग कर के, आप एक WindowStateListener का उपयोग करें, और उसके बाद का परीक्षण WindowEvent दोनों WINDOW_DEACTIVATED और WINDOW_LOST_FOCUS के लिए में पारित कर दिया। इसमें मूल विंडो के पीछे संवाद की संभावना शामिल होनी चाहिए।

0

मैं तो मैं इस समस्या पर एक कोशिश करने का निर्णय लिया उत्सुक था। आप को पता चला है, यह कठिन की तुलना में यह लग रहा है क्योंकि जो कुछ कोड आप WindowAdapter में लिखते हैं, यह हमेशा माता पिता खिड़की से पहले सक्रिय होगा और बटन ध्यान केंद्रित हो जाता है, और इसलिए संवाद पहले से ही बंद कर दिया जाएगा।

मेरा मानना ​​है कि समाधान सुनिश्चित करें बटन अक्षम है जब तक संवाद कुछ देर के लिए बंद कर दिया गया बनाने के लिए है, और है कि मैं क्या किया है है। डायलॉग बंद होने पर मैं बटन को अक्षम करता हूं। दूसरी चुनौती बटन को फिर से सक्षम करने का एक तरीका ढूंढना था, लेकिन माउस-डाउन ईवेंट संसाधित होने के बाद ही अन्यथा बटन क्लिक किया जाएगा और संवाद तुरंत दिखाई देगा।

मेरी पहली समाधान एक javax.swing.Timer जो 100ms की देरी है, जो तब बटन को फिर से सक्षम हैं के साथ, संवाद खोने फोकस पर एक बार को गति प्रदान करने के लिए सेट किया गया था इस्तेमाल किया। यह काम करता है क्योंकि छोटे समय की देरी सुनिश्चित हुई कि बटन तब तक सक्षम नहीं हुआ जब तक कि क्लिक ईवेंट पहले से ही बटन पर नहीं गया था, और चूंकि बटन अभी भी अक्षम था, इसलिए इसे क्लिक नहीं किया गया था। क्योंकि कोई टाइमर या देरी के लिए आवश्यक हैं

दूसरा समाधान है, जो मैं यहाँ पोस्ट, बेहतर है। मैं बस SwingUtilities.invokeLater में बटन को पुनः सक्षम करने के लिए कॉल को लपेटता हूं, जो इस ईवेंट को ईवेंट कतार के अंत में धक्का देता है। इस बिंदु पर, माउस-डाउन इवेंट पहले से ही कतार पर है, इसलिए इसके बाद बटन को सक्षम करने की क्रिया की गारंटी है, क्योंकि स्विंग ने क्रमशः क्रमशः संसाधित किया है। बटन को अक्षम करने और सक्षम करने से अचानक ऐसा होता है कि आपको ऐसा होने की संभावना नहीं है, लेकिन जब तक संवाद समाप्त नहीं हो जाता है, तब तक बटन पर क्लिक करने से रोकने के लिए पर्याप्त है।

उदाहरण कोड एक मुख्य विधि है जो एक JFrame में बटन डालता है। आप संवाद खोल सकते हैं और फिर बटन पर क्लिक करके या विंडो के शीर्षक पट्टी पर क्लिक करके इसे फोकस खो सकते हैं। मैंने आपके मूल कोड को दोबारा प्रतिक्रिया दी ताकि बटन केवल निर्दिष्ट संवाद को दिखाने और छिपाने के लिए ज़िम्मेदार हो, ताकि आप जिस भी वार्तालाप को चाहते हैं उसे दिखाने के लिए आप इसका पुनः उपयोग कर सकें।

import java.awt.Component; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.awt.event.WindowAdapter; 
import java.awt.event.WindowEvent; 

import javax.swing.JButton; 
import javax.swing.JCheckBox; 
import javax.swing.JDialog; 
import javax.swing.JFrame; 
import javax.swing.SwingUtilities; 
import javax.swing.WindowConstants; 

public class QuickDialogButton extends JButton { 

    private final JDialog dialog; 

    public QuickDialogButton(String label, JDialog d) { 
     super(label); 

     dialog = d; 

     dialog.addWindowListener(new WindowAdapter() { 
      public void windowDeactivated(WindowEvent e) { 
       // Button will be disabled when we return. 
       setEnabled(false); 
       dialog.setVisible(false); 
       // Button will be enabled again when all other events on the queue have finished. 
       SwingUtilities.invokeLater(new Runnable() { 
        @Override 
        public void run() { 
         setEnabled(true); 
        } 
       }); 
      } 
     }); 

     addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       Component c = (Component) e.getSource(); 
       dialog.setLocation(c.getLocationOnScreen().x, c.getLocationOnScreen().y + c.getHeight()); 
       dialog.setVisible(true); 
      } 
     }); 
    } 

    public static void main(String[] args) { 
     JFrame f = new JFrame("Parent Window"); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     JDialog d = new JDialog(f, "Child Dialog"); 
     d.setDefaultCloseOperation(WindowConstants.HIDE_ON_CLOSE); 
     d.add(new JCheckBox("Something")); 
     d.setUndecorated(true); 
     d.pack(); 

     f.add(new QuickDialogButton("Button", d)); 
     f.pack(); 
     f.setLocationRelativeTo(null); 
     f.setVisible(true); 
    } 

} 
0

यहां एक कामकाजी समाधान है। असल में हम विंडो को दिखाने से बचना चाहते हैं अगर यह बटन पर क्लिक करके बंद हो गया था जो विंडो को निष्क्रिय और छुपाता है। माउसडाउन और विंडो निष्क्रिय दोनों एक ही इनपुट घटना पर संसाधित होते हैं, हालांकि घटना के समय थोड़ा अलग होते हैं। माउसअप पर उत्पन्न होने के बाद से कार्रवाई का समय बहुत बाद में हो सकता है। WindowAdapter का उपयोग करना विंडो लिस्टनर के लिए सुविधाजनक है और @Override एनोटेशन का उपयोग करना टाइपो की वजह से सामान काम न करने से बचने के लिए अच्छा है।


public class PropertiesButton extends JButton { 

    private JDialog theWindow; 
    private long deactivateEventTime = System.currentTimeMillis(); 
    private long mouseDownTime; 

    public PropertiesButton(String text, final Frame launcher) { 
     super(text); 

     theWindow = new JDialog(); 
     theWindow.getContentPane().add(new JLabel("Properties")); 
     theWindow.pack(); 
// theWindow.setUndecorated(true); 
     theWindow.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); 
// theWindow.add(new JMenuCheckBoxItem("Something")); 
     theWindow.addWindowListener(new WindowAdapter() { 
      // just an example, need to implement other methods 
      @Override 
      public void windowDeactivated(WindowEvent e) { 
       deactivateEventTime = EventQueue.getMostRecentEventTime(); 
       theWindow.setVisible(false); 
      } 
     }); 
     this.addActionListener(new ActionListener() { 
      public void actionPerformed(ActionEvent e) { 
       boolean alsoDeactivated = Math.abs(deactivateEventTime - mouseDownTime) < 100; 
       if (theWindow.isVisible()) { 
        theWindow.setVisible(false); 
       } else if (!alsoDeactivated) { 
//     JButton btn = (JButton)e.getSource(); 
//     theWindow.setLocation(btn.getLocationOnScreen().x,btn.getLocationOnScreen().x+50); 
        theWindow.setVisible(true); 
       } 
      } 
     }); 
     theWindow.setVisible(false); 
    } 
    public void processMouseEvent(MouseEvent event) { 
     if (event.getID() == MouseEvent.MOUSE_PRESSED) { 
      mouseDownTime = event.getWhen(); 
     } 
     super.processMouseEvent(event); 
    } 
} 
संबंधित मुद्दे