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イベントは、編集モードの値を変更し、whileループが終了するようにnotifyAll()を発行します。ただし、テストによると、システムがwhileループを実行している場合、マウスをクリックしてもMouseClickedイベントは発生しません。

ActionListenerはMouseClickedイベントをブロックしますか?この問題を解決するにはどうすればよいですか?

ありがとう

4

2 に答える 2

8

Swingイベントスレッドを使用しないでくださいwhile(true)。同様に、Swingイベントスレッドを呼び出さないでwait()ください。GUI全体がフリーズし、完全に応答しなくなります。メインのSwingイベントスレッドまたは「イベントディスパッチスレッド」がすべてのSwing描画とユーザー操作を担当することを理解する必要があります。したがって、長時間実行またはフリーズするコードと結び付けると、GUI全体がロックされます。

代わりに、プログラムの状態を変更します。おそらく変数を1つか2つ設定して、プログラムの動作をこの状態に依存させます。より具体的なアドバイスが必要な場合は、達成しようとしている行動を教えてください。おそらく、より良い方法を提供できるでしょう。

Swingイベントスレッドの詳細については、以下をお読みください:レッスン:Swingでの並行性

編集
あなたの状態:

ユーザーがメニュー項目をクリックしたときに、ウィンドウから一連の「個別の」マウスクリックを介して情報を取得したいと思います。したがって、メニューをクリックすると、ユーザーは「ウィンドウ内のポイントを選択する」ように求められます。したがって、必要なのは、ActionListener関数(menu_addbound3)がマウスクリックを待つことです。したがって、待機/通知の設定。マウスクリックでedit_modeが変更され、notifyAll()によってwhileループでの待機が終了し、whileループが終了します。次に、menu_addbound3関数内で次の情報の入力を求めることができ、必要に応じてこれを繰り返します。 。

明確化してくれてありがとう、そして今、私はあなたがそれを間違っていることを間違いなくあなたに言うことができます、あなたは間違いなくwhileループを使用したくない、待ったり通知したりしたくないです。この問題を解決する方法はたくさんあります。ブール変数または列挙型変数を使用してプログラムに状態を​​与え、状態に応じてその動作を変更する方法があります。EditMode列挙型をMouseListenerで使用して、アクティブであることを通知できます。次に、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

議論から、あなたのクラスにいくつかの州を想定させることが、進むための最良の方法であるように思われます。これは、 1つ以上の列挙型変数によって実現できます。これを最初に理解するのが非常に難しいと思った理由は、MouseClicked関数にすべてのコードを含めることの利点を理解できなかったためです。これは醜く、せいぜい手に負えないものです。

ただし、複数の列挙型を使用し、処理をいくつかの外部関数に分割することで、実際に必要なものに適したシステムを実現できます。

于 2012-06-14T13:28:24.433 に答える