使用处理程序在 EDT 和其他线程 Java 之间传递信息
Passing information between EDT and other threads Java with a Handler
我有一个 GUI(在它的 EDT 线程上)和另一个名为 "Recorder" 的线程,如果按下按钮则由 GUI 的 eventListener 创建:
if(actionEvent.getSource().equals(ui.record)) {
if(recorderThread == null) {
recorder = new Recorder();
recorderThread = new Thread(recorder);
recorderThread.start();
}
}
在同一个事件监听器中,我还实现了一个mouseListener。
public void mouseReleased(MouseEvent mEvent) {
int x, y;
x = mEvent.getXOnScreen();
y = mEvent.getYOnScreen();
}
我想在单击鼠标时将这些 X 和 Y 变量传递到记录器线程中的记录器对象。我想我可以避免使用易失性变量的解决方案,但我在某处读到处理程序可用于在两个线程之间传递信息或调用方法,并且有兴趣了解它。我发现 面临着与我类似的问题。
post 的解决方案,但是,我很困惑。我认为这个人将线程对象传递给处理程序,这样任何线程都可以调用该处理程序中的所有对象?例如:
handler(someObj);
然后在另一个线程中
handler.getSomeObj().methodInObj();
但我不完全确定这是否是处理程序的工作方式。此外,他们似乎也在处理Swing的后台线程而不是用户创建的单独线程(如果这是相同的概念,请提前致歉)。
最后,解决方案似乎调用了 Java 库中内置的处理程序 class,而我想编写自己的处理程序 class 以便更好地了解线程如何工作沟通(因为我是一个真正的新手 youtube 教过的程序员)。如果有人可以帮助我,我将不胜感激。提前致谢!
一方面区分线程的概念,另一方面区分 classes(包括实例及其成员)的概念。
线程可以通过多种方式进行通信(意味着在其他线程可以写入或读取的地方读取或写入变量。在您的示例中,我会让您的 Recorder class 公开一个 public 方法 addCoordinates()。记录器有一个私有列表成员,其中存储添加的坐标。真正的问题是同步访问这个列表:你必须确保没有一个线程读取列表而另一个线程添加新记录- 同时。最简单的解决方案是有一个同步列表:
private List<Coordinates> myCoordinates = Collections.synchronizedList( new ArrayList<>());
public void addCoordinates( Coordinates coordinates)
{
// this runs in the context of your GUI thread
myCoordinates.add(coordinates);
synchronized(this)
{
this.notify(); // wakes up the recorder thread
}
}
public void run()
{
// this runs in the context of the Recorder thread
while ( true)
{
synchronized(this)
{
this.wait(); // waits until the 'this' is notified
}
for( Coordinates c : myCoordinates)
{
// do something
}
}
}
The recorder simply creates a list of objects called "Point" that store the X and Y position of the mouseclick, to be used later by an autoclicker
那么记录器不应该 运行 在它自己的线程中,因为没有必要这样做,而是直接从 GUI 写入记录器 在 EDT 线程上。否则你会使事情变得过于复杂。例外情况是 Recorder 实际上做的更多,例如目前 运行 一个外部进程。
例如:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class TestRecorder extends JPanel {
private static final int GAP = 3;
private MyRecorder myRecorder = new MyRecorder();
private boolean recording = false;
public TestRecorder() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
btnPanel.add(new JButton(new StartAction("Start")));
btnPanel.add(new JButton(new StopAction("Stop")));
btnPanel.add(new JButton(new ShowAction("Show")));
addMouseListener(new MyMouse());
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setPreferredSize(new Dimension(500, 400));
setLayout(new BorderLayout());
add(btnPanel, BorderLayout.PAGE_END);
}
private class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
if (recording) {
myRecorder.addPoint(e.getPoint());
}
}
}
private class StartAction extends AbstractAction {
public StartAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
recording = true;
}
}
private class StopAction extends AbstractAction {
public StopAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
recording = false;
}
}
private class ShowAction extends AbstractAction {
public ShowAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Points:");
for (Point point : myRecorder.getPoints()) {
System.out.println(point);
}
System.out.println();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
TestRecorder mainPanel = new TestRecorder();
JFrame frame = new JFrame("TestRecorder");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
public class MyRecorder {
private List<Point> points = new ArrayList<>();
public List<Point> getPoints() {
return points;
}
public void addPoint(Point p) {
points.add(p);
}
}
我有一个 GUI(在它的 EDT 线程上)和另一个名为 "Recorder" 的线程,如果按下按钮则由 GUI 的 eventListener 创建:
if(actionEvent.getSource().equals(ui.record)) {
if(recorderThread == null) {
recorder = new Recorder();
recorderThread = new Thread(recorder);
recorderThread.start();
}
}
在同一个事件监听器中,我还实现了一个mouseListener。
public void mouseReleased(MouseEvent mEvent) {
int x, y;
x = mEvent.getXOnScreen();
y = mEvent.getYOnScreen();
}
我想在单击鼠标时将这些 X 和 Y 变量传递到记录器线程中的记录器对象。我想我可以避免使用易失性变量的解决方案,但我在某处读到处理程序可用于在两个线程之间传递信息或调用方法,并且有兴趣了解它。我发现
post 的解决方案,但是,我很困惑。我认为这个人将线程对象传递给处理程序,这样任何线程都可以调用该处理程序中的所有对象?例如:
handler(someObj);
然后在另一个线程中
handler.getSomeObj().methodInObj();
但我不完全确定这是否是处理程序的工作方式。此外,他们似乎也在处理Swing的后台线程而不是用户创建的单独线程(如果这是相同的概念,请提前致歉)。
最后,解决方案似乎调用了 Java 库中内置的处理程序 class,而我想编写自己的处理程序 class 以便更好地了解线程如何工作沟通(因为我是一个真正的新手 youtube 教过的程序员)。如果有人可以帮助我,我将不胜感激。提前致谢!
一方面区分线程的概念,另一方面区分 classes(包括实例及其成员)的概念。
线程可以通过多种方式进行通信(意味着在其他线程可以写入或读取的地方读取或写入变量。在您的示例中,我会让您的 Recorder class 公开一个 public 方法 addCoordinates()。记录器有一个私有列表成员,其中存储添加的坐标。真正的问题是同步访问这个列表:你必须确保没有一个线程读取列表而另一个线程添加新记录- 同时。最简单的解决方案是有一个同步列表:
private List<Coordinates> myCoordinates = Collections.synchronizedList( new ArrayList<>());
public void addCoordinates( Coordinates coordinates)
{
// this runs in the context of your GUI thread
myCoordinates.add(coordinates);
synchronized(this)
{
this.notify(); // wakes up the recorder thread
}
}
public void run()
{
// this runs in the context of the Recorder thread
while ( true)
{
synchronized(this)
{
this.wait(); // waits until the 'this' is notified
}
for( Coordinates c : myCoordinates)
{
// do something
}
}
}
The recorder simply creates a list of objects called "Point" that store the X and Y position of the mouseclick, to be used later by an autoclicker
那么记录器不应该 运行 在它自己的线程中,因为没有必要这样做,而是直接从 GUI 写入记录器 在 EDT 线程上。否则你会使事情变得过于复杂。例外情况是 Recorder 实际上做的更多,例如目前 运行 一个外部进程。
例如:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
@SuppressWarnings("serial")
public class TestRecorder extends JPanel {
private static final int GAP = 3;
private MyRecorder myRecorder = new MyRecorder();
private boolean recording = false;
public TestRecorder() {
JPanel btnPanel = new JPanel(new GridLayout(1, 0, GAP, 0));
btnPanel.add(new JButton(new StartAction("Start")));
btnPanel.add(new JButton(new StopAction("Stop")));
btnPanel.add(new JButton(new ShowAction("Show")));
addMouseListener(new MyMouse());
setBorder(BorderFactory.createEmptyBorder(GAP, GAP, GAP, GAP));
setPreferredSize(new Dimension(500, 400));
setLayout(new BorderLayout());
add(btnPanel, BorderLayout.PAGE_END);
}
private class MyMouse extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
if (recording) {
myRecorder.addPoint(e.getPoint());
}
}
}
private class StartAction extends AbstractAction {
public StartAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
recording = true;
}
}
private class StopAction extends AbstractAction {
public StopAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
recording = false;
}
}
private class ShowAction extends AbstractAction {
public ShowAction(String name) {
super(name);
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Points:");
for (Point point : myRecorder.getPoints()) {
System.out.println(point);
}
System.out.println();
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui() {
TestRecorder mainPanel = new TestRecorder();
JFrame frame = new JFrame("TestRecorder");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
}
public class MyRecorder {
private List<Point> points = new ArrayList<>();
public List<Point> getPoints() {
return points;
}
public void addPoint(Point p) {
points.add(p);
}
}