Reputation: 319
I am working on a relatively complicated java project that involves a GUI as well as communicating with two different arduinos across a network.
I have a rotary encoder on one of the arduinos that will tell the java program how far a wheel has turned. I have a thread that deals with retrieving the data from the arduino and rotating the image.
The issue arises when I try to rotate the rotary encoder quickly. The image will flash white as seen here.
I use the following code to rotate the image:
public static void setimageto(int degree){
stageRotation.stageangel = degree;
try {
BufferedImage localBufferedImage = ImageIO.read(new File("CircleStagePNG.png"));
JPanel rotatepanel = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
if (g != null) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
g2.drawImage(localBufferedImage, 0, 0, null);
}
}
};
stageRotation.pnPanel3.removeAll();
rotatepanel.setBackground(stageRotation.color);
stageRotation.pnPanel3.add(rotatepanel);
stageRotation.pnPanel0.setBackground(stageRotation.color);
stageRotation.pnPanel0.updateUI();
} catch (IOException localIOException) {
}
}
I have also uploaded the full code to this link
the main java file is called stageRotation.java while javatest.java should be an example of what it should look like.
Any explanation or solution would be helpful as would any suggestions to make this question more user friendly.
[EDIT] This is my main class and constructor with a lot of code removed. I attempted to shorten it down the best I could but may have left some unnecessary items and this is also why it may not run correctly. Thanks again for any assistance
import javax.swing.UIManager.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.net.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.net.ServerSocket;
import javax.swing.filechooser.*;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.TimeUnit;
public class stageRotation extends JPanel {
static stageRotation thestageRotation;
public static JFrame mainFrame;
public static JPanel pnPanel0;
public static JPanel pnPanel1;
public static JPanel pnPanel3;
public static Object rotationobject;
public static Object[] queadd;
public static Thread motorcontrollerthread;
public static Thread sensorcontrollerthread;
public static Thread rotationthread = new Thread();
public static Thread inputthread = new Thread();
public static Boolean endinsight = false;
public static Boolean rotaterflag = true;
public static Boolean imagechange = false;
public static volatile Boolean sensorinput = true;
public static volatile Boolean motorinput = true;
public static Color color = Color.WHITE;
public static PrintWriter motorsocketout;
public static PrintWriter sensorsocketout;
public static Socket echoSocket;
public static BufferedImage localBufferedImage;
public static void main(String[] args) {
//Makes the whole program look a lot better but there are some inexcusable errors that need to be worked out
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, you can set the GUI to another look and feel.
}
thestageRotation = new stageRotation();
}
public stageRotation() {
/*while(motorconnected == 0 || sensorconnected == 0) {
if (motorconnected == -1 || sensorconnected == -1) {
System.exit(0);
}
}*/
//frame definition and layoutmanager definition
JFrame mainFrame = new JFrame("Que thingy");
pnPanel0 = new JPanel();
GridBagLayout localGridBagLayout1 = new GridBagLayout();
GridBagConstraints localGridBagConstraints1 = new GridBagConstraints();
pnPanel0.setLayout(localGridBagLayout1);
pnPanel3 = new JPanel();
pnPanel3.setLayout(localGridBagLayout1);
// create image for display
try {
final BufferedImage localBufferedImage = ImageIO.read(new File("CircleStagePNG.png"));
pnPanel1 = new JPanel() {
public Dimension getPreferredSize() {
return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
}
protected void paintComponent(Graphics paramAnonymousGraphics) {
super.paintComponent(paramAnonymousGraphics);
Graphics2D localGraphics2D = (Graphics2D)paramAnonymousGraphics;
localGraphics2D.rotate(0.0D, localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
localGraphics2D.drawImage(localBufferedImage, 0, 0, null);
}
};
//set up graphical properties for image
GridBagLayout localGridBagLayout2 = new GridBagLayout();
pnPanel1.setBackground(color);
pnPanel3.add(pnPanel1);
pnPanel3.setLayout(localGridBagLayout2);
localGridBagConstraints1.gridx = 0;
localGridBagConstraints1.gridy = 0;
localGridBagConstraints1.gridwidth = 1;
localGridBagConstraints1.gridheight = 2;
localGridBagConstraints1.fill = GridBagConstraints.BOTH;
localGridBagConstraints1.weightx = 1;
localGridBagConstraints1.weighty = 1;
localGridBagConstraints1.anchor = GridBagConstraints.NORTH;
localGridBagLayout1.setConstraints(pnPanel3, localGridBagConstraints1);
pnPanel3.setBackground(Color.WHITE);
pnPanel0.add(pnPanel3);
mainFrame.setContentPane(pnPanel0);
mainFrame.pack();
mainFrame.setBackground(Color.WHITE);
mainFrame.setVisible(true);
tbJquetable.requestFocus();
} catch (IOException localIOException) {}
}
//changes background will sometimes report nullpointerexception error however has no effect on code
public static void setimageto(int degree){
stageRotation.stageangel = degree;
try {
localBufferedImage = ImageIO.read(new File("CircleStagePNG.png"));
pnPanel1 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
g2.drawImage(localBufferedImage, 0, 0, null);
}
};
stageRotation.pnPanel3.removeAll();
pnPanel1.setBackground(stageRotation.color);
stageRotation.pnPanel3.add(pnPanel1);
stageRotation.pnPanel0.setBackground(stageRotation.color);
stageRotation.pnPanel0.updateUI();
} catch (IOException localIOException) {
}
}
}
[EDIT2]
While the following code does not flicker, the image will hang at points. I was unable to reproduce the flickering with url imagaes and only with local files; however, I believe the image hanging and flickering are the same problem.
import javax.swing.UIManager.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
import java.net.*;
import java.io.*;
import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.net.ServerSocket;
import javax.swing.filechooser.*;
import java.rmi.RemoteException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.concurrent.TimeUnit;
public class stageRotation extends JPanel {
static stageRotation thestageRotation;
public static JFrame mainFrame;
public static JPanel pnPanel0;
public static JPanel pnPanel1;
public static JPanel pnPanel3;
public static Object rotationobject;
public static Object[] queadd;
public static Thread motorcontrollerthread;
public static Thread sensorcontrollerthread;
public static Thread rotationthread = new Thread();
public static Thread inputthread = new Thread();
public static Boolean endinsight = false;
public static Boolean rotaterflag = true;
public static Boolean imagechange = false;
public static volatile Boolean sensorinput = true;
public static volatile Boolean motorinput = true;
public static Color color = Color.WHITE;
public static PrintWriter motorsocketout;
public static PrintWriter sensorsocketout;
public static Socket echoSocket;
public static BufferedImage localBufferedImage;
public static URL url;
public static void main(String[] args) {
//Makes the whole program look a lot better but there are some inexcusable errors that need to be worked out
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, you can set the GUI to another look and feel.
}
thestageRotation = new stageRotation();
for (int i = 0; i < 360; i++){
setimageto(i);
}
}
public stageRotation() {
try{
url = new URL("https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/CIRCLE_LINES.svg/220px-CIRCLE_LINES.svg.png");
} catch(MalformedURLException a){}
JFrame mainFrame = new JFrame("Que thingy");
pnPanel0 = new JPanel();
GridBagLayout localGridBagLayout1 = new GridBagLayout();
GridBagConstraints localGridBagConstraints1 = new GridBagConstraints();
pnPanel0.setLayout(localGridBagLayout1);
pnPanel3 = new JPanel();
pnPanel3.setLayout(localGridBagLayout1);
// create image for display
try {
final BufferedImage localBufferedImage = ImageIO.read(url);
pnPanel1 = new JPanel() {
public Dimension getPreferredSize() {
return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
}
protected void paintComponent(Graphics paramAnonymousGraphics) {
super.paintComponent(paramAnonymousGraphics);
Graphics2D localGraphics2D = (Graphics2D)paramAnonymousGraphics;
localGraphics2D.rotate(0.0D, localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
localGraphics2D.drawImage(localBufferedImage, 0, 0, null);
}
};
//set up graphical properties for image
GridBagLayout localGridBagLayout2 = new GridBagLayout();
pnPanel1.setBackground(color);
pnPanel3.add(pnPanel1);
pnPanel3.setLayout(localGridBagLayout2);
localGridBagConstraints1.gridx = 0;
localGridBagConstraints1.gridy = 0;
localGridBagConstraints1.gridwidth = 1;
localGridBagConstraints1.gridheight = 2;
localGridBagConstraints1.fill = GridBagConstraints.BOTH;
localGridBagConstraints1.weightx = 1;
localGridBagConstraints1.weighty = 1;
localGridBagConstraints1.anchor = GridBagConstraints.NORTH;
localGridBagLayout1.setConstraints(pnPanel3, localGridBagConstraints1);
pnPanel3.setBackground(Color.WHITE);
pnPanel0.add(pnPanel3);
mainFrame.setExtendedState(6);
WindowListener exitListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
System.out.println("EXIT");
stageRotation.motorsocketout.println("EXIT");
sensorsocketout.println("EXIT");
sensorinput = false;
motorinput = false;
mainFrame.setVisible(false);
mainFrame.dispose();
System.exit(0);
} catch (NullPointerException p){
System.exit(0);
}
}
};
mainFrame.addWindowListener(exitListener);
mainFrame.setContentPane(pnPanel0);
mainFrame.pack();
mainFrame.setBackground(Color.WHITE);
mainFrame.setVisible(true);
} catch (IOException localIOException) {}
}
//changes background will sometimes report nullpointerexception error however has no effect on code
public static void setimageto(int degree){
try {
localBufferedImage = ImageIO.read(url);
pnPanel1 = new JPanel() {
@Override
public Dimension getPreferredSize() {
return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
g2.drawImage(localBufferedImage, 0, 0, null);
}
};
stageRotation.pnPanel3.removeAll();
pnPanel1.setBackground(stageRotation.color);
stageRotation.pnPanel3.add(pnPanel1);
stageRotation.pnPanel0.setBackground(stageRotation.color);
stageRotation.pnPanel0.updateUI();
} catch (IOException localIOException) {
}
}
}
Upvotes: 2
Views: 261
Reputation: 168845
OK.. the MCVE above demonstrates a variety of misunderstandings.
Timer
. The ActionListener
(used in the constructor of the timer) should then perform a single frame of the animation. Usually using a loop to animate will block the Event Dispatch Thread, with the end result that the 'animation' will only appear as the first frame - direct to switching to the last frame.There are a number of other improvements that might be made to the code, but I stopped there since it seems to address the main problem.
Here is code that implements the above advice:
import javax.swing.UIManager.*;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.net.*;
import java.io.*;
import java.awt.image.BufferedImage;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
public class stageRotation extends JPanel {
private static stageRotation thestageRotation;
public static JPanel pnPanel0;
public static PnPanel1 pnPanel1;
public static JPanel pnPanel3;
public static volatile Boolean sensorinput = true;
public static volatile Boolean motorinput = true;
public static Color color = Color.WHITE;
public static PrintWriter motorsocketout;
public static PrintWriter sensorsocketout;
public static BufferedImage localBufferedImage;
public static URL url;
public static void main(String[] args) {
//Makes the whole program look a lot better but there are some inexcusable errors that need to be worked out
try {
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(info.getName())) {
UIManager.setLookAndFeel(info.getClassName());
break;
}
}
} catch (Exception e) {
// If Nimbus is not available, you can set the GUI to another look and feel.
}
setThestageRotation(new stageRotation());
ActionListener actionListener = new ActionListener() {
int degree = 0;
@Override
public void actionPerformed(ActionEvent e) {
if (degree<360) {
degree++;
setimageto(degree);
}
}
};
Timer timer = new Timer(10,actionListener);
timer.start();
}
/**
* @param aThestageRotation the thestageRotation to set
*/
public static void setThestageRotation(stageRotation aThestageRotation) {
thestageRotation = aThestageRotation;
}
public stageRotation() {
try {
url = new URL("https://upload.wikimedia.org/wikipedia/commons/thumb/0/06/CIRCLE_LINES.svg/220px-CIRCLE_LINES.svg.png");
localBufferedImage = ImageIO.read(url);
} catch (Exception ex) {
Logger.getLogger(stageRotation.class.getName()).log(Level.SEVERE, null, ex);
}
JFrame mainFrame = new JFrame("Que thingy");
pnPanel0 = new JPanel();
GridBagLayout localGridBagLayout1 = new GridBagLayout();
GridBagConstraints localGridBagConstraints1 = new GridBagConstraints();
pnPanel0.setLayout(localGridBagLayout1);
pnPanel3 = new JPanel();
pnPanel3.setLayout(localGridBagLayout1);
pnPanel1 = new PnPanel1();
pnPanel3.add(pnPanel1);
// create image for display
try {
final BufferedImage localBufferedImage = ImageIO.read(url);
//set up graphical properties for image
GridBagLayout localGridBagLayout2 = new GridBagLayout();
pnPanel1.setBackground(color);
pnPanel3.setLayout(localGridBagLayout2);
localGridBagConstraints1.gridx = 0;
localGridBagConstraints1.gridy = 0;
localGridBagConstraints1.gridwidth = 1;
localGridBagConstraints1.gridheight = 2;
localGridBagConstraints1.fill = GridBagConstraints.BOTH;
localGridBagConstraints1.weightx = 1;
localGridBagConstraints1.weighty = 1;
localGridBagConstraints1.anchor = GridBagConstraints.NORTH;
localGridBagLayout1.setConstraints(pnPanel3, localGridBagConstraints1);
pnPanel3.setBackground(Color.WHITE);
pnPanel0.add(pnPanel3);
WindowListener exitListener = new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
try {
System.out.println("EXIT");
stageRotation.motorsocketout.println("EXIT");
sensorsocketout.println("EXIT");
sensorinput = false;
motorinput = false;
mainFrame.setVisible(false);
mainFrame.dispose();
System.exit(0);
} catch (NullPointerException p) {
System.exit(0);
}
}
};
mainFrame.addWindowListener(exitListener);
mainFrame.setContentPane(pnPanel0);
mainFrame.pack();
mainFrame.setBackground(Color.WHITE);
mainFrame.setVisible(true);
} catch (IOException localIOException) {
}
}
//changes background will sometimes report nullpointerexception error however has no effect on code
public static void setimageto(int degree) {
pnPanel1.setDegree(degree);
pnPanel1.repaint();
}
class PnPanel1 extends JPanel {
int degree;
@Override
public Dimension getPreferredSize() {
return new Dimension(localBufferedImage.getWidth(), localBufferedImage.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.rotate(Math.toRadians(degree), localBufferedImage.getWidth() / 2, localBufferedImage.getHeight() / 2);
g2.drawImage(localBufferedImage, 0, 0, this);
}
public void setDegree(int degree) {
this.degree = degree;
}
};
}
Upvotes: 2
Reputation: 499
I think issue is for every degree change, you are clearing stageRotation and re-setting background.
You should call all init code only once and just redraw image only when a change in degree is required.
Upvotes: 1