仅在按键时保留事件调度线程条目 (Java)
Leave Event Dispatch Thread entry ONLY on key press (Java)
我了解使用事件调度线程对 Java 中的界面进行任何更改很重要。但是,我不知道如何将这些事件操纵到 stop/continue/start。我想避免移动到 main() 的下一行(在将 Runnable 放入 EventQueue 的行之后),直到按下某个键。
为了清楚起见,我举了一个例子。我想在这里做的是生成 JFrame,允许用户使用箭头键移动框,然后按 Enter 停止框移动操作,然后才在 main() 结束时进行计算并使答案出现。我应该可以得到400、500、600等。因为JFrame出现后立即计算,所以答案总是300。
我为应该绑定到 Enter 的任何操作开辟了一个位置;它在绑定到箭头键的操作的声明下方。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EndTheShifter extends JFrame
{
private Color ourRectColor = new Color(28,222,144);
private int ourRectWidth = 50;
private int ourRectHeight = 50;
protected static Point ourRecLocation = new Point(100,100);
// Rectangle object can paint itself
public class Rectangle
{
protected void paint(Graphics2D g2d)
{
g2d.setColor(ourRectColor);
g2d.fillRect(ourRecLocation.x, ourRecLocation.y, ourRectWidth, ourRectHeight);
}
} // Rectangle class
// OurRectangle can create a Rectangle and call paint() on it
public class OurRectangle extends JPanel
{
private Rectangle capableRectangle;
public OurRectangle()
{
capableRectangle = new Rectangle();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
capableRectangle.paint(g2d);
g2d.dispose();
}
} // OurRectangle class
KeyStroke pressRight = KeyStroke.getKeyStroke("RIGHT");
KeyStroke pressLeft = KeyStroke.getKeyStroke("LEFT");
KeyStroke pressUp = KeyStroke.getKeyStroke("UP");
KeyStroke pressDown = KeyStroke.getKeyStroke("DOWN");
KeyStroke pressEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0);
OurRectangle recToWorkWith = new OurRectangle();
// Create InputMap and ActionMap
InputMap inputMap = recToWorkWith.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = recToWorkWith.getActionMap();
// Mapping Shortcut
protected void setTheAction(KeyStroke a, String b, Action c)
{
inputMap.put(a,b);
actionMap.put(b,c);
}
// Constructor!!!
public EndTheShifter()
{
add(recToWorkWith);
Action rightAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.x != 600)
ourRecLocation.x += 50;
else
ourRecLocation.x = 100;
recToWorkWith.repaint();
}
};
Action leftAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.x != 100)
ourRecLocation.x -= 50;
else
ourRecLocation.x = 600;
recToWorkWith.repaint();
}
};
Action downAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.y != 600)
ourRecLocation.y += 50;
else
ourRecLocation.y = 100;
recToWorkWith.repaint();
}
};
Action upAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.y != 100)
ourRecLocation.y -= 50;
else
ourRecLocation.y = 600;
recToWorkWith.repaint();
}
};
/*
Action enterAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
}
}
setTheAction(pressEnter,"enterAction",enterAction);
*/
setTheAction(pressRight,"rightAction",rightAction);
setTheAction(pressLeft,"leftAction",leftAction);
setTheAction(pressDown,"downAction",downAction);
setTheAction(pressUp,"upAction",upAction);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,800);
setVisible(true);
}
// Main kicks things off by putting all of the above
// in the Event Dispatch thread
// On an enter press, I want the last line of main() to run
public static void main(String[] argv)
{
EventQueue.invokeLater(
new Runnable()
{
@Override
public void run()
{
new EndTheShifter();
}
});
// What I want to trigger only on Enter
System.out.println(ourRecLocation.x + 2*ourRecLocation.y);
}
} // EndTheShifter, our outermost class
and ONLY then make the calculation at the end of main()
这不是 GUI 的工作方式。
main()方法仅用于显示框架。
一旦框架可见,EDT 就会启动,框架就在那里等待生成用户事件。
然后您的应用程序代码会响应这些用户事件。
I understand that it is important to use the Event Dispatch Thread for any changes to the interface in Java.
侦听器中调用的所有代码都在 EDT 上执行。因此,您的 Action 中的代码确实在 EDT 上执行。您不需要做任何特别的事情。
What I want to trigger only on Enter
那么该逻辑应该包含在输入操作中。
我支持camickr说的;可能有更好的方法来实现您想要做的事情。也就是说,如果你真的想让你的主方法等到按下回车键,方法如下:
首先,在您的文件顶部,定义一个用作同步锁的对象,如下所示:
public static final Object LOCK = new Object();
然后,在您的 main 方法中,在您的 println 语句之前,放置以下代码:
synchronized (LOCK) {
LOCK.wait();
}
它的作用是等待 LOCK
对象的监视器锁未被任何线程使用(非常简单的解释,阅读更多 here),然后它使当前线程(在这种情况下,启动您的主要方法的线程)无限期等待。
接下来,在您的 main 方法的方法头中添加一个 throws 声明:
public static void main(String[] argv) throws InterruptedException
这告诉编译器您的代码可能会抛出一个 InterruptedException
,如果您的线程在等待时被中断,就会发生这种情况。
最后,在您的 EndTheShifter
构造函数的任意位置,放置以下代码:
synchronized (LOCK) {
LOCK.notify();
}
这再次等待,直到 LOCK
对象的监视器锁变得可用,然后它“通知”所有等待 LOCK
对象的线程它们可以继续。在这种情况下,它会让我们的主线程继续执行 println。
我了解使用事件调度线程对 Java 中的界面进行任何更改很重要。但是,我不知道如何将这些事件操纵到 stop/continue/start。我想避免移动到 main() 的下一行(在将 Runnable 放入 EventQueue 的行之后),直到按下某个键。
为了清楚起见,我举了一个例子。我想在这里做的是生成 JFrame,允许用户使用箭头键移动框,然后按 Enter 停止框移动操作,然后才在 main() 结束时进行计算并使答案出现。我应该可以得到400、500、600等。因为JFrame出现后立即计算,所以答案总是300。
我为应该绑定到 Enter 的任何操作开辟了一个位置;它在绑定到箭头键的操作的声明下方。
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class EndTheShifter extends JFrame
{
private Color ourRectColor = new Color(28,222,144);
private int ourRectWidth = 50;
private int ourRectHeight = 50;
protected static Point ourRecLocation = new Point(100,100);
// Rectangle object can paint itself
public class Rectangle
{
protected void paint(Graphics2D g2d)
{
g2d.setColor(ourRectColor);
g2d.fillRect(ourRecLocation.x, ourRecLocation.y, ourRectWidth, ourRectHeight);
}
} // Rectangle class
// OurRectangle can create a Rectangle and call paint() on it
public class OurRectangle extends JPanel
{
private Rectangle capableRectangle;
public OurRectangle()
{
capableRectangle = new Rectangle();
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g.create();
capableRectangle.paint(g2d);
g2d.dispose();
}
} // OurRectangle class
KeyStroke pressRight = KeyStroke.getKeyStroke("RIGHT");
KeyStroke pressLeft = KeyStroke.getKeyStroke("LEFT");
KeyStroke pressUp = KeyStroke.getKeyStroke("UP");
KeyStroke pressDown = KeyStroke.getKeyStroke("DOWN");
KeyStroke pressEnter = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0);
OurRectangle recToWorkWith = new OurRectangle();
// Create InputMap and ActionMap
InputMap inputMap = recToWorkWith.getInputMap(JPanel.WHEN_IN_FOCUSED_WINDOW);
ActionMap actionMap = recToWorkWith.getActionMap();
// Mapping Shortcut
protected void setTheAction(KeyStroke a, String b, Action c)
{
inputMap.put(a,b);
actionMap.put(b,c);
}
// Constructor!!!
public EndTheShifter()
{
add(recToWorkWith);
Action rightAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.x != 600)
ourRecLocation.x += 50;
else
ourRecLocation.x = 100;
recToWorkWith.repaint();
}
};
Action leftAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.x != 100)
ourRecLocation.x -= 50;
else
ourRecLocation.x = 600;
recToWorkWith.repaint();
}
};
Action downAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.y != 600)
ourRecLocation.y += 50;
else
ourRecLocation.y = 100;
recToWorkWith.repaint();
}
};
Action upAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
if(ourRecLocation.y != 100)
ourRecLocation.y -= 50;
else
ourRecLocation.y = 600;
recToWorkWith.repaint();
}
};
/*
Action enterAction = new AbstractAction()
{
public void actionPerformed(ActionEvent e)
{
}
}
setTheAction(pressEnter,"enterAction",enterAction);
*/
setTheAction(pressRight,"rightAction",rightAction);
setTheAction(pressLeft,"leftAction",leftAction);
setTheAction(pressDown,"downAction",downAction);
setTheAction(pressUp,"upAction",upAction);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800,800);
setVisible(true);
}
// Main kicks things off by putting all of the above
// in the Event Dispatch thread
// On an enter press, I want the last line of main() to run
public static void main(String[] argv)
{
EventQueue.invokeLater(
new Runnable()
{
@Override
public void run()
{
new EndTheShifter();
}
});
// What I want to trigger only on Enter
System.out.println(ourRecLocation.x + 2*ourRecLocation.y);
}
} // EndTheShifter, our outermost class
and ONLY then make the calculation at the end of main()
这不是 GUI 的工作方式。
main()方法仅用于显示框架。
一旦框架可见,EDT 就会启动,框架就在那里等待生成用户事件。
然后您的应用程序代码会响应这些用户事件。
I understand that it is important to use the Event Dispatch Thread for any changes to the interface in Java.
侦听器中调用的所有代码都在 EDT 上执行。因此,您的 Action 中的代码确实在 EDT 上执行。您不需要做任何特别的事情。
What I want to trigger only on Enter
那么该逻辑应该包含在输入操作中。
我支持camickr说的;可能有更好的方法来实现您想要做的事情。也就是说,如果你真的想让你的主方法等到按下回车键,方法如下:
首先,在您的文件顶部,定义一个用作同步锁的对象,如下所示:
public static final Object LOCK = new Object();
然后,在您的 main 方法中,在您的 println 语句之前,放置以下代码:
synchronized (LOCK) {
LOCK.wait();
}
它的作用是等待 LOCK
对象的监视器锁未被任何线程使用(非常简单的解释,阅读更多 here),然后它使当前线程(在这种情况下,启动您的主要方法的线程)无限期等待。
接下来,在您的 main 方法的方法头中添加一个 throws 声明:
public static void main(String[] argv) throws InterruptedException
这告诉编译器您的代码可能会抛出一个 InterruptedException
,如果您的线程在等待时被中断,就会发生这种情况。
最后,在您的 EndTheShifter
构造函数的任意位置,放置以下代码:
synchronized (LOCK) {
LOCK.notify();
}
这再次等待,直到 LOCK
对象的监视器锁变得可用,然后它“通知”所有等待 LOCK
对象的线程它们可以继续。在这种情况下,它会让我们的主线程继续执行 println。