This is the smallest runnable SSCCE,of my project, that I could implement to show you.
I've read that calling the game logic from the Event Dispacth Thread is a bad practice, how can I separate them, because as you can see update()
and repaint()
are related into loop
and how can I separate code in a pretty way, I'm getting in trouble with this, trying to find out how to do it.
I've posted a similar question regarding and I got an answer,that says to use a Swing Timer,but i have huge task to make and as i read Swing timer
isn't ideal for this scenario.This is the question:
Main class
import javax.swing.JFrame;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
public class Main {
private static final Main mainFrame = new Main();
private final JFrame frame;
private Main() {
frame = new JFrame();
frame.setUndecorated(true);
frame.add(new MyPanel());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public static Main getMainFrameInstance() {
return mainFrame;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
Main.getMainFrameInstance();
}
});
}
}
MyPanel Class
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.image.BufferedImage;
import javax.swing.JPanel;
public class MyPanel extends JPanel implements Runnable,KeyListener,MouseListeners {
private static final long serialVersionUID = 1L;
// thread and loop
private Thread thread;
private boolean running;
private int FPS = 60;
private long targetTime = 1000 / FPS;
private long start;
private long elapsed;
private long wait;
// image
public BufferedImage image;
// foo
private Foo foo;
private Render render = Render.getRenderManagerInstance();
public MyPanel() {
setPreferredSize(new Dimension(700, 700));
setFocusable(true);
requestFocus();
}
public void addNotify() {
super.addNotify();
if (thread == null) {
addKeyListeners(this);
addMouseListener(this);
thread = new Thread(this);
thread.start();
}
}
private void initGraphic() {
image = new BufferedImage(700, 700, BufferedImage.TYPE_INT_RGB);
foo = new Foo();
running = true;
}
public void run() {
initGraphic();
// loop
while (running) {
start = System.nanoTime();
foo.update();
repaint();
elapsed = System.nanoTime() - start;
wait = (targetTime - elapsed / 1000000) - 8;
if (wait <= 0)
wait = 6;
try {
Thread.sleep(wait);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
graphics = image.getGraphics();
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
((Graphics2D) graphics).setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
render.setRenderState((Graphics2D) graphics);
graphic.drawImage(image, 0, 0, this);
// clear graphics resources after use them
graphic2D.dispose();
}
public void keyPressed(KeyEvent keyEvent) {
//code not considerable
}
public void keyReleased(KeyEvent keyEvent) {
//code not considerable
}
public void mousePressed(MouseEvent mouseEvent) {
//code not considerable
}
public void mouseReleased(MouseEvent mouseEvent) {
//code not considerable
}
}
This is how it can look like. You'll need to call the following code somewhere in EDT or through Swing Timer. I'm assuming here that your "huge" task will need to update a text field, but it can be any other UI control as well. All of that, just to demonstrate an idea. Do not treat it as a tested code.
//javax.swing.JTextField jfield; The field that needs to be updated. Take it from your Panel
String text = ""; // just a place holder
Object params [] = new Object []{jfield, text};
HugeTaskRunner ht = new HugeTaskRunner(params, new CallBack());
HugeTaskRunner is derived from AbstractTaskRunner, which looks like follows:
public abstract class AbstractTaskRunner extends Thread {
CallBack callBack = null;
Object [] params = new Object[0];
public AbstractTaskRunner (Object [] params, CallBack callBack) {
this.params = params;
this.callBack = callBack;
}
public abstract void doTask ();
@Override
public void run() {
doTask();
if (callBack != null) {
callBack.doCall(new Object[]{"DONE"});
}
}
}
HugeTaskRunner:
public class HugeTaskRunner extends AbstractTaskRunner {
public HugeTaskRunner(Object[] params, CallBack callBack) {
super(params, callBack);
// TODO Auto-generated constructor stub
}
@Override
public void doTask() {
// HERE YOU'LL HAVE TO DO SOME HUGE TASK ACTIONS
// THEN YOU'LL NEED TO CALL callBack.doCall(params) to update GUI
String newText = "Image #1 has been loaded";
params[params.length -1] = newText; // assuming that the last param is for updated text
callBack.doCall(params);
}
}
CallBack class:
public class CallBack {
public void doCall (Object [] params) {
javax.swing.SwingUtilities.invokeLater(new GUIUpdater(params, null));
}
}
GUIUpdater class:
public class GUIUpdater extends AbstractTaskRunner {
public GUIUpdater(Object[] params, CallBack callBack) {
super(params, callBack);
}
@Override
public void doTask() {
// UPDATE YOUR GUI HERE TAKING Swing UI objects from params, e.g.
if (params.length == 1 && params[0].equals("DONE")) {
// HUGE TASK IS COMPLETED, DO SOMETHING IF YOU NEED TO
}
else if (params.length == 2) { // It's a request to update GUI
javax.swing.JTextField txt = (javax.swing.JTextField) this.params[0];
txt.setText((String)this.params[1]);
}
else {
// UNKNOWN REQUEST
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With