多线程锁定Java Swing GUI
我正在为一个多用户绘制程序做一个项目,我遇到了一个GUI锁定问题 我已经完成了大部分程序,除了这个错误,它是一个相当大的程序,所以我尝试在一个较小的程序中重现错误 在这个较小的程序中,我有两个JFrames。可以通过单击并拖动鼠标来绘制这两个图形。次要JFrame是一个休眠10秒的线程,然后将您绘制的内容发送到另一个要显示的帧 但是,一旦主帧接收到来自次帧的图像,GUI将锁定,主帧将无法再绘制 我目前正在使用SwingUtilities.invokeLater()方法。在寻找答案的过程中,我找到了SwingWorker类,但我想先看看是否有一个简单的解决方案,然后再对我的代码进行大规模重写,以使其与SwingWorker一起工作 谢谢你的阅读。我的代码如下。还有,这是我第一次在这里发帖。我似乎在格式化代码时遇到了一些问题,所以如果出现错误,我会提前道歉。我会尽我最大的努力把它修好多线程锁定Java Swing GUI,java,multithreading,swing,swingutilities,Java,Multithreading,Swing,Swingutilities,我正在为一个多用户绘制程序做一个项目,我遇到了一个GUI锁定问题 我已经完成了大部分程序,除了这个错误,它是一个相当大的程序,所以我尝试在一个较小的程序中重现错误 在这个较小的程序中,我有两个JFrames。可以通过单击并拖动鼠标来绘制这两个图形。次要JFrame是一个休眠10秒的线程,然后将您绘制的内容发送到另一个要显示的帧 但是,一旦主帧接收到来自次帧的图像,GUI将锁定,主帧将无法再绘制 我目前正在使用SwingUtilities.invokeLater()方法。在寻找答案的过程中,我找到
package gui_thread_test;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
import javax.swing.JComponent;
public class DrawPanel extends JComponent
{
private Image canvas;
private int x, y, prevX, prevY;
Graphics2D g2;
public DrawPanel()
{
setDoubleBuffered(false);
addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e )
{
prevX = e.getX();
prevY = e.getY();
}
});
addMouseMotionListener(new MouseMotionAdapter()
{
@Override
public void mouseDragged(MouseEvent e)
{
x = e.getX();
y = e.getY();
g2.drawLine(prevX, prevY, x, y);
repaint();
prevX = x;
prevY = y;
}
});
}
@Override
public void paintComponent(Graphics g)
{
if (canvas == null)
{
canvas = createImage(getSize().width, getSize().height);
g2 = (Graphics2D) canvas.getGraphics();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
}
g.drawImage(canvas, 0, 0, null);
}
public synchronized void updateCanvas(Image _canvas)
{
canvas = _canvas;
repaint();
}
public Image getImage()
{
return canvas;
}
}
-
-
每10秒传输一次,使用一个摆动计时器而不是线程。使用BuffereImage保存图形并传输图形 例如:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class GuiDoubleDraw extends JPanel {
private static final int BI_WIDTH = 500;
private static final int BI_HEIGHT = BI_WIDTH;
public static final Color PEN_COLOR = Color.black;
private BufferedImage backgroundImg = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
public GuiDoubleDraw() {
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(BI_WIDTH, BI_HEIGHT);
}
public BufferedImage getBackgroundImage() {
BufferedImage copyImg = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics g = copyImg.getGraphics();
g.drawImage(backgroundImg, 0, 0, null);
g.dispose();
return copyImg;
}
public void setBackgroundImage(BufferedImage bImg) {
this.backgroundImg = bImg;
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
Point previousPt = null;
@Override
public void mousePressed(MouseEvent mEvt) {
previousPt = mEvt.getPoint();
}
@Override
public void mouseDragged(MouseEvent mEvt) {
drawPt(mEvt);
}
@Override
public void mouseReleased(MouseEvent mEvt) {
drawPt(mEvt);
}
private void drawPt(MouseEvent mEvt) {
Graphics g = backgroundImg.getGraphics();
Point nextPt = mEvt.getPoint();
g.setColor(PEN_COLOR);
g.drawLine(previousPt.x, previousPt.y, nextPt.x, nextPt.y);
g.dispose();
previousPt = nextPt;
repaint();
}
}
private static void createAndShowGui() {
final GuiDoubleDraw guiDoubleDraw1 = new GuiDoubleDraw();
final GuiDoubleDraw guiDoubleDraw2 = new GuiDoubleDraw();
JFrame frame = new JFrame("Draw 1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(guiDoubleDraw1);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
JDialog dialog = new JDialog(frame, "Draw 2", ModalityType.MODELESS);
dialog.getContentPane().add(guiDoubleDraw2);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
int timerDelay = 10 * 1000;
new Timer(timerDelay, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
guiDoubleDraw1.setBackgroundImage(guiDoubleDraw2
.getBackgroundImage());
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
您将希望在代码中实现SwingWorker,这将允许您在事件调度线程上和下运行代码。即使您应该在这个场景中找到解决方法,SwingWorker也是使用线程更新UI的正确方法。你会发现,使用各种线程并尝试在没有SwingWorker的情况下更新UI通常会“把你自己弄到一个角落”。我会重构并将其作为一种积极的学习体验。你的应用程序没有锁定,你的
线程正在退出
这里没有任何东西可以通过终止线程来阻止运行
方法的完成,这意味着不再有任何更新
public void run() {
//Sleep thread for 10 seconds to give time to draw on the image
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(
new Runnable() {
@Override
public void run() {
System.out.println("Post...");
//Posts the message to the server chat window
panel.updateCanvas(threadPanel.getImage());
}
});
}
HoverCraftFullOfels是正确的,请改用。它将以固定的时间间隔继续运行。虽然“技术上”没有错,javax.swing.Timer
将更适合手头的问题-定期、计划的更新…IMHO(更不用说更容易了)我计划重构它,以获得使用SwingWorker的一些经验,现在我已经找到了它,但在我有时间了解SwingWorker之前,我必须先展示一些工作代码,但在我尝试向完整程序添加更多功能之前,SwingWorker的重构肯定是我的任务清单上的一部分。事实上,这是一个答案,事实上说明了原始海报代码的问题所在。1+线程正是我用来重现错误的。问题是您可以在主框架中绘制。次帧向主帧发送图像,主帧显示图像。现在,主框架不能被拉入。传输实际上是通过我的流套接字连接来的。我只是以线程睡眠为例来重现我的锁定错误。但是,我检查了你的代码,它似乎解决了这个问题。我现在将更深入地研究它。我想我应该能解决我的问题。也许不使用BuffereImage是我错的地方。谢谢
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Dialog.ModalityType;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class GuiDoubleDraw extends JPanel {
private static final int BI_WIDTH = 500;
private static final int BI_HEIGHT = BI_WIDTH;
public static final Color PEN_COLOR = Color.black;
private BufferedImage backgroundImg = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
public GuiDoubleDraw() {
MyMouseAdapter mouseAdapter = new MyMouseAdapter();
addMouseListener(mouseAdapter);
addMouseMotionListener(mouseAdapter);
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (backgroundImg != null) {
g.drawImage(backgroundImg, 0, 0, this);
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(BI_WIDTH, BI_HEIGHT);
}
public BufferedImage getBackgroundImage() {
BufferedImage copyImg = new BufferedImage(BI_WIDTH, BI_HEIGHT,
BufferedImage.TYPE_INT_ARGB);
Graphics g = copyImg.getGraphics();
g.drawImage(backgroundImg, 0, 0, null);
g.dispose();
return copyImg;
}
public void setBackgroundImage(BufferedImage bImg) {
this.backgroundImg = bImg;
repaint();
}
private class MyMouseAdapter extends MouseAdapter {
Point previousPt = null;
@Override
public void mousePressed(MouseEvent mEvt) {
previousPt = mEvt.getPoint();
}
@Override
public void mouseDragged(MouseEvent mEvt) {
drawPt(mEvt);
}
@Override
public void mouseReleased(MouseEvent mEvt) {
drawPt(mEvt);
}
private void drawPt(MouseEvent mEvt) {
Graphics g = backgroundImg.getGraphics();
Point nextPt = mEvt.getPoint();
g.setColor(PEN_COLOR);
g.drawLine(previousPt.x, previousPt.y, nextPt.x, nextPt.y);
g.dispose();
previousPt = nextPt;
repaint();
}
}
private static void createAndShowGui() {
final GuiDoubleDraw guiDoubleDraw1 = new GuiDoubleDraw();
final GuiDoubleDraw guiDoubleDraw2 = new GuiDoubleDraw();
JFrame frame = new JFrame("Draw 1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(guiDoubleDraw1);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
JDialog dialog = new JDialog(frame, "Draw 2", ModalityType.MODELESS);
dialog.getContentPane().add(guiDoubleDraw2);
dialog.pack();
dialog.setLocationRelativeTo(null);
dialog.setVisible(true);
int timerDelay = 10 * 1000;
new Timer(timerDelay, new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
guiDoubleDraw1.setBackgroundImage(guiDoubleDraw2
.getBackgroundImage());
}
}).start();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}
public void run() {
//Sleep thread for 10 seconds to give time to draw on the image
try {
Thread.sleep(10000);
} catch (InterruptedException ex) {
Logger.getLogger(ThreadTest.class.getName()).log(Level.SEVERE, null, ex);
}
SwingUtilities.invokeLater(
new Runnable() {
@Override
public void run() {
System.out.println("Post...");
//Posts the message to the server chat window
panel.updateCanvas(threadPanel.getImage());
}
});
}