• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Devaka Cooray
  • Ron McLeod
  • Paul Clapham
  • Liutauras Vilda
Sheriffs:
  • paul wheaton
  • Jeanne Boyarsky
  • Tim Cooke
Saloon Keepers:
  • Stephan van Hulst
  • Tim Holloway
  • Tim Moores
  • Mikalai Zaikin
  • Carey Brown
Bartenders:

Only getting a PropertyChangeEvent at the end of SwingWorker

 
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello,

I am revisiting an assignment from my first Java class, where we had to do a simple GUI for painting the Mandelbrot Set. I'd like to add a JProgressBar where the value is determined by the loop in doInBackground(). My BufferedImage is 500 pixels wide, so I use publish(x/5) and setProgress(x/5) to set the value in the JProgressBar.

The problem is I cannot get the bar to update during the execution of the loop. Neither the PropertyChangeListener in Paint() in MB.java, nor the process() override in BuildImage.java seems to have an effect anywhere except at the end of the loop, at which point the bar shows 99%.

I've included below the two relevant classes. The class ComplexNumber is not included since it has nothing to do with the GUI.

I hope I am just overlooking something, but if I need to do a structural overhaul, I'll just have to suck it up and make the changes. :-)

Cheers
BD


MB.java






BuildImage.java
 
Sheriff
Posts: 22773
130
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
1) You should not mix AWT and Swing. Stop using Canvas, and use JPanel instead.

2) When you want to do custom painting with JPanel, you should override paintComponent(Graphics) instead. Make sure the first statement is super.paintComponent(g);.

3) You are now creating a new dialog with a new progress bar every time the canvas is repainted. That could be several times a second. Don't do that.

You should redesign your application a bit. The SwingWorker should be called either when the application starts, or upon a button press or something similar. It should most definitely not be called from any painting method.
To get the Image from the SwingWorker to the MB instance, class MB should get an Image field. The paintComponent method will then simply paint this image unless it's null (not set yet). The SwingWorker will set this Image field when it's done().
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thank you for your time, Rob. I do appreciate the number of tips you gave. When I asked my Professor for a critique (he does not grade them, his grad students do) he gave a few general tips, but nothing like yours. I hesitated posting that much code thinking people would just skip over this thread shaking their head. :-)

I never thought about the fact that I was mixing AWT and Swing. I'll stop doing that.

As far as the new dialog with every repaint, I noticed that and wondered myself. I found that example on the Net, but I guess I picked the wrong one to follow. :-(

When you say my MB instance should have an Image field, do you mean a BufferedImage since that is what I make, or do I convert the BufferedImage to an Image? Can I just do a cast here? I chose a BufferedImage because I did not like how the image was drawn, line by line. I prefer to wait with a black screen and have it appear when finished. I guess with SwingWorker setting the Image inside done(), I don't have a need to use a BufferedImage. Isn't a BufferedImage more efficient though? Or am I mixing apples and oranges here?

I may be misunderstanding something, but what is the difference between publish() and setProgress()? Can I pick one of those to use, or do I need to use both? If I use publish(), is my code for the JProgressBar/Dialog inside the process() override? Or does that lead to another multiple creation of dialog problem? The more I read in the JavaDoc, the more I think I need only setProgress() for this particular program since I am using the loop counter as my "percentage complete".

Again, thanks for the help. I've got two weeks before the Summer semester starts, so I plan to do a lot of Java in between the other projects I need to complete. I'll be posting more noob questions soon. :-)

BD
 
Rob Spoor
Sheriff
Posts: 22773
130
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bd Howard wrote:When you say my MB instance should have an Image field, do you mean a BufferedImage since that is what I make, or do I convert the BufferedImage to an Image? Can I just do a cast here? I chose a BufferedImage because I did not like how the image was drawn, line by line.


BufferedImage extends Image

I guess with SwingWorker setting the Image inside done(), I don't have a need to use a BufferedImage.


You can still use BufferedImage for creating the image. Afterwards you can set just that created BufferedImage as the Image of the MB instance.

Isn't a BufferedImage more efficient though? Or am I mixing apples and oranges here?


I wouldn't bother worrying about performance until you get performance problems. If BufferedImage works then just use that.

I may be misunderstanding something, but what is the difference between publish() and setProgress()? Can I pick one of those to use, or do I need to use both? If I use publish(), is my code for the JProgressBar/Dialog inside the process() override? Or does that lead to another multiple creation of dialog problem? The more I read in the JavaDoc, the more I think I need only setProgress() for this particular program since I am using the loop counter as my "percentage complete".


With publish / process you can work with any type of data. With setProgress you're limited to the progress. In your case that's just what you need.
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

BufferedImage extends Image



Who says I can't type faster than I can think? Either I am one hell of a typist, or my thought process is kinda slow.

Thanks. I'm making the changes now.

BD
 
Rob Spoor
Sheriff
Posts: 22773
130
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
You're welcome
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Back again,

The paintComponent(Graphics g) override needs that Graphics g. When I construct my BufferedImage in another class, do I also need the Graphics object I used to draw that BufferedImage to be sent back to the paintComponent()? Or will the Graphics g inside the paintComponent work with that static BufferedImage that is set from the done() in my SwingWorker thread of that other class? I do the cast to Graphics2D.

I am reusing code I know worked to draw my BufferedImage via a SwingWorker. When my paintComponent() in the GUI class draws the BufferedImage, all I get is a black background. Therefore, I am wondering if I am passing all that I need to pass, or if I am losing something in the translation. I can draw test shapes fine from within paintComponent(), but the static image does not paint aside from the background.

So in a nutshell, what I am doing is drawing an initial image with the default values in my class that extends SwingWorker. The done() sets the static bufferedImage inside my GUI class to the result of the Worker. The GUI build finishes and displays all of the components, except I am just getting a black box for my static image.

My question is how would you pass that BufferedImage around? Do I need to pass more than just the image? Is the Graphics instance that does the drawing, needed elsewhere, or is it not needed anymore once it completes the draw? Can another instance of Graphics work with that BufferedImage?

I want to put your answers to these conceptual questions to work before I give up and paste code.
 
Bartender
Posts: 5167
11
Netbeans IDE Opera Java
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
After the BufferedImage has had its content drawn, call repaint()
 
Rob Spoor
Sheriff
Posts: 22773
130
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator

Bd Howard wrote:The paintComponent(Graphics g) override needs that Graphics g. When I construct my BufferedImage in another class, do I also need the Graphics object I used to draw that BufferedImage to be sent back to the paintComponent()? Or will the Graphics g inside the paintComponent work with that static BufferedImage that is set from the done() in my SwingWorker thread of that other class? I do the cast to Graphics2D.


There should be two Graphics objects - one for creating the BufferedImage content, and one for drawing the BufferedImage on screen.
The first you can get by calling getGraphics() or preferably createGraphics() on the BufferedImage. If you use createGraphics() you don't need to do any casting to Graphics2D. You should call dispose() on the Graphics object when you're done.
The second one is the one passed to paintComponent.
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When I post code, should it be the whole class (even if it is long) or just the relevant methods?

The code I posted above is mostly stuff that does not have bearing on my original questions.

BD
 
Rob Spoor
Sheriff
Posts: 22773
130
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Likes 1
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
It should be an SSCCE (<= link).
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi,

I believe what I have here is an SSCCE.

As pointed out on the SSCCE page, the mere act of me simplifying my code down to the bare minimum has led me much closer to the resolution. I can now get my image to paint, but I have questions. I know, I know, there is always a catch.

Why does the print statement inside paintComponent() print out as if it is in an infinite loop? Shouldn't paintComponent() only be called when a change is detected?

Why is repaint() needed in paintComponent()? If I remove that, no image is displayed. Come to think of it, that repaint() explains the looping of my print statement. So that means the repaint() should not be there. If that is the case, how can I get my image to print without the reprint()?

There are three classes below. ComplexNumber has nothing to do with this problem, but it is required to generate the image. The code will paint the image, but with the infinite loop in full swing.

Thank you for your time.

BD

MB.java




BuildImage.java




ComplexNumber.java
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Here is something curious:

If I add this into my paintComponent(), the image will display if repaint() is called somewhere between 650 and 750 times or greater. The cut-off value changes with each run of the program. If I reduce "count" below that, I get no image.




Anyone know why this is the case?

BD
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Think I have it figured out. :-)
 
Rob Spoor
Sheriff
Posts: 22773
130
Eclipse IDE Spring VI Editor Chrome Java Windows
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
When you call repaint(), this will lead to a new call to paintComponent. This will again call repaint(), and your program is busy painting itself forever.
 
Bd Howard
Greenhorn
Posts: 80
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
I gave up on my want to have a whole separate class for the SwingWorker. I just set up an inner class that extends SW. Ended up being much simpler. I tend to make things too complicated in my quest to organize.

Everything paints correctly, AND with no need for a repaint() inside paintComponent().

Thanks for your help

BD
 
Wait for it ... wait .... wait .... NOW! Pafiffle! A perfect tiny ad!
a bit of art, as a gift, the permaculture playing cards
https://gardener-gift.com
reply
    Bookmark Topic Watch Topic
  • New Topic