2016-04-08 2 views
0

В настоящее время я пытаюсь отобразить JPopupMenu, щелкнув правой кнопкой мыши JTable. Я уже достиг этого по-разному, но ни один из них не позволяет мне делать то, о чем идет речь: выполнение кода после того, как я нажму правой кнопкой мыши на таблице, но всплывающее меню находится на экране.что-то делать, когда щелкнув правой кнопкой мыши за пределами JPopupMenu (проблема UIManager)

Когда всплывающее меню отображается и я нажимаю его правой кнопкой, он снова открывается в другом месте. Таким образом, внутри него должен присутствовать слушатель, который говорит ему об этом, но я не могу его найти. В идеале я бы @Override и выполнил тот же код, который я выполняю, когда я нажимаю правой кнопкой мыши на JTable.

Итак, чтобы подытожить вопрос, как я могу вызвать некоторый код, когда я нажимаю правой кнопкой мыши вне меню (или, например, на ячейке таблицы), когда в меню все еще есть фокус (или отображается)?

EDIT: Рассмотрев более тщательно, я определил проблему, но не решение. JPopupMenu не проблема, а UIManager. Вот код моей тестовой форме, которая отображает проблему, которую я описываю:

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

Если вы удалите строку:

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

и окружающий try и catch, она работает безупречно.

+0

«Обычный» способ показать всплывающее окно через ['JComponent # setComponentPopupMenu'] (https://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#setComponentPopupMenu (javax.swing.JPopupMenu)), вы можете использовать 'PopupMenuListener' для контроля состояния всплывающего окна, но я не совсем уверен, что это может вам помочь. Вы хотите предпринять некоторые действия, когда пользователь пытается щелкнуть правой кнопкой мыши в другом месте, пока всплывающее окно все еще отображается? – MadProgrammer

+0

@MadProgrammer, если вы играете со всплывающими меню, которые используют Windows, когда вы нажимаете на другое место, и меню находится на экране, оно закрывает и запускает событие щелчка, в котором вы пытались щелкнуть. JPopupMenu этого не делает, он просто закрывается и не запускается. Я хочу, чтобы он вел себя как всплывающее окно Windows. – RaKXeR

ответ

1

Ну, после многих часов, пытаясь решить проблему, я в конечном итоге сделать хитроумный исправить.Код, который делает то, что я просил здесь:

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

Несмотря на setComponentPopupMenu() отображение всплывающего окна снова, пока он еще виден, он по-прежнему обыкновение вызывать MouseListener с.

Как я «фиксированный» он был с помощью AncestorListener, что вызовет ancestorAdded когда появится всплывающее меню, и ancestorRemoved, когда он вышел на экран.

С ancestorAdded, я просто сделал так, что всякий раз, когда отображалось меню, он также выбрал клетку за ней (потребовалось много времени, чтобы выяснить, как получить ту же позицию с MouseInfo, как я хотел бы получить от MouseEvent , но я добрался туда).

С ancestorRemoved мне пришлось «обмануть». В принципе, каждый раз, когда я нажимаю (MousePressed) на стол, я хранил, какая кнопка была использована для этого. Затем, как только ancestorRemoved запускается, он создает Robot, который повторяет последний щелчок мыши (если это была мышь 1, она запускает мышь 1, мышь 2 запускает мышь 2 и т. Д.).

Это решение работает, однако это не позволяет мне удерживать кнопку мыши при выходе из JPopupMenu. Если кто-то считает, что знает решение, сообщите мне, но на данный момент проблема решена.

+0

'все еще не запускает MouseListeners' - может быть, это проблема. Вы не должны использовать MouseListener в пункте меню. Вы должны использовать ActionListener. Я обновил свой ответ. Насколько я могу сказать, он работает так же, как и ваш код. Кроме того, вам действительно нужно научиться создавать графический интерфейс без использования среды IDE, чтобы было меньше кода для просмотра. – camickr

+0

@camickr Я использую редактор графического редактора Netbeans (который работает не так плохо, но работает), но мне проще использовать простой класс для примера здесь – RaKXeR

+0

@camickr отредактирован, поэтому он использует ActionListener вместо MouseListener. Я использовал MouseListener, потому что перед этой итерацией кода у меня была гораздо более сложная версия, и как только я упростил ее, мне больше не нужно было захватывать щелчки мыши, но забыл изменить ее. – RaKXeR

1

или на верхней части таблицы

заголовок таблицы не является частью таблицы, поэтому он не будет реагировать на события мыши. Вам нужно добавить отдельный прослушиватель в заголовок таблицы.

при нажатии кнопки где-нибудь еще, и меню на экране, это как закрывается и запускает событие щелчка, где вы пытались мне с помощью JDK8 на Windows 7 щелкнуть

отлично работает, если нажать на ячейку таблицы.

Если у вас по-прежнему возникают проблемы, отправьте сообщение SSCCE, что демонстрирует проблему.

Edit:

Как MadProgrammer предложил в своем комментарии, метод setComponentPoupMenu(...) следует использовать. Это новый API. Я не знаю, какая разница между этими двумя подходами, но использование этого метода работает для меня на обоих LAF, которые я тестировал.

Edit2:

Еще раз он все еще работает хорошо для меня. Обратите внимание, что вы не должны добавлять MouseListener в элемент меню. Вы используете ActionListener обрабатывать щелчки пункта меню:

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

«сверху таблицы» Я имел в виду, как будто я просматривал свой экран сверху, так что «перед столом». – RaKXeR

+0

также не могли бы вы показать мне код, который вы использовали, который не сталкивался с этой проблемой? – RaKXeR

+0

Вы сначала. Вас попросили опубликовать «SSCCE», который демонстрирует проблему. Частью решения проблемы является изучение того, как упростить проблему. Скорее всего, вы делаете что-то странное. Я понятия не имею, что вы подразумеваете под «перед столом», поэтому вам нужно разместить свой демо-код. – camickr

Смежные вопросы