2016-04-08 10 views
0

Ich versuche gerade eine JPopupMenu anzuzeigen, wenn Sie mit der rechten Maustaste auf eine JTable klicken. Ich habe dies bereits auf verschiedene Arten erreicht, aber keiner von ihnen erlaubt mir zu tun, worum es in dieser Frage geht: Code ausführen, nachdem ich mit der rechten Maustaste auf den Tisch geklickt habe, aber das Popup-Menü erscheint auf dem Bildschirm.etwas tun, wenn Sie mit der rechten Maustaste außerhalb von JPopupMenu (UIManager-Problem) klicken

Wenn das Popup-Menü angezeigt wird und ich mit der rechten Maustaste darauf klicke, wird es an anderer Stelle wieder geöffnet. Es muss also ein Zuhörer in ihm sein, der ihm sagt, dass er das tun soll, aber ich kann es nicht finden. Im Idealfall würde ich @Override es und führen Sie den gleichen Code, den ich ausführe, wenn ich mit der rechten Maustaste auf die JTable.

Also, um die Frage zusammenzufassen, wie trigger ich etwas Code, wenn ich mit der rechten Maustaste außerhalb des Menüs (oder auf einer Tabellenzelle zum Beispiel), wenn das Menü immer noch Fokus hat (oder angezeigt wird)?

EDIT: Nach genauerem Hinsehen erkannte ich das Problem, aber nicht die Lösung. Die JPopupMenu ist nicht das Problem, aber die UIManager. Hier ist der Code meiner Testform, die das Problem zeigt ich beschreibe:

import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.JMenuItem; 
import javax.swing.JPopupMenu; 
import javax.swing.SwingUtilities; 
import javax.swing.UnsupportedLookAndFeelException; 

public class PopupTesting extends javax.swing.JFrame { 

    public PopupTesting() { 
     initComponents(); 
    } 

    private void initComponents() { 

     jScrollPane1 = new javax.swing.JScrollPane(); 
     jTable1 = new javax.swing.JTable(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     jTable1.setModel(new javax.swing.table.DefaultTableModel(
      new Object [][] { 
       {null, null, null, null}, 
       {null, null, null, null}, 
       {null, null, null, null}, 
       {null, null, null, null} 
      }, 
      new String [] { 
       "Title 1", "Title 2", "Title 3", "Title 4" 
      } 
     )); 
     jTable1.addMouseListener(new java.awt.event.MouseAdapter() { 
      @Override 
      public void mousePressed(java.awt.event.MouseEvent evt) { 
       jTable1MousePressed(evt); 
      } 
     }); 
     jScrollPane1.setViewportView(jTable1); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGap(61, 61, 61) 
       .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
       .addContainerGap(83, Short.MAX_VALUE)) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGap(69, 69, 69) 
       .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE) 
       .addContainerGap(121, Short.MAX_VALUE)) 
     ); 
     pack(); 
    }      

    private void jTable1MousePressed(java.awt.event.MouseEvent evt) {          
     if (SwingUtilities.isRightMouseButton(evt)) { 
      jTable1.setRowSelectionInterval(jTable1.rowAtPoint(evt.getPoint()), jTable1.rowAtPoint(evt.getPoint())); 
      getPopup().show(jTable1, evt.getX(), evt.getY()); 
     } 
    }          

    public static void main(String args[]) { 
     try { 
      javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); 
     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
      Logger.getLogger(PopupTesting.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     java.awt.EventQueue.invokeLater(() -> { 
      new PopupTesting().setVisible(true); 
     }); 
    } 

    private JPopupMenu getPopup() { 
     if (jTable1.getSelectedRow() > -1) { 
      JPopupMenu popup = new JPopupMenu(); 

      MouseListener listener = (new MouseAdapter() { 
       @Override 
       public void mousePressed(MouseEvent e) { 
        System.out.println("I'm a menu Item."); 
       } 
      }); 

      JMenuItem m = new JMenuItem("Regular Menu Item"); 
      m.addMouseListener(listener); 
      popup.add(m); 

      return popup; 
     } return null; 
    } 

    private javax.swing.JScrollPane jScrollPane1; 
    private javax.swing.JTable jTable1;    
} 

Wenn Sie die Zeile entfernen:

javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); 

und die umliegende try und catch, es einwandfrei funktioniert.

+0

Der "normale" Weg, um ein Popup anzuzeigen, ist durch ['JComponent # setComponentPopupMenu'] (https://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#setComponentPopupMenu (javax.swing.JPopupMenu)), können Sie einen 'PopupMenuListener' verwenden, um den Status des Popups zu überwachen, aber ich bin mir nicht ganz sicher, ob Ihnen das helfen kann. Sie möchten etwas unternehmen, wenn der Benutzer versucht, irgendwo anders mit der rechten Maustaste zu klicken, während das Popup noch sichtbar ist? – MadProgrammer

+0

@MadProgrammer Wenn Sie mit den von Windows verwendeten Popup-Menüs herumspielen, wenn Sie irgendwo anders klicken und das Menü auf dem Bildschirm angezeigt wird, wird sowohl das Click-Ereignis als auch das Click-Ereignis, auf das Sie klicken wollten, ausgelöst. JPopupMenu macht das nicht, es schließt nur und löst nicht aus. Ich möchte, dass es sich wie das Windows-Popup-Fenster verhält. – RaKXeR

Antwort

1

Nun, nach vielen Stunden versucht, das Problem zu beheben, landete ich ein kaputtes fix zu machen.Der Code, der tut, was ich bat hier:

import java.awt.AWTException; 
import java.awt.MouseInfo; 
import java.awt.Point; 
import java.awt.Robot; 
import java.awt.event.InputEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.util.logging.Level; 
import java.util.logging.Logger; 
import javax.swing.JMenuItem; 
import javax.swing.JPopupMenu; 
import javax.swing.SwingUtilities; 
import javax.swing.UnsupportedLookAndFeelException; 
import javax.swing.event.AncestorEvent; 
import javax.swing.event.AncestorListener; 

public class PopupTesting extends javax.swing.JFrame { 

    public PopupTesting() { 
     initComponents(); 
     jTable.setComponentPopupMenu(getPopup()); 
    } 

    volatile int lastMouse = 1; 

    private void initComponents() { 

     jScrollPane1 = new javax.swing.JScrollPane(); 
     jTable = new javax.swing.JTable(); 

     setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 

     jTable.setModel(new javax.swing.table.DefaultTableModel(
      new Object [][] { 
       {null, null, null, null}, 
       {null, null, null, null}, 
       {null, null, null, null}, 
       {null, null, null, null} 
      }, 
      new String [] { 
       "Title 1", "Title 2", "Title 3", "Title 4" 
      } 
     )); 
     jTable.addMouseListener(new java.awt.event.MouseAdapter() { 
      @Override 
      public void mousePressed(java.awt.event.MouseEvent evt) { 
       jTableMousePressed(evt); 
      } 
     }); 

     jScrollPane1.setViewportView(jTable); 

     javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 
     getContentPane().setLayout(layout); 
     layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGap(61, 61, 61) 
       .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 
       .addContainerGap(83, Short.MAX_VALUE)) 
     ); 
     layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 
      .addGroup(layout.createSequentialGroup() 
       .addGap(69, 69, 69) 
       .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 267, javax.swing.GroupLayout.PREFERRED_SIZE) 
       .addContainerGap(121, Short.MAX_VALUE)) 
     ); 
     pack(); 
    } 

    private void jTableMousePressed(java.awt.event.MouseEvent evt) {          
     lastMouse = evt.getButton(); 
     if (lastMouse == 3) lastMouse--; 
     lastMouse = InputEvent.getMaskForButton(lastMouse); 
    }         


    public static void main(String args[]) { 
     try { 
      javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName()); 
     } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { 
      Logger.getLogger(PopupTesting.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     java.awt.EventQueue.invokeLater(() -> { 
      new PopupTesting().setVisible(true); 
     }); 
    } 

    private JPopupMenu getPopup() { 
     JPopupMenu popup = new JPopupMenu(); 

     JMenuItem m = new JMenuItem("Regular Menu Item"); 
     m.addActionListener((ActionEvent e) -> { 
      System.out.println("I'm a menu Item."); 
     }); 
     popup.add(m); 
     PopupTesting frame = this; 
     popup.addAncestorListener(new AncestorListener() { 
      @Override 
      public void ancestorAdded(AncestorEvent event) { 
       Point mousePoint = MouseInfo.getPointerInfo().getLocation(); 
       mousePoint = SwingUtilities.convertPoint(frame, parseInt(mousePoint.getX() - getX()), parseInt(mousePoint.getY() - getY()), jTable); 
       jTable.setRowSelectionInterval(jTable.rowAtPoint(mousePoint), jTable.rowAtPoint(mousePoint)); 
      } 
      @Override public void ancestorRemoved(AncestorEvent event) { 
       try { 
        Robot bot = new Robot(); 
        bot.mousePress(lastMouse); 
        bot.mouseRelease(lastMouse); 
       } catch (AWTException ex) { 
        Logger.getLogger(PopupTesting.class.getName()).log(Level.SEVERE, null, ex); 
       } 
      } 
      @Override public void ancestorMoved(AncestorEvent event) {} 
     }); 
     return popup; 
    } 


    private int parseInt(Double val) { 
     return val.intValue(); 
    } 

    private javax.swing.JScrollPane jScrollPane1; 
    private javax.swing.JTable jTable;    
} 

Trotz setComponentPopupMenu() der Popup-Anzeige wieder, während es noch sichtbar ist, wird es nicht noch MouseListener s auslösen.

So wie ich „fest“ es war durch ein AncestorListener verwenden, das wäre ancestorAdded auslösen, wenn das Popup-Menü angezeigt wurde, und ancestorRemoved, wenn es um den Bildschirm verlassen.

Mit dem ancestorAdded habe ich es einfach so, dass, wenn das Menü angezeigt wurde, ist es auch die Zelle ausgewählt dahinter (viel Zeit nahm, um herauszufinden, wie die gleiche Position von MouseInfo zu bekommen, wie ich von MouseEvent bekommen würde , aber ich kam dorthin).

Mit der ancestorRemoved musste ich "betrügen". Grundsätzlich, jedes Mal, wenn ich auf den Tisch klicke (MousePressed), speichere ich, welche Taste dazu benutzt wurde. Dann, sobald ancestorRemoved ausgelöst wird, erstellt es eine Robot, die den letzten Mausklick wiederholt (wenn es Maus 1 war löst es Maus 1, Maus 2 löst Maus 2, usw.).

Diese Lösung funktioniert, aber es erlaubt mir nicht, eine Maustaste beim Beenden der JPopupMenu zu halten. Wenn jemand glaubt, die Lösung zu kennen, lassen Sie es mich bitte wissen, aber jetzt ist das Problem gelöst.

+0

'es wird immer noch nicht MouseListeners 'auslösen - vielleicht ist das das Problem. Sie sollten keinen MouseListener für einen Menüeintrag verwenden. Sie sollten einen ActionListener verwenden. Ich habe meine Antwort aktualisiert. Soweit ich das beurteilen kann, funktioniert es genauso wie Ihr Code. Außerdem sollten Sie lernen, wie Sie eine GUI erstellen, ohne die IDE zu verwenden, damit Sie weniger Code sehen können. – camickr

+0

@camickr Ich benutze den Netbeans-GUI-Editor (was ziemlich schlecht ist aber funktioniert), aber ich finde es einfacher, eine einfache Klasse für ein Beispiel zu verwenden – RaKXeR

+0

@camickr bearbeitet, so dass es einen ActionListener statt MouseListener verwendet. Ich hatte MouseListener benutzt, weil ich vor dieser Iteration des Codes eine viel kompliziertere Version hatte, und nachdem ich sie vereinfacht hatte, brauchte ich keine Mausklicks mehr zu erfassen, sondern vergaß sie zu ändern. – RaKXeR

1

oder auf den Tisch ist

Der Tabellenkopf der Tabelle nicht Teil, so dass es mit dem Maus-Ereignisse nicht reagiert. Sie müssen dem Tabellenkopf einen separaten Listener hinzufügen.

, wenn Sie woanders klicken und das Menü ist auf dem Bildschirm, es beide geschlossen und löst das Click-Ereignis, wo Sie

Adaequat klicken versucht, für mich JDK8 auf Windows 7 verwenden, wenn Sie klicken auf eine Zelle der Tabelle.

Wenn Sie weiterhin Probleme haben, dann senden Sie eine SSCCE, die das Problem demonstriert.

Edit:

Wie MadProgrammer in seinem Kommentar vorgeschlagen, die setComponentPoupMenu(...) Methode verwendet werden soll. Dies ist eine neuere API. Ich weiß nicht, was der Unterschied zwischen den beiden Ansätzen ist, aber die Verwendung dieser Methode funktioniert für mich auf beiden LAFs, die ich getestet habe.

Edit2:

Wieder es funktioniert immer noch für mich in Ordnung. Beachten Sie, dass Sie einem Menüelement keinen MouseListener hinzufügen sollten. Sie verwenden ein Action das Klicken des Menüpunktes zu handhaben:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class TableRightClick extends JFrame implements ActionListener 
{ 
    JPopupMenu popup; 

    public TableRightClick() 
    { 
     popup = new JPopupMenu(); 
     popup.add(new JMenuItem("Do Something1")); 
     JMenuItem menuItem = new JMenuItem("ActionPerformed"); 
     menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_A, ActionEvent.ALT_MASK)); 

     menuItem.addActionListener(this); 
     popup.add(menuItem); 

     JTable table = new JTable(10, 5); 

     table.addMouseListener(new MouseAdapter() 
     { 
      public void mousePressed(MouseEvent e) 
      { 
       JTable source = (JTable)e.getSource(); 
       int row = source.rowAtPoint(e.getPoint()); 
       int column = source.columnAtPoint(e.getPoint()); 

       if (! source.isRowSelected(row)) 
        source.changeSelection(row, column, false, false); 
      } 
     }); 

     table.setComponentPopupMenu(popup); 

     table.setPreferredScrollableViewportSize(table.getPreferredSize()); 
     getContentPane().add(new JScrollPane(table)); 

     JMenuBar menuBar = new JMenuBar(); 
     setJMenuBar(menuBar); 
     menuBar.add(popup); 
    } 

    public void actionPerformed(ActionEvent e) 
    { 
     Component c = (Component)e.getSource(); 
     JPopupMenu popup = (JPopupMenu)c.getParent(); 
     JTable table = (JTable)popup.getInvoker(); 
     System.out.println(table.getSelectedRow() + " : " + table.getSelectedColumn()); 
    } 

    public static void main(String[] args) 
    { 
     try 
     { 
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
     } 
     catch (Exception ex) { System.out.println(ex); } 

     TableRightClick frame = new TableRightClick(); 
     frame.setDefaultCloseOperation(EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setLocationRelativeTo(null); 
     frame.setVisible(true); 
    } 
} 
+0

von "oben auf dem Tisch" meinte ich so, als würde ich meinen Bildschirm von oben betrachten, also "vor dem Tisch". – RaKXeR

+0

könntest du mir vielleicht auch den Code zeigen, den du benutzt hast, der dieses Problem nicht hatte? – RaKXeR

+0

Sie zuerst. Sie wurden gebeten, eine 'SSCCE' zu veröffentlichen, die das Problem demonstriert. Ein Teil des Problemlösens ist zu lernen, wie man das Problem vereinfacht. Wahrscheinlich tust du etwas Seltsames. Ich habe keine Ahnung, was Sie mit "vor dem Tisch" meinen, weshalb Sie Ihren Demo-Code veröffentlichen müssen. – camickr