I'm working on a project for a multiple user paint program and I have run into a problem with my GUI locking up.
I have most of the program done except for this error, it is a rather large program so I tried to reproduce the error in a smaller program.
In this smaller program, I have 2 JFrames. Both of them can be drawn in by clicking and dragging the mouse. The secondary JFrame is a thread that sleeps for 10 seconds and then sends what you have drawn to the other frame to be displayed.
However, once the main frame has received the image from the secondary frame, the GUI locks up and the main frame can no longer be drawn in.
I'm currently using the SwingUtilities.invokeLater() method to work with. While looking for answers, I found the SwingWorker class, but I wanted to see if there was a simple solution before I undertook a large rewrite of my code to try to make it work with SwingWorker.
Thanks for reading. My code is below. Also, this is my first time posting here. I seemed to be having some trouble formatting the code, so I apologize in advance if it comes out wrong. I will do my best to fix it.
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);
}
}
Use a Swing Timer rather than a Thread for your every 10 second transfer. Use BufferedImages to hold the drawings and to transfer the drawings.
For example:
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();
}
});
}
}