我正在为一个多用户绘图程序项目工作,但我遇到了 GUI 锁定的问题。
除了这个错误,我已经完成了大部分程序,这是一个相当大的程序,所以我试图在一个较小的程序中重现错误。
在这个较小的程序中,我有 2 个 JFrame。它们都可以通过单击并拖动鼠标来绘制。 secondary JFrame 是一个线程, hibernate 10 秒,然后将你绘制的内容发送到另一个框架进行显示。
但是,一旦主框架从辅助框架接收到图像,GUI 就会锁定,无法再绘制主框架。
我目前正在使用 SwingUtilities.invokeLater() 方法进行处理。在寻找答案时,我找到了 SwingWorker 类,但我想先看看是否有简单的解决方案,然后再对我的代码进行大量重写以尝试使其与 SwingWorker 一起工作。
感谢阅读。我的代码如下。另外,这是我第一次在这里发帖。我似乎在格式化代码时遇到了一些问题,所以如果出现错误,我提前道歉。我会尽力修复它。
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;
}
}
-
package gui_thread_test;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.RenderingHints;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
public class ThreadTest extends JFrame implements Runnable
{
private Image canvas;
private Graphics2D g2;
private DrawPanel panel;
private DrawPanel threadPanel;
public ThreadTest(DrawPanel _panel)
{
super("Secondary");
panel = _panel;
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setPreferredSize(new Dimension(500,500));
this.setMinimumSize(new Dimension(500,500));
this.setVisible(true);
threadPanel = new DrawPanel();
this.add(threadPanel);
}
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);
}
@Override
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() {
//Posts the message to the server chat window
panel.updateCanvas(threadPanel.getImage());
}
});
}
}
-
package gui_thread_test;
import java.awt.Dimension;
import javax.swing.JFrame;
public class GUI_Thread_Test {
public static void main(String[] args)
{
JFrame window = new JFrame("Main");
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setPreferredSize(new Dimension(500,500));
window.setMinimumSize(new Dimension(500,500));
DrawPanel draw = new DrawPanel();
window.add(draw);
Thread testThread = new Thread(new ThreadTest(draw));
testThread.start();
window.pack();
window.setVisible(true);
}
}
最佳答案
每 10 秒传输一次,使用 Swing 计时器而不是线程。使用 BufferedImages 保存图纸和传输图纸。
例如:
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();
}
});
}
}
关于java - 多线程锁定 Java Swing GUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15825230/