Swing - paintComponent not called

B

Bojan

Hi all,

For some reason the paintComponent is never called to print the
image. The image is valid, i have tested it with setIconImage(image)
and it worked fine. Why is the paintComponent never called? Any help
would be appreciated. Thanks in Advance.


The ProgressFrame is called from a run method, which is in a class
that implements Runnable. Which is called by creating a new thread.


Here is the code for the ProgressFrame:

public class ProgressFrame extends JFrame {

public ProgressFrame()
{
Container contentPane = this.getContentPane();
URL url = this.getClass().getResource("/Resources/busy.jpg");
Image image = Toolkit.getDefaultToolkit().getImage(url); //new File
("/Resources/busy.jpg");

DrawingPanel panel = new DrawingPanel(image);
contentPane.add(panel);
setTitle("Loading");
setSize(384, 230);
setResizable(false);
setVisible(true);
toFront();
}
}

class DrawingPanel extends JPanel
{
Image img;

DrawingPanel (Image img)
{ this.img = img; }

public void paintComponent (Graphics g) {
super.paintComponent (g);
g.drawImage (img, 0, 0, this);
} // paintComponent
}
 
K

Knute Johnson

Bojan said:
Hi all,

For some reason the paintComponent is never called to print the
image. The image is valid, i have tested it with setIconImage(image)
and it worked fine. Why is the paintComponent never called? Any help
would be appreciated. Thanks in Advance.


The ProgressFrame is called from a run method, which is in a class
that implements Runnable. Which is called by creating a new thread.


Here is the code for the ProgressFrame:

public class ProgressFrame extends JFrame {

public ProgressFrame()
{
Container contentPane = this.getContentPane();
URL url = this.getClass().getResource("/Resources/busy.jpg");
Image image = Toolkit.getDefaultToolkit().getImage(url); //new File
("/Resources/busy.jpg");

DrawingPanel panel = new DrawingPanel(image);
contentPane.add(panel);
setTitle("Loading");
setSize(384, 230);
setResizable(false);
setVisible(true);
toFront();
}
}

class DrawingPanel extends JPanel
{
Image img;

DrawingPanel (Image img)
{ this.img = img; }

public void paintComponent (Graphics g) {
super.paintComponent (g);
g.drawImage (img, 0, 0, this);
} // paintComponent
}

Are you creating the ProgressFrame on the EDT? Is the image really
where you think it is?
 
R

Roedy Green

For some reason the paintComponent is never called to print the
image.

The usual reason an overridden method never gets called is you changed
the signature slightly so it does not actually override the base
method. Check the spelling and parm types with a microscope.

--
Roedy Green Canadian Mind Products
http://mindprod.com

"At this point, 29 percent of fish and seafood species have collapsed - that is,
their catch has declined by 90 percent. It is a very clear trend, and it is accelerating.
If the long-term trend continues, all fish and seafood species are projected to collapse
within my lifetime -- by 2048."
~ Dr. Boris Worm of Dalhousie University
 
B

Bojan

<snip>

Works for me--draws the image (when main added.) Are you sure busy.jpg is in
the correct location or that Resources is capitalized correctly?  It is best
also to launch the window from the EDT as in:

SwingUtilities.invokeLater (new Runnable () {
  public void run () {
    ProgressFrame pf = new ProgressFrame ();
  }
  });

Matt Humphreyhttp://www.iviz.com/

That does work. But I forgot to mention that I am calling the method
from actionPerformed(ActionEvent ae).

A main frame has menu items that correspond to actions. When one of
them is executed it checks if ae.getSource equals to the menu item.
E.g.
JMenuItem source = (JMenuItem) ae.getSource();
if (source == open) {
openFile();
}
else if (...

When openFile is called, which creates the new thread... it does not
show the image.


But if an argument is passed to the main method, it calls openFile
(fileName) it does show the image.
openFile() and openFile(File f) have the similar code.

does anyone have any ideas why there is a difference?

Thanks in advance
 
B

Bojan

The usual reason an overridden method never gets called is you changed
the signature slightly so it does not actually override the base
method. Check the spelling and parm types with a microscope.

--
Roedy Green Canadian Mind Productshttp://mindprod.com

"At this point, 29 percent of fish and seafood species have collapsed - that is,
their catch has declined by 90 percent. It is a very clear trend, and it is accelerating.
If the long-term trend continues, all fish and seafood species are projected to collapse
within my lifetime -- by 2048."
~ Dr. Boris Worm of Dalhousie University

Good point, but that is not the problem since it does work when called
from outside actionPerformed(ActionEvent ae);
 
R

Roedy Green

URL url = this.getClass().getResource("/Resources/busy.jpg");
Image image = Toolkit.getDefaultToolkit().getImage(url); //new File
("/Resources/busy.jpg");

Just where in your jar is this resource? Normally you file them in
the same package as the class using them. You have used an absolute
name, outside the package.

See http://mindprod.com/jgloss/image.html
and
http://mindprod.com/jgloss/resource.html

Dump the url.toString() to see where it is looking for your resource.
Use JarLook to dump out the contents of your jar to see where the
resource really is. They had better match.

See http://mindprod.com/products1.html#JARLOOK


also, you have no media tracker. To make sure the icon gets loaded
properly you can use:

Image image = new ImageIcon( url ).getImage();

ImageIcon has a built-in MediaTracker.

Your "new File" suggests this resource is not inside the jar at all.
That is masochism. Put everything in the jar.

see http://mindprod.com/jgloss/jar.html

--
Roedy Green Canadian Mind Products
http://mindprod.com

"At this point, 29 percent of fish and seafood species have collapsed - that is,
their catch has declined by 90 percent. It is a very clear trend, and it is accelerating.
If the long-term trend continues, all fish and seafood species are projected to collapse
within my lifetime -- by 2048."
~ Dr. Boris Worm of Dalhousie University
 
B

Bojan

Just where in your jar is this resource?  Normally you file them in
the same package as the class using them. You have used an absolute
name, outside the package.

Seehttp://mindprod.com/jgloss/image.html
andhttp://mindprod.com/jgloss/resource.html

Dump the url.toString() to see where it is looking for your resource.
Use JarLook to dump out the contents of your jar to see where the
resource really is.  They had better match.

I am not using a jar file, I am using RAD (Rational Application
Developer) (a version of eclipse) to test the code.
The New File is just a comment that i forgot to delete, sorry for
confusing you.
I have used setIconImage(image) and it works fine all the time, so the
file defiantly exists.

Seehttp://mindprod.com/products1.html#JARLOOK

also, you have no media tracker. To make sure the icon gets loaded
properly you can use:

Image image = new ImageIcon( url ).getImage();

ImageIcon has a built-in MediaTracker.

Your "new File" suggests this resource is not inside the jar at all.
That is masochism.  Put everything in the jar.

seehttp://mindprod.com/jgloss/jar.html

I have tried changing the declaration of Image to what you have
recommended but The result is still the same. The icon is displayed,
but the image is never updated in the panel.
 
L

Lew

Matt said:
Whoa! Hold on there! This is a completely different problem.

If you're creating a new thread, there are various constraints on how
you can update the GUI from that thread. If you are attempting to do
more than repaint, revalidate or invalidate you should expect to have
problems. Virtually all other Swing methods must take place on the EDT.

When you say you are "calling the method from actionPerformed" do you
mean paintComponent or some method --as yet not shown-- which invokes
new ProgressFrame () ? I'm guessing the latter in which case your main
problem is probably threading, but if not calling paintComponent is
probably the wrong thing to do anyway.

You will have to show what openFile does and explain how it connects to
new ProgressFrame. At this point it would probably be best if you put
together a test program that actually demonstrates the problem (as
opposed to the code you sent that does not.)

Your points are valid and helpful, especially the call for a test program
(implicitly an SSCCE), but your HTML post showed up as really, really tiny
text in my newsreader. Could you please stick with plain text?
 
J

John B. Matthews

Bojan said:
The usual reason an overridden method never gets called is you
changed the signature slightly so it does not actually override the
base method. Check the spelling and parm types with a microscope.
[...]
Good point, but that is not the problem since it does work when
called from outside actionPerformed(ActionEvent ae);

You might verify that addActionListener() has been invoked correctly. If
you are calling paintComponent() from actionPerformed(), repaint() might
be clearer.
 
K

Knute Johnson

Bojan said:
Good point, but that is not the problem since it does work when called
from outside actionPerformed(ActionEvent ae);

Are you calling paintComponent() from the ActionListener?
 
C

cbossens73

The usual reason an overridden method never gets called is you changed
the signature slightly so it does not actually override the base
method. Check the spelling and parm types with a microscope.

To which it's probably safe to add that since Java 1.5
the @Override annotation can really help to make this
point moot :)

Charles
 
R

RedGrittyBrick

Lew said:
Matt Humphrey wrote: [...]
You will have to show what openFile does and explain how it connects
to new ProgressFrame. At this point it would probably be best if you
put together a test program that actually demonstrates the problem (as
opposed to the code you sent that does not.)

Your points are valid and helpful, especially the call for a test
program (implicitly an SSCCE), but your HTML post showed up as really,
really tiny text in my newsreader.

Ctrl+Plus helps (Thunderbird).

Could you please stick with plain text?

I second this request :)
 
B

Bojan

  >
  >  >
  > > Hi all,
  >
  > > For some reason the paintComponent is never called to print the
  > > image. The image is valid, i have tested it with setIconImage(image)
  > > and it worked fine. Why is the paintComponent never called? Any help
  > > would be appreciated. Thanks in Advance.
  >
  > > The ProgressFrame is called from a run method, which is in a class
  > > that implements Runnable. Which is called by creating a new thread.
  >
  > > Here is the code for the ProgressFrame:
  >
  > <snip>
  >
  > Works for me--draws the image (when main added.) Are you sure busy.jpg is in
  > the correct location or that Resources is capitalized correctly? It is best
  > also to launch the window from the EDT as in:
  >
  > SwingUtilities.invokeLater (new Runnable () {
  > public void run () {
  > ProgressFrame pf = new ProgressFrame ();
  > }
  > });
  >
  > Matt Humphreyhttp://www.iviz.com/

  That does work. But I forgot to mention that I am calling the method
  from actionPerformed(ActionEvent ae).

  A main frame has menu items that correspond to actions.  When one of
  them is executed it checks if ae.getSource equals to the menu item.
  E.g.
  JMenuItem source = (JMenuItem) ae.getSource();
  if (source == open) {
    openFile();
  }
  else if (...

  When openFile is called, which creates the new thread... it does not
  show the image.
Whoa! Hold on there!  This is a completely different problem.

If you're creating a new thread, there are various constraints on how you can update the GUI from that thread.  If you are attempting to do more than repaint, revalidate or invalidate you should expect to have problems.  Virtually all other Swing methods must take place on the EDT.

When you say you are "calling the method from actionPerformed" do you mean paintComponent or some method --as yet not shown-- which invokes new ProgressFrame () ?  I'm guessing the latter in which case your main problem is probably threading, but if not calling paintComponent is probably the wrong thing to do anyway.

You will have to show what openFile does and explain how it connects to new ProgressFrame.  At this point it would probably be best if you put together a test program that actually demonstrates the problem (as opposed to the code you sent that does not.)

Matt Humphreyhttp://www.iviz.com/

Here is the test code that will address my problem. I have changed
the image to an image from the internet so that everyone will have it
the same.

FILE 1: This file is the place where the image should load, it is run
in a new thread.

public class ProgressFrame extends JFrame {
public ProgressFrame()
{
Container contentPane = this.getContentPane();
URL url = null;
try {
url = new URL("http://online.vodafone.co.uk/en_GB/assets/static/
ipi_please_wait.gif");
} catch (MalformedURLException e) {
e.printStackTrace();
}
Image image = new ImageIcon( url ).getImage();
setIconImage(image);//If the icon is changed, then so is image
should be displayed as well

DrawingPanel panel = new DrawingPanel(image);
contentPane.add(panel);
setTitle("Loading");
setSize(384, 230);
setResizable(false);
setVisible(true);
toFront();
}

public void close()
{
setVisible(false);
dispose(); //close the window
}
}
@SuppressWarnings("serial")
class DrawingPanel extends JPanel
{
Image img;

DrawingPanel (Image img)
{ this.img = img; }

public void paintComponent (Graphics g) {
super.paintComponent (g);
g.drawImage (img, 0, 0, this);
} // paintComponent
}

FILE 2: When the button is pressed, it creates a new thread, creates
ProgressFrame and keeps changing the title of the ProgressFrame.

public class MainFrame extends JFrame implements ActionListener{
private String statusTitle;
JButton button;
public MainFrame()
{
JPanel panel = new JPanel();
button = new JButton("Start Loading");
panel.add(button);
button.addActionListener(this);
Container contentPane = this.getContentPane();
contentPane.add(panel);

setTitle("Main Frame");
setSize(400, 200);
setVisible(true);
}

public void actionPerformed(ActionEvent e) {
if (e.getSource() == button)
{
Thread a = new Thread (new Runnable () {
public void run () {
ProgressFrame pf = new ProgressFrame();
int counter = 0;
//Just to show that the window is doing something
try {
while (true)
{
Thread.sleep(200);
pf.setTitle(pf.getTitle() + ".");
counter++;
if (counter==4)
{
counter = 0;
pf.setTitle(statusTitle);
}
}
} catch (InterruptedException e) {
pf.close();
}
}
});

statusTitle = "Loading";
a.start();
try {
//This is supposed to represent some actions that the main class
will do
Thread.sleep(10000);
} catch (InterruptedException e1) {

}
a.interrupt();
}
}
}

File 3 Just creates the Main Frame.:

public class Runer {
public static void main(String[] args)
{
JFrame main = new MainFrame();
}
}
 
B

Bojan

public void actionPerformed(ActionEvent e) {
if (e.getSource() == button)
{
Thread a = new Thread (new Runnable () {
public void run () {
ProgressFrame pf = new ProgressFrame();
int counter = 0;
//Just to show that the window is doing something
try {
while (true)
{
Thread.sleep(200);
pf.setTitle(pf.getTitle() + ".");
counter++;
if (counter==4)
{
counter = 0;
pf.setTitle(statusTitle);

}
}
} catch (InterruptedException e) {
pf.close();
}
}
});

statusTitle = "Loading";
a.start();
try {
//This is supposed to represent some actions that the main class
will do
Thread.sleep(10000);

} catch (InterruptedException e1) {
}
a.interrupt();
}
}
}

-------------------------------------------
Ok, the main troubles I see are:
   you are launching a new window in a non-EDT thread,
   you are updating that window from a non-EDT thread
   you are blocking the EDT with a sleep so no updates / drawing will occur.

To create the window in the EDT--just move the ProgressFrame creation
outside of the loop (mark the local variable pf as final).  As for updating
the title, it is probably not part of your main problem, but you should
instead use (uncompiled, untested)

SwingUtilities.invokeLater (new Runnable () {
  pf.setTitle (---whatever---);

});

As for blocking the EDT with sleep--keep in mind that all GUI updates
(redrawing, handing events, etc) take place on the EDT--the screen will not
update while you are processing the menu selection.  Launch your interruptor
into a separate thread where it can wait while the EDT gets back to work.
Mark local variable "a" as final.

Thread interruptor = new Thread (new Runnable () {
try {
  Thread.sleep (10000);} catch (InterruptedException ex) {

  ex.printStackTrace (); // Never leave this empty}
a.interrupt ();
});

interruptor.start ();
// Return back to EDT so it can do its job

Matt Humphreyhttp://www.iviz.com/

I did not use
SwingUtilities.invokeLater (new Runnable () {
pf.setTitle (---whatever---);

});
but everything else works perfectly.

Thanks a lot. I really appreciate it.
 
R

Roedy Green

Good point, but that is not the problem since it does work when called
from outside actionPerformed(ActionEvent ae);

It is non-idiomatic Java to call paintComponent yourself. You are
supposed to call repaint or repaint with a clip region and wait for
the event to percolate to call your paintComponent to repaint it.
Other stuff happens prior to paintComponent that you likely are not
sufficiently closely emulating.
--
Roedy Green Canadian Mind Products
http://mindprod.com

"The most significant trend in the US industry has been the decline in the amount
of energy recovered compared to energy expended. In 1916, the ratio was about 28
to 1, a very handsome energy return. By 1985, the ratio had dropped to 2 to 1,
and it is still dropping."
~ Walter Youngquist, Professor of Geology

By 2003, it had dropped to 0.5 to 1 in the US, making oil extraction no longer economically viable, no matter how high the price of crude.
 
R

Roedy Green

. If you are attempting to do more than repaint, revalidate or invalidate you should expect to have problems. Virtually all other Swing methods must take place on the EDT.

Yikes! Swing is relentlessly single thread. How do you use it from
other threads? See http://mindprod.com/jgloss/swingthreads.html

I find it odd O.P. could be doing something as advanced as
paintComponent while somehow never stumbling on the elementary
discussions of Swing and the EDT thread.

--
Roedy Green Canadian Mind Products
http://mindprod.com

"The most significant trend in the US industry has been the decline in the amount
of energy recovered compared to energy expended. In 1916, the ratio was about 28
to 1, a very handsome energy return. By 1985, the ratio had dropped to 2 to 1,
and it is still dropping."
~ Walter Youngquist, Professor of Geology

By 2003, it had dropped to 0.5 to 1 in the US, making oil extraction no longer economically viable, no matter how high the price of crude.
 
D

Daniel Pitts

Roedy said:
Yikes! Swing is relentlessly single thread. How do you use it from
other threads? See http://mindprod.com/jgloss/swingthreads.html

I find it odd O.P. could be doing something as advanced as
paintComponent while somehow never stumbling on the elementary
discussions of Swing and the EDT thread.
It happens. I have, unaware, written a few programs that weren't thread
safe myself.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top