• Post Reply Bookmark Topic Watch Topic
  • New Topic

How to update an image using JLabel without creating a new window.

 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Last semester I was introduced to GUI with JFrame. I wanted to learn more, so I started my own project to try and experiment with what I knew.

(A little background)
I play Magic The Gathering and I was interested in Planechase, but I didn't want to spend the money to get the cards. I then had the idea to make my own "app" on my computer to "act" as if the cards were really in play. This then became my project. I've got a working "Alpha" build, but I want to expand on it and I'm stuck as to how. I did some research, but either it didn't quite pertain to what I was doing or it was something I had never dealt with and got lost as soon as I start it haha. Basically in a nut shell my first "upgrade/fix" for this is that I wanted it to update the JLable image in the same window instead of creating a new one as it does now. This is what I have so far, but I'm still a little iffy on how it all come together:


I hoping this will condense itself when I post it as it isn't in the preview and it's a lot of code in my opinion.

Some of this is redundant such as the two methods. One is called "generator" and the other is called "randomGenerator" The random one works, but the generator doesn't yet. The difference being that the "randomGenerator" randomly displays a picture while the "generator" is a future endeavor that will go in order from first to finish and then repeat as it displays the pictures. The main issue I'd want to get solved first is being able to display in one window as I think that may clear up the other issue (or at least make it easier).

Thanks for any help given!

- Alex Petsche
 
Supun Lakshan Dissanayake
Ranch Hand
Posts: 135
Android Java PHP
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
there are two methods in JLabel which are inherited from javax.swing.JComponent to do it as far as i know.



try one of those methods.
I think it will work.

And use switch instead of if/else if in your code. i makes more clearly.
 
Campbell Ritchie
Marshal
Posts: 52516
118
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
My, there is some bad design there. And switch will only improve it slightly.
Avoid addActionListener(this) like the plague. It is poor, non‑object‑oriented design. You might not notice when you only have one button, but it becomes a right mess when you have many.
Avoid all those if statements. Again, poor, non‑object‑oriented design. It is also full of repeated code, and error‑prone. What happens if you get one of the numbers wrong? You can put all your images into an array and select from the array.
Don't use Math#random(). Use a java.util.Random object. It has methods which do exactly what you want.

Will repaint or revalidate be necessary at all? You should get all your setting up of the GUI, sizing, adding Images, everything else, etc., finished before you call setVisible. Which I think you are doing already.
Why are you calling setBounds on a button or a label? Why are you not using a specific layout?

Moving discussion to our GUIs forum.
 
m Korbel
Ranch Hand
Posts: 174
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
- use CardLayout

- everything else is simulation of CardLayout
 
Campbell Ritchie
Marshal
Posts: 52516
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Card Layout? Now you come to mention it, that is obviously the answer.
 
m Korbel
Ranch Hand
Posts: 174
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Card Layout? Now you come to mention it, that is obviously the answer.

- yes

- reason/better to call Icon/ImageIcon.getImage().flush(); instead of CardLayout, if yes then this comment make me some sence
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think I understand that my current "system" isn't set up to use repaint properly. I'll try using switches, but don't they work roughly the same as and else if? I may be wrong, but I thought the way I set up Math.random in the randomGenerator method prevented any errors. Also I think I see how the array of images is probably a better idea. I'll see if I can get it working and go from there. I am calling setVisible after I've set up the window and everything I believe. I chose to use setBounds because I understood how it worked for a layout. I have tried borderLayout, but I didn't think it worked the way I was trying to use it. I'll give it another look and see if I can't get it to work. Thanks for the help so far!

Just a couple questions first though.

My teacher showed us to just use "this" in actionListener, but I wasn't sure what the "this" is referencing. The error when I remove it makes me think it needs an event actionLisntener, but I'm not sure how to represent that other than putting "this".

Also would using if statements in my action performed method to check what instance of button was triggered be a "rough workaround" if I did have multiple buttons?
EX:


Lastly I assume "cardLayout" is another layout I can use instead of setBounds. I'll give it a shot and see how it works.

I think because of how it all displayed I'm going to try and remove everything I currently don't need for this to work, so that I'm not taking up 10 pages when I post code again. Thanks for all the help!
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I ran into a problem when I tried to create an array of all the JLable images. This is what I tried: Both give me an error saying that there is an "Exception in thread "main" java.lang.NullPointerException" amd it occurs at there two points in the above code: I'm not sure what is wrong with the code that would cause it to have a nullPointerException. From my understanding I created a JLabel that represents an image and then I placed that into the array, but it doesn't seem to like that. :/ An explanation as to why would be awesome! Thanks for the help!

I did a little research and found out (at least one way of doing it) that I can use "array[0].setIcon". I'm still running into a problem though where it can't find the file. For some reason it's looking for "Thumbs.db" This is the full error it give me:

java.io.FileNotFoundException: C:\Users\Alex\Desktop\Projects\Planechase_App\Petsche.Alex.Planechase_App\build\classes\petsche\alex\planechase_app\Thumbs.db (Access is denied)
at java.io.FileOutputStream.open(Native Method)
at java.io.FileOutputStream.<init>(FileOutputStream.java:212)
at java.io.FileOutputStream.<init>(FileOutputStream.java:165)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.copyFile(BuildArtifactMapperImpl.java:461)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.copyRecursively(BuildArtifactMapperImpl.java:548)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.copyRecursively(BuildArtifactMapperImpl.java:541)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.copyRecursively(BuildArtifactMapperImpl.java:541)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.copyRecursively(BuildArtifactMapperImpl.java:541)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.copyRecursively(BuildArtifactMapperImpl.java:541)
at org.netbeans.modules.java.source.usages.BuildArtifactMapperImpl.ensureBuilt(BuildArtifactMapperImpl.java:296)
at org.netbeans.modules.java.source.ant.TranslateClassPath.translateEntry(TranslateClassPath.java:151)
at org.netbeans.modules.java.source.ant.TranslateClassPath.translate(TranslateClassPath.java:113)
at org.netbeans.modules.java.source.ant.TranslateClassPath.execute(TranslateClassPath.java:95)
at org.apache.tools.ant.UnknownElement.execute(UnknownElement.java:291)
at sun.reflect.GeneratedMethodAccessor146.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at org.apache.tools.ant.dispatch.DispatchUtils.execute(DispatchUtils.java:106)
at org.apache.tools.ant.Task.perform(Task.java:348)
at org.apache.tools.ant.Target.execute(Target.java:392)
at org.apache.tools.ant.Target.performTasks(Target.java:413)
at org.apache.tools.ant.Project.executeSortedTargets(Project.java:1399)
at org.apache.tools.ant.Project.executeTarget(Project.java:1368)
at org.apache.tools.ant.helper.DefaultExecutor.executeTargets(DefaultExecutor.java:41)
at org.apache.tools.ant.Project.executeTargets(Project.java:1251)
at org.apache.tools.ant.module.bridge.impl.BridgeImpl.run(BridgeImpl.java:285)
at org.apache.tools.ant.module.run.TargetExecutor.run(TargetExecutor.java:539)
at org.netbeans.core.execution.RunClassThread.run(RunClassThread.java:153)
BUILD FAILED (total time: 0 seconds)

I'm obviously doing something wrong, but I'm not sure what seeing as I've never really used this before. Any help is very much appreciated!
 
Campbell Ritchie
Marshal
Posts: 52516
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You get null from getResource() if whatever you are seeking does not exist. Even the tiniest spelling error will throw the JVM and it will fail to load the picture. That may be the cause of the exception. I think I can see a spelling error.
And that is no way to initialise an array. Apart from my having to go and edit your post to get rid of the long lines, you can do the whole thing in an initialiserNow you can manipulate those images inside the array. I suggest you iterate the entire array as a test to check whether you have any nulls.
You can create a label array from that array.
Using all those if-else statements inside the action performed method should have shown you why addactionListener(this) is usually such bad non‑object‑oriented design.

There must be some way of going through the folders and finding the names of all classes ending with .jpg, but I can't think of it at the moment. Somebody else is bound to know.
I would suggest you nearly got it working with getResource; sort out the little errors you have got there and forget about the setImage() method for the time being. Particularly if you have access problems with Thumbs.db.
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the help! Changing the array type from JLabel to ImageIcon helped a lot.
In retrospect I should have realized that ImageIcon was it's own type, but I'm not thinking clearly with all the new stuff I'm trying to figure out.

I think I found the spelling error in "academy" ( the missing "d") and I changed my array to initialize as your's is, but even after I fixed all of that I still got the same error.
I thought it might be another spelling error, so I copied and pasted the first line that was giving me trouble and now it works.

I guess then that my way of setting the size of the array and then assigning values at each position isn't the correct way to do it?
I do see how your way is nicer as you just build it as you go and don't need to assign a starting size.

Sorry about the long lines issue. I hope this comment is better than the past ones you've had to edit.

I ran the program and I'm not using the array yet, but it does compile and run.

I see what you mean about all the if else statements in the actionPerformed method.
What would be the correct way of doing it then?
I understand that the "this" represents some kind of action listener event, but I don't what I would replace the "this" with.
Basically I'm not sure what the "this" is referencing in my code.
It does give me a message saying "leaking this in the constructor", but I'm not sure what it means.

Now that I've got this somewhat I think the next thing to do would be to use the array and and implement the repaint() method.
I'll play around with it and see what I can get going.

Thanks for all the help!
 
Campbell Ritchie
Marshal
Posts: 52516
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I think you are trying too much all at once. As you have seen, you can set up an array of any size with initlaisers. Iterate the array and confirm that it doesn't contain any nulls.

As for the Listeners, I have some suggestions, which I wrote long ago when I was an ordinary ranch hand. Start here, and follow all three links in that post. I hope that will help. You can see some heated discussion in those links!
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the articles! I think I get it now.

Instead of doing this:

I should do this:

I'm not sure if I have the syntax or formatting right, but it appears to be working for what it is.

I if understand correctly I want to do the second one because it is for that individual button where as the method is for every single button I make?
Thanks for the help and I probably should break this into one problem at a time haha.
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thanks for the help!
I think I got it to work and it's somewhat professional looking as well?
At the very least I hope it's neater and nicer to look at.


From a syntax stand point is this something that would be accepted at a place of work?
I know my first post was a jumbled mess, but I'm hoping after the help I got that it's now more "professional" looking.
Any more tips and advice is much appreciated! Thanks for all the help!
 
Campbell Ritchie
Marshal
Posts: 52516
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Alex Petsche wrote: . . . Instead of doing this: . . . I should do this . . .
Much much better
One of these posts might help decide whether to use anonymous classes or not: 1 2. Note there is an example with Actions by Rob Spoor in the same thread as link 1.

You can see the improvement in the code if you count the lines in the old version and the new version. You can also see the repeated code has gone

You are using the number literal 39; “magic numbers” like that are usually a bad idea. You should be using array.length (array is by no means a good name for it). That means the image[] should be a field and you need slightly different syntax to initialise it. You need to write new ImageIcon[]{...}
I am not convinced that the button and labels need to be fields; I suspect they can be local variables in the constructor. You do not need the content pane variable at all, as you see from the add() method documentation. Please check this style guide about names. Note the mistake about variables.
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I fixed the "magic number" use and I changed the name of my array. It was more of a quick fix to get it working, but I should have fixed it before posting the "final" version.

and in the method for randomGenerator I changed it to:

If I understand correctly (breaking the first section of code down) the "final ImageIcon images[]" creates an array that can be used as an object of the type ImageIcon and is named images.
Then "= new ImageIcon[]{" is creating the memory space for the data it is going to hold. I didn't need to specify a size, because I am telling it the size by filling in each picture to it.
If that is true, then how did my code work before I added "new ImageIcon[]" to it? Did Java just see what I was trying to do and accepted it?

Cool you are right about not needing "cp" for "contentPane". It looks like it is inheriting it from one of the imported classes?
I did end up needing the variable "currentLabel" declared as a field.
When I tried to move it inside the class as a local variable it said I had to declare it as a "final" and that defeated the purpose of the variable.
It's supposed to hold the last displayed Image, so that I can use the remove method to remove that image. If it's final then I can't change the data it holds which is what I need it to do.
There's probably a better way to do this, but I got this way to work for now.

I also have changed from using setBounds to BorderLayout. Would it just be personal preference or is there a preferred or "best" layout when deciding what to use?

Thanks for the help!
 
Campbell Ritchie
Marshal
Posts: 52516
118
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The add method has been updated in Java5 to add directly to the content pane.
I do not think you need the images array to be final. If you reallocate it to a new array, the images.length bit till still work.
final ImageIcon[] images; That tells the JVM to allocate enough memory for a reference to an array and gives its type
= new ImageIcon[]{...}; Creates an array object, whose contents are in ... and assigns the array object to the reference to the left of the =
... new ImageIcon(xyz.jpg), new ImageIcon(pqr.jpg) ... Creates two ImageIcon objects and assigns them to two of the places in the array.
 
Alex Petsche
Ranch Hand
Posts: 42
Java Netbeans IDE Windows
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Ok that's good to know. Thanks for clarifying that!

I tried taking away "final" and it gave me this error "local variable images is accessed from within inner class; needs to be declared final"

It starts up, but then when I click the "next" button to call the next image it breaks.


I know that the "final" keyword made the variable a constant, but I agree with you that I don't see why the variable would need to be declared as final.
Do you see why it needs to be declared that way?
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!