2016-10-07 13 views
2

私は個人的なプロジェクトを行っています。ボタンの機能の一部は、右クリックしたときに表示されるPopMenuです。昨日まで働いていたコードですが、今日はOOとなりましたが、MenuItemsをクリックするとメニューは表示されません。私は残念なことにバージョンコントロールを持っていないので、古いバージョンはありません。JMenuItemのActionListenerが機能しません

コードを以下に記載されている:

これは、これが実際のMenuItemあるPopUpMenuクラス

public class PopUpMenu extends JPopupMenu { 
    private Container parent; 

    public PopUpMenu(MenuItem[] menuItems) { 
     super(); 
     for (MenuItem item : menuItems) { 
      add(item); 
     } 
    } 

    public Container getParent() { 
     return parent; 
    } 

    public void setParent(Container parent) { 
     this.parent = parent; 
     parent.addMouseListener(new PopUpListener(this)); 
    } 

} 

あります。

public class MenuItem extends JMenuItem { 
    private String methodName; 

    public MenuItem(String methodName, String text) { 
     super(text); 
     setMethodName(methodName); 
     setFocusable(true); 
     addActionListener(new MenuItemListener()); 
    } 

    public String getMethodName() { 
     return methodName; 
    } 

    public void setMethodName(String methodName) { 
     this.methodName = methodName; 
    } 

} 

この

はここ abstract class IListenerある PopUpMenu

public class PopUpListener extends MouseAdapter { 
    private PopUpMenu menu; 

    public PopUpListener(PopUpMenu menu) { 
     setMenu(menu); 
    } 

    public void mouseReleased(MouseEvent event) { 
     if (event.isPopupTrigger()) { 
      menu.show(event.getComponent(), event.getX(), event.getY()); 
     } 
    } 

    public PopUpMenu getMenu() { 
     return menu; 
    } 

    public void setMenu(PopUpMenu menu) { 
     this.menu = menu; 
    } 

} 

MenuItem

public class MenuItemListener extends IListener { 

    protected void action(ActionEvent event) { 
     Object source = event.getSource(); 
     if (source instanceof MenuItem) { 
      MenuItem item = (MenuItem) source; 
      Container parent = item.getParent(); 
      if (parent instanceof PopUpMenu) { 
       PopUpMenu menu = (PopUpMenu) parent; 
       Container container = menu.getParent(); 
       try { 
        String name = item.getMethodName(); 
        Method method = container.getClass().getMethod(name); 
        method.invoke(container); 
       } catch (Exception e) { 
       } 
      } 
     } 
    } 

} 

このActionListenerActionListenerです。

public abstract class IListener implements ActionListener { 
    private boolean keyboardSensitive; 

    public IListener() { 
     setKeyboardSensitive(false); 
    } 

    @Override 
    public void actionPerformed(ActionEvent event) { 
     if ((event.getModifiers() != 0) || isKeyboardSensitive()) { 
      action(event); 
     } 
    } 

    protected abstract void action(ActionEvent event); 

    public boolean isKeyboardSensitive() { 
     return keyboardSensitive; 
    } 

    public void setKeyboardSensitive(boolean keyboardSensitive) { 
     this.keyboardSensitive = keyboardSensitive; 
    } 

} 

は、テストのビットの後、私は(デバッグの中にあれば削除することによって判明)、ActionListenerが実際にではなく、マウスのどのボタンで押されたキーによって活性化されたことが判明あなたといるので非常に参考にされていませんIListenerクラスで見ることができますが、キーボードからのイベントは受け入れたくありません。

IListenerは、私のプログラムで使用している他のすべてのための基礎でもあり、問題なく動作しているようです。

私の質問は、MenuItemListenerがマウスクリックによってアクティブになるように修正する必要があることです。

+0

「PopUpListener」クラスを追加できますか? – hamena314

+3

それがなければあなたのコードをテストすることができません。 [mcve]を作成すると、コードをコピーして、マシン上で何が間違っているのかを知ることができます。 – hamena314

答えて

2

は、この方法はjava.awt.Component.getParent()で定義されたgetParentを上書きしますPopUpMenu

public class PopUpMenu extends JPopupMenu { 
    private Container parent; 

    public PopUpMenu(MenuItem[] menuItems) { 
     super(); 
     for (MenuItem item : menuItems) { 
      add(item); 
     } 
    } 

    public void setParent(Container parent) { 
     this.parent = parent; 
     parent.addMouseListener(new PopUpListener(this)); 
    } 

} 

からgetParentメソッドを削除します。私はこれが予想外の動作につながると思います。

EDIT

私はわざとそのメソッドをオーバーライドしています。しかし、私はそれが問題を解決するかどうかを調べるためにそれを削除しようとしました。残念ながら、それはしませんでした。

このメソッドをオーバーライドすることはできますが、Component.getParentmethod's contractを必ず指定する必要があります。

PopUpMenuは、コンテナparentの子ではありません。つまり、PopUpMenuがコンテナparentを返すと、コンテナはPopUpMenuがその子であることも知っているはずです。例えば。 Container.getCompnents()にはPopUpMenuが含まれている必要があります。それが契約です。

しかし、実際にコンポーネントの親子関係を作成したくないので、状況には役立ちません。を呼び出したいオブジェクトへの参照を保持したいだけです。

この例は、私が上記のsuggesstedで修正したコードに基づいています。私はMVCEを提供するために、1つのコンパイル単位内のすべてを入れている:ここで

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

public class Main { 

    public static void main(String[] args) { 
     JFrame frame = createFrame(); 

     MenuItem menuItem1 = new MenuItem("getForeground", "Foreground Color"); 
     MenuItem menuItem2 = new MenuItem("getBackground", "Background Color"); 
     PopUpMenu popUpMenu = new PopUpMenu(new MenuItem[] { menuItem1, menuItem2 }); 
     popUpMenu.setParent(frame); 

     frame.setVisible(true); 
    } 

    private static JFrame createFrame() { 
     JFrame frame = new JFrame(); 
     frame.setSize(1000, 800); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     return frame; 
    } 

} 


class PopUpMenu extends JPopupMenu { 

    private Container parent; 

    public PopUpMenu(MenuItem[] menuItems) { 
     super(); 
     for (MenuItem item : menuItems) { 
      add(item); 
     } 
    } 

    public Container getParentComponent() { 
     // another name because I don't want to override getParent() 
     // Try to rename this method to getParent to see 
     // that it will not work 
     return parent; 
    } 

    public void setParent(Container parent) { 
     this.parent = parent; 
     parent.addMouseListener(new PopUpListener(this)); 
    } 

} 

class MenuItemListener extends IListener { 

    protected void action(ActionEvent event) { 
     Object source = event.getSource(); 
     if (source instanceof MenuItem) { 
      MenuItem item = (MenuItem) source; 
      Container parent = item.getParent(); 
      if (parent instanceof PopUpMenu) { 
       PopUpMenu menu = (PopUpMenu) parent; 
       Container container = menu.getParentComponent(); 
       try { 
        String name = item.getMethodName(); 
        Method method = container.getClass().getMethod(name); 
        Object invoke = method.invoke(container); 
        JOptionPane.showMessageDialog(container, invoke); 
       } catch (Exception e) { 
       } 
      } 
     } 
    } 

} 


abstract class IListener implements ActionListener { 
    private boolean keyboardSensitive; 

    public IListener() { 
     setKeyboardSensitive(false); 
    } 

    @Override 
    public void actionPerformed(ActionEvent event) { 
     if ((event.getModifiers() != 0) || isKeyboardSensitive()) { 
      action(event); 
     } 
    } 

    protected abstract void action(ActionEvent event); 

    public boolean isKeyboardSensitive() { 
     return keyboardSensitive; 
    } 

    public void setKeyboardSensitive(boolean keyboardSensitive) { 
     this.keyboardSensitive = keyboardSensitive; 
    } 

} 

class MenuItem extends JMenuItem { 
    private String methodName; 

    public MenuItem(String methodName, String text) { 
     super(text); 
     setMethodName(methodName); 
     setFocusable(true); 
     addActionListener(new MenuItemListener()); 
    } 

    public String getMethodName() { 
     return methodName; 
    } 

    public void setMethodName(String methodName) { 
     this.methodName = methodName; 
    } 

} 

class PopUpListener extends MouseAdapter { 
    private PopUpMenu menu; 

    public PopUpListener(PopUpMenu menu) { 
     setMenu(menu); 
    } 

    @Override 
    public void mousePressed(MouseEvent event) { 
     if (event.isPopupTrigger()) { 
      menu.show(event.getComponent(), event.getX(), event.getY()); 
     } 

    } 

    public void mouseReleased(MouseEvent event) { 
     if (event.isPopupTrigger()) { 
      menu.show(event.getComponent(), event.getX(), event.getY()); 
     } 
    } 

    public PopUpMenu getMenu() { 
     return menu; 
    } 

    public void setMenu(PopUpMenu menu) { 
     this.menu = menu; 
    } 

} 

PopUPMenuまたはMenuItemなどの専門(拡張)のクラスの多くを必要としません同じロジックのリファクタリングバージョンです。

import java.awt.*; 
import java.awt.event.*; 
import java.io.*; 
import java.lang.reflect.*; 
import java.text.MessageFormat; 

import javax.swing.*; 

public class Main { 

    public static void main(String[] args) { 
     JFrame frame = createFrame(); 

     JMenuItem foregroundMenuItem = createMenuItem(frame, "getForeground", "Foreground Color"); 
     JMenuItem backgroundMenuItem = createMenuItem(frame, "getBackground", "Background Color"); 

     JPopupMenu popupMenu = new JPopupMenu(); 

     popupMenu.add(foregroundMenuItem); 
     popupMenu.add(backgroundMenuItem); 

     PopUpListener popUpListener = new PopUpListener(popupMenu); 
     frame.addMouseListener(popUpListener); 

     frame.setVisible(true); 
    } 

    private static JMenuItem createMenuItem(Object invocationTarget, String methodName, String actionName) { 
     MethodInvocationAction methodInvocationAction = new MethodInvocationAction(invocationTarget, methodName); 
     methodInvocationAction.putValue(Action.NAME, actionName); 

     JMenuItem menuItem = new JMenuItem(methodInvocationAction); 
     return menuItem; 
    } 

    private static JFrame createFrame() { 
     JFrame frame = new JFrame(); 
     frame.setSize(1000, 800); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     return frame; 
    } 

} 

class MethodInvocationAction extends AbstractAction { 

    private Object targetObj; 
    private Method targetMethod; 

    private boolean keyboardSensitive; 

    public MethodInvocationAction(Object targetObj, String methodName) { 
     this.targetObj = targetObj; 
     try { 
      targetMethod = targetObj.getClass().getMethod(methodName); 
     } catch (NoSuchMethodException | SecurityException e) { 
      String msg = MessageFormat.format("{0} does not have a method named {1}", targetObj, methodName); 
      throw new RuntimeException(msg, e); 
     } 
    } 

    public boolean isKeyboardSensitive() { 
     return keyboardSensitive; 
    } 

    public void setKeyboardSensitive(boolean keyboardSensitive) { 
     this.keyboardSensitive = keyboardSensitive; 
    } 

    @Override 
    public void actionPerformed(ActionEvent event) { 
     if ((event.getModifiers() != 0) || isKeyboardSensitive()) { 
      performAction(event); 
     } 
    } 

    public void performAction(ActionEvent e) { 
     try { 
      Object invoke = targetMethod.invoke(targetObj); 
      JOptionPane.showMessageDialog(null, invoke); 
     } catch (Exception exception) { 
      showException(exception); 
     } 
    } 

    private void showException(Exception e1) { 
     StringWriter exceptionStackTraceWriter = new StringWriter(); 
     e1.printStackTrace(new PrintWriter(exceptionStackTraceWriter)); 
     String exceptionStackTrace = exceptionStackTraceWriter.toString(); 

     JTextArea exceptionStackTraceTextComponent = new JTextArea(); 
     exceptionStackTraceTextComponent.setText(exceptionStackTrace); 

     JScrollPane scrollPane = new JScrollPane(exceptionStackTraceTextComponent); 
     scrollPane.setPreferredSize(new Dimension(800, 600)); 

     JOptionPane.showMessageDialog(null, scrollPane, e1.getLocalizedMessage(), JOptionPane.ERROR_MESSAGE); 
    } 
} 

class PopUpListener extends MouseAdapter { 
    private JPopupMenu menu; 

    public PopUpListener(JPopupMenu menu) { 
     this.menu = menu; 
    } 

    public void mousePressed(MouseEvent event) { 
     handlePopupEvent(event); 
    } 

    public void mouseReleased(MouseEvent event) { 
     handlePopupEvent(event); 
    } 

    private void handlePopupEvent(MouseEvent event){ 
     if (event.isPopupTrigger()) { 
      menu.show(event.getComponent(), event.getX(), event.getY()); 
     } 
    } 

} 
+0

私はそのメソッドを目的に合わせてオーバーライドしています。しかし、私はそれが問題を解決するかどうかを調べるためにそれを削除しようとしました。残念ながら、それはしませんでした。 –

+0

このコードを追加したと仮定します: 'Object invoke = method.invoke(container); JOptionPane.showMessageDialog(container、invoke); 'プログラムが動作していることを示すために、テスト後に削除する必要があります。正しい? –

+0

また、なぜ 'mousClicked()'メソッドを 'PopUpListener'クラスに追加しましたか? –

関連する問題