3

我有一个带有以下 ActionListener 的 MenuItem“maddbound3”窗口:

maddbound3.addActionListener
(
    new ActionListener()
    {
        public void actionPerformed(ActionEvent e)
        { 
            menu_addbound3();
        } 
    }
);

单击菜单时,此侦听器将调用下面的 menu_addbound3():

void menu_addbound3()
{
    while(getEditMode() != EditMode.NONE)
    {
        System.out.println("!... " + getEditMode());

        synchronized(this)
        {
            try
            {
                wait();
            }
            catch(InterruptedException e)
            {
                e.printStackTrace();
            }
        }
    }
}

MouseClicked 事件更改编辑模式的值并发出 notifyAll() 以便退出 while 循环。但是,测试表明,当系统通过 while 循环运行时,鼠标单击时不会发生 MouseClicked 事件。

ActionListener 会阻止 MouseClicked 事件吗?我该如何解决这个问题?

谢谢

4

2 回答 2

8

不要while(true)在 Swing 事件线程上使用,同样不要wait()在 Swing 事件线程上调用——您将冻结整个 GUI,使其完全无响应。您需要了解主 Swing 事件线程或“事件调度线程”负责所有 Swing 绘图和用户交互,因此如果您将其与长时间运行或冻结的代码捆绑在一起,您就会锁定整个 GUI。

相反,改变你的程序的状态——也许通过设置一个或两个变量,让你的程序的行为依赖于这个状态。如果您需要更具体的建议,请告诉我们您想要实现的行为,我们或许可以为您提供更好的方法。

有关 Swing 事件线程的更多信息,请阅读:课程:Swing 中的并发

编辑
你状态:

当用户单击菜单项时,我想通过窗口中的一系列“离散”鼠标单击来获取信息。因此,在单击菜单时,将提示用户“在窗口中选择一个点”。所以,我需要的是我的 ActionListener 函数(menu_addbound3)然后等待鼠标点击。因此等待/通知设置。鼠标单击更改 edit_mode 和 notifyAll() 导致 while 循环中的等待退出,然后导致 while 循环退出,然后我可以在 menu_addbound3 函数中提示我的下一点信息,根据需要重复此操作.

感谢您的澄清,现在我可以肯定地告诉您,您做错了,您绝对不想使用 while 循环或等待或通知。有很多方法可以解决这个问题,一种是使用一些布尔变量或枚举变量来给程序一个状态,然后根据状态改变它的行为。您可以在 MouseListener 中使用您的 EditMode 枚举以使其知道其处于活动状态,然后您还可以为 MouseListener 类提供一个布尔变量 windowPointSelected,设置为 false,然后仅在第一次单击后将其设置为 true。

编辑 2
例如:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.*;

@SuppressWarnings("serial")
public class ProgState extends JPanel {
   private static final int PREF_W = 400;
   private static final int PREF_H = PREF_W;
   private static final Color EDIT_COLOR = Color.red;
   private EditMode editMode = EditMode.NONE;
   private boolean firstPointSelected = false;
   private JMenuBar jMenuBar = new JMenuBar();
   private JTextField firstPointField = new JTextField(15);
   private JTextField secondPointField = new JTextField(15);

   public ProgState() {
      add(firstPointField);
      add(secondPointField);

      JMenu menu = new JMenu("Menu");
      menu.add(new JMenuItem(new AbstractAction("Edit") {

         @Override
         public void actionPerformed(ActionEvent arg0) {
            setEditMode(EditMode.EDITING);
            setFirstPointSelected(false);
         }
      }));
      jMenuBar.add(menu);

      addMouseListener(new MouseAdapter() {

         @Override
         public void mousePressed(MouseEvent mEvt) {
            if (getEditMode() == EditMode.EDITING) {
               Point p = mEvt.getPoint();
               String pStr = String.format("[%d, %d]", p.x, p.y);
               if (!isFirstPointSelected()) {
                  firstPointField.setText(pStr);
                  setFirstPointSelected(true);
               } else {
                  secondPointField.setText(pStr);
                  setEditMode(EditMode.NONE);
               }
            }
         }

      });
   }

   public void setEditMode(EditMode editMode) {
      this.editMode = editMode;

      Color c = editMode == EditMode.NONE ? null : EDIT_COLOR;
      setBackground(c);
   }

   public EditMode getEditMode() {
      return editMode;
   }

   public void setFirstPointSelected(boolean firstPointSelected) {
      this.firstPointSelected = firstPointSelected;
   }

   public boolean isFirstPointSelected() {
      return firstPointSelected;
   }

   @Override
   public Dimension getPreferredSize() {
      return new Dimension(PREF_W, PREF_H);
   }

   public JMenuBar getJMenuBar() {
      return jMenuBar;
   }

   private static void createAndShowGui() {
      ProgState progState = new ProgState();

      JFrame frame = new JFrame("EditMode");
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.getContentPane().add(progState);
      frame.setJMenuBar(progState.getJMenuBar());
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   }

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

enum EditMode {
   NONE, EDITING
}
于 2012-06-14T11:55:26.023 回答
0

从讨论看来,让你的班级假设一些状态是最好的方法。我们可以通过一个或多个枚举变量来实现这一点。最初我发现这很难理解的原因是我看不到在 MouseClicked 函数中包含所有代码的好处。这是丑陋的,充其量是无法管理的。

但是,使用多个枚举并将处理拆分为多个外部函数,我们确实实现了我们想要的一个很好的系统。

于 2012-06-14T13:28:24.433 回答