Changing background image in JGame - java

In JGame, the method setBGImage() is supposed to change the background image. This works when I'm setting the background image for the first time at the start of the initialization. However, when I call the same method later to change the background image, it seems to do nothing. What am I doing wrong?
Here's some example code to show you what I mean:
import jgame.*;
import jgame.platform.*;
public class Test extends JGEngine{
public static void main(String[] args) {
new Test();
}
public Test(){
super();
initEngine(640,480);
}
public void initCanvas(){
setCanvasSettings(10,6,64,80,null,JGColor.white,null);
}
public void initGame(){
setFrameRate(35,2);
defineMedia("media.tbl");
doTestBackground();
}
/* Demonstrates the bug */
void doTestBackground(){
new Thread(new Runnable(){
public void run(){
setBGImage("bg1");
/* If it's put here, then it works perfectly:
setBGImage("bg2"); */
try{
Thread.sleep(2000);
}
catch(Exception e){}
/* If it's put here it doesn't work!
The background SHOULD change here but it doesn't */
setBGImage("bg2");
}
}).start();
}
}

If you still want some answer. Here it is:
http://installsteps.blogspot.com/2010/10/jgame-java-game-engine.html

FYI, this setBGImage behaviour is a bug that was fixed in version 3.4. Since 3.4, setBGImage correctly updates the screen.

Perhaps you are running into problems with using the wrong thread? Generally, the AWT thread is used to change components (in the Swing framework).
Try using SwingUtilities.invokeLater(new Runnable() { public void run() { setBGImage("things");} } );

Related

JFrame ActionPerformed on a button takes full time until it finishes the code

It's my first time making GUI on java, and I have a small issue that is pretty annoying.
My code looks something like this.
private void RunButtonActionPerformed(java.awt.event.ActionEvent evt){
richText.append("Starting...");
try{ something happens here }
richText.append("Done...");
}
The problem is that when I click run button, it waits until it finishes the task and print "Starting..." and "Done..." at the same time. How do I make it print "Starting" first before and print "Done" after?
This code is executed in EDT, so any UI changes (richText.append in your case) will be repainted after it. You should execute your heavy task in new thread.
private void RunButtonActionPerformed(java.awt.event.ActionEvent evt){
richText.append("Starting...");
new Thread() {
public void run() {
try{ something happens here }
SwingUtilities.invokeLater(new Runnable() {
richText.append("Done...");
});
}
}.start();
}
Or use SwingWorker to get extra functionality such as reporting progress of task completion
I followed the tutorial for SwingWorker as suggested on the comment, and it worked! It looks something like this.
`private class Worker extends SwingWorker<Void, Void>{
protected Void doInBackground() throws Exception{
try{ things happen here }
return null;
}
#Override
protected void done(){
try{ get (); } catch (){}
}
}
And to call this, RunButtonActionPerformed just needs new Worker().execute().

JavaFX 8 Screen resolution doesn't update when program is running

For some reason when I print my laptop's resolution width using Screen.getPrimary().getVisualBounds().getWidth()); I get the right result of 1920. But if I print the resolution width, change the resolution to 1680x1050 in Windows Settings, ask the thread to wait a minute, and print the resolution width again using the same code, I get 1920 instead of 1680! However, if I stop the project, set the resolution to 1680x1050, then compile and run the project, it does print 1680. In other words it seems that the project doesn't update the resolution if I change it while the project is running.
Below is some JavaFX code to illustrate what I mean. If I run the code below, watch it print 1920, change the resolution real quick, wait until the thread is done sleeping, then as described before it will still print 1920 instead of the new resolution width.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
System.out.println(Screen.getPrimary().getVisualBounds().getWidth());
Thread.sleep(60000);
System.out.println(Screen.getPrimary().getVisualBounds().getWidth());
}
public static void main(String[] args) { launch(args); }
}
The problem has to do with polling the screen resolution on the same thread. If a new thread is created, told to sleep while the user changes the screen resolution in Windows Settings, and then told to print the screen resolution the screen, the resolution will reflect the updated resolution.
If the user ran the following and changed the resolution while the thread is asleep then the correct updated resolution would print to screen, unlike the code in the original question.
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
System.out.println(Screen.getPrimary().getVisualBounds().getWidth());
new Thread(){
public void run() {
try{
this.sleep(30000);
} catch (InterruptedException e) {
// ignore
}
System.out.println(Screen.getPrimary().getVisualBounds().getWidth());
}
}.start();
}
public static void main(String[] args) { launch(args); }
}
Another solution that also reflects an updated screen resolution is to use AWT. The following would print the correct updated resolution,
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
System.out.println(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
Thread.sleep(30000);
System.out.println(java.awt.Toolkit.getDefaultToolkit().getScreenSize());
}
public static void main(String[] args) { launch(args); }
}

Java - Swing GUI doesn't load

I've been trying to learn java for a few weeks now, and I'm working on a pretty simple autoclicker.
The clicker itself works, but my problem is that my GUI never shows up.
The GUI runs just fine when I run the GUI file itself, but when I'm trying to run it from my main program (different file) it never shows. The clicker works fine all the time though. I'm sure the problem is something really simple that I have simply missed, but this is now my 4th day without any clue on what might be wrong with it, so decided I'd ask here.
Beware - the code is really messy atm, because I've been trying pretty much everything possible to get it working.
This is the code in the main program trying to run the GUI.
package autoclicker;
import java.awt.AWTException;
/**
* The main program for the autoclicker.
*/
public class AutoClicker {
public static void main(String[] args) throws AWTException {
Click click = new Click(true);
click.clicker();
try {
Swingerinos sw = new Swingerinos();
sw.initialize();
}
catch (AWTException e) { e. printStackTrace(); System.exit(-1); }
}
}
And this is the whole GUI file.
package autoclicker;
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
public class Swingerinos extends Click implements WindowListener,ActionListener {
private int numClicks = 0;
TextField text;
private JFrame frame;
/**
* #wbp.nonvisual location=181,19
*/
private final JLabel lblAutoclicker = new JLabel("AutoClicker");
/**
* Launch the application.
*/
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Swingerinos window = new Swingerinos();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Swingerinos() throws AWTException {
initialize();
}
/**
* Initialize the contents of the frame.
*/
public void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 109);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel panel = new JPanel();
frame.getContentPane().add(panel, BorderLayout.WEST);
JButton btnNewButton = new JButton("Toggle On / Off");
text = new TextField(20);
text.setLocation(100, 100);
btnNewButton.addActionListener( this);
btnNewButton.setToolTipText("Toggles the autoclicker on / off.");
panel.add(btnNewButton);
panel.add(text);
frame.setVisible(true);
}
public void actionPerformed(ActionEvent e) {
toggle();
numClicks++;
text.setText(""+numClicks);
}
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
public void windowClosed(WindowEvent e) {}
}
I know the GUI file is really messy (there's 2x initialize(), one in the main program and one in the GUI file, and lots of other stuff, but I'm just too confused as for what to do now.
EDIT: I added the whole main program code, also this is the code for the autoclicker.
package autoclicker;
import java.awt.*;
import java.awt.event.InputEvent;
public class Click {
private boolean active;
private Robot robot;
public Click(boolean active, Robot robot) {
this.active = active;
this.robot = robot;
}
public Click() throws AWTException {
this(false, new Robot());
}
public Click(boolean active) throws AWTException {
this(active, new Robot());
}
//TODO: add click.toggle() to somewhere and control da clicker
public void toggle() {
active = !active;
}
public void clicker() {
while (active) {
robot.mousePress(InputEvent.BUTTON1_DOWN_MASK);
robot.mouseRelease(InputEvent.BUTTON1_DOWN_MASK);
robot.setAutoDelay(10000);
}
}
}
Expanding JB Nizet's comment(s) into an answer.
The immediate cause:
When the JVM calls your code, it is run on the main thread. It calls main(String[]), as you know. You posted two main methods, only one of which is relevant to your nothing-is-happening problem: AutoClick#main(String[]). Let's go through it:
Click click = new Click(true);
click.clicker();
This first of the above two lines obviously calls the constructor of Click, which sets the active variable to true. So far so good. The second line is much more interesting. It calls Click#clicker(). Let's look at that method:
public void clicker() {
while (active) {
// <snip>
}
}
This method is the problem. Since you haven't started any other threads, the main thread is the only one you have at that moment, the only thread on which you can execute code. When this loop is executed it only finishes when the active variable is set to false. As long as it is true, it will keep looping. This means that Click#clicker() only returns if active is set to false. But, you never do that in the loop itself, meaning you need a thread different from the thread executing the loop to change active. So, how many threads do we have? 1, the main thread. See the problem? Because the loop never ends, the main thread never reaches the statements in the main method after click.clicker().
Simple solution
You could just set a fixed number of iterations:
public void clicker() {
int i = 0;
while (i < 100) { // iterate 100 times
// <snip>
++i;
}
}
Or using a for-loop (recommended):
public void clicker() {
for (int i = 0; i < 100; ++i) {
// <snip>
}
}
This eliminates the need for the active variable and hence the need for another thread.
A somewhat more complicated solution
If you really want the active variable, you'll need to have multiple threads. This is conveniently known as "multithreading"1, a very complicated topic. Luckily, we only need a bit of it, so it is only a bit complicated.
Don't just call the method Click#clicker() like you would normally. This creates your current problem. You'll need a worker thread, which can call the method. The easiest way to create a new thread is to call the constructor of the class Thread which takes a single argument of type Runnable. Like this:
Thread worker = new Thread(new Runnable() {
public void run() {
click.clicker();
}
});
This returns relatively quickly and leaves the Click#clicker() method running on another thread. Your main thread is now free to execute the other statements and even call click.toggle() after a while.
As JB Nizet pointed out, there are some other problems with your code. For example, Swingerinos shouldn't extend Click, but have an instance variable of type Click (http://en.wikipedia.org/wiki/Composition_over_inheritance) (as JB Nizet pointed out). Also, you shouldn't need to implement WindowListener to just call System.exit() when the window closes if you already call frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);. To get all kinds of feedback (not limited to but including this kind of issues, style and design) on working code2 I highly recommend the StackExchange website codereview.stackexchange.com
1: I by no means consider myself even remotely an expert on threading, so I won't go into it. If you want to know more about it, google it - there's lots of texts on multithreading - or ask another question - if you have a specific problem.
2: this is important: broken code is off-topic on Code Review.

UI thread can not start after IDE changed

I changed my IDE from Eclipse to IntelliJ IDEA. The new one started complaining about my code.
public class Controller {
private OknoGlowne frame;
private MenuListener menuListen = new MenuListener(this);
private TabListener tabListener = new TabListener(this);
public OknoGlowne getFrame() {
return frame;
}
public Controller(){
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
frame = new OknoGlowne();
frame.setVisible(true); //error
frame.addMenuListener(menuListen);
frame.addTabListener(tabListener);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
}
So I commented this line. And add new line to constructor of UI frame.
public OknoGlowne() {
jPanel.setVisible(true);
}
App start but UI doesn't show any more. IDEA create frame in different way than Eclispe. I have to switch.
Main
public class Runner {
public static void main(String[] args) {
new Controller();
}
}
This doesn't really have anything to do with your IDEs. I bet if you ran it 100 times in eclipse, or from the command line, you'd get different results depending on how busy your system is.
The reason you aren't seeing the JFrame pop up is because you're using invokeLater() instead of invokeAndWait().
The invokeLater() method immediately returns, at which point you're in a race condition: will the event thread display the EDT first, or will the main thread exit first? If the main thread exits first, then your program will exit before any windows are shown.
To prevent this, you have to use invokeAndWait() instead of invokeLater().

Unable to update GUI while sending file

I am sending a file over network using sockets. The file is received properly without any problem. But now I am using a JProgressBar to show percentage of file sent. My problem is that even when I update GUI in a separate thread, the progress bar is updated only when file is completely sent. I also tried adjusting the priority of main thread to Thread.MIN_PRIORITY but the problem still persisted.
The complete code is long so I am not posting it (I will post if someone asks). The short code for sending file and updating progress bar is
final double temp=(done/fileSize)*100; // percentage of file sent
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
try
{
jpb.setString("Completed : "+temp+" %");
jpb.setValue((int)temp); // this is executed only when 100%
}
catch(Exception e)
{
e.printStackTrace();
}
}
});
System.out.println(temp); // only this and
bos.write(b,0,read); // this statement is executed
Problem lies in below line:
final double temp=(done/fileSize)*100; // percentage of file sent
If done and fileSize are both not double then result of done/fileSize is 0.0.
Make them double (at least one of them) to keep the decimal part of the division.
Here is a implementation that I talked about.
It's not the best design as I did it quick and dirty but this way the file transfer code is not dependent on the UI.
public class FileTransfer implements Runnable
{
double transferPercent = 0.0;
double getTransferPercent(){ return transferPercent; }
#Override
public void run()
{
while(transferingFile)
{
// Write data
// Update transferPercent
}
}
}
public class UIClass extends TimerTask
{
private FileTransfer fileTransfer;
public void createUI()
{
TimerTask myClass = this;
JButton b = new JButton("Transfer");
b.addMouseListener(new MouseAdapter()
{
#Override
public void mouseClicked(MouseEvent e)
{
fileTransfer.start();
Timer t = new Timer();
t.scheduleAtFixedRate(myClass, 0.0, 20);
}
});
}
// Update the UI here!
#Override
public void run()
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
jpb.setValue(fileTransfer.getTransferPercent());
}
});
}
}
I'd probably design this differently. I'd make the network code independent of the UI and have it just update a variable on percentage sent.
The UI would then poll this number with a timer to update the progress bar.
But your code should work. Try adding an #Override on your run function. Maybe SwingUltities.invokeLater is calling Runnable's run function instead of your own.

Categories

Resources