Consider this code:
public class StateChartPanel extends JPanel {
private LightContext LC;
public StateChartPanel(LightContext lc){
LC=lc;
}
public void paintComponent( Graphics G ){
super.paintComponent( G );
LC.DrawStateChart((Graphics2D)G);
}
}
StateChartPanel is a panel to draw something (a state chart). It sends its Graphics object to LC which use it to draw shapes but whenever it draws something the PaintComponent event of StateChartPanel happens again and it causes my application to hang.
I think what's likely happening is an infinite loop: StateChartPanel.paintComponent is calling LC.DrawStateChart, which is then calling StateChartPanel.paintComponent. You probably have a StateChartPanel as a subcomponent of LC somehwere, and LC.DrawStateChart is calling its own paint() function. Try removing StateChartPanel.paintComponent's call to LC.DrawStateChart and see if that works.
Please learn proper Java Naming conventions. All conventions are typically followed in text books, tutorials or code we post in the forums. So follow them and don't make up your own:
a) variable names should not start with an upper case character
b) method names should not start with an upper case character
If you are looping then its probably because you invoke repaint() somewhere in your invisible code that you didn't post.
If you need more help post your SSCCE that shows the problem.
Related
/*
<applet code =game height = 400 width =400 >
</applet>
*/
import java.awt.* ;
import java.awt.event.* ;
import java.applet.* ;
public class game extends Applet {
public void paint(Graphics g){
System.out.println("done");
}
}
This is my code. I haven't used the repaint function in program but still the output is:
done
done
That is, 'done' is printed twice.
First of all, the paintComponent(Graphics g){...} function is called lots and lots of times (when you create the JPanel, when you resize it...) and you don't really know when it's being called. It's not a good practice to write code which isn't intended to draw stuff in that function (unless you're debugging that part of the code). It could cause your app to be very laggy.
Instead, try to write that piece of code in other method and call it at the end of the JPanel constructor(or introduce it directly), that way you'll know when the constructor has ended building up the JPanel. (If that's your purpose).
As a sidenote: check out this swing tutorial, it's going to help you clearly understand how swing works.
Select as answer if it'd helped you. :D
I've got a beginner question here that I was hoping someone with some Java experience could help me with. Currently taking an intro to OOP course focused on Java. My instructor is currently covering awt and swing, specifically the need to override the paint method so that graphics are redrawn when a window is resized, etc. I like to do as much outside reading as possible, and my concern is that the examples that my professor gives involve things that I've read are not best practices. To get to the point...
I understand that it's necessary to override the paint method, but I don't know the best way to do so. My professor's examples are all similar to the following:
class Example extends JFrame {
public void paint(Graphics g) {
super.paint(g);
g.drawString("Blah, blah");
}
public static void main(String[] args) {
Example a = new Example();
a.setDefaultCl...
\\Etc...
}
}
This bothers me because it doesn't seem right to include everything for the GUI in the same class as my main method. Also, I read on a different thread here that you shouldn't extend JFrame, but there wasn't an explanation as to why. My solution was to create a class handling the gui and instantiate JFrame within the constructor. However, unless I'm mistaken, doing so won't let me override the paint method. I feel compelled to extend JFrame to allow me to override paint, but again I read that was the wrong thing to do.
Any help would be sincerely appreciated, I know I can just model my code off of what he has but I really want to understand this and know the best way to handle it.
I understand that it's necessary to override the paint method
No you should not override the paint() method.
You should override the paintComponent() method of a JPanel and then add the panel to the frame.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.
The tutorial will also show you how to better structure your code so that the GUI is created on the Event Dispatch Thread (EDT). The tutorial also has a section on Concurrency which will explain why this is important.
I am having an odd issue when using paintComponent() and repaint().
As you see below, I have a paintComponent() class as an inner class as the main JPanel of my GUI.
// add another panel to centerInner
tableBottom = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (!paintImages.isEmpty()) {
for (PaintImages temp : paintImages) {
g.drawImage(temp.getImage(), temp.getX(), temp.getY(), this);
}
}
if (!extraCards.isEmpty()) {
for (PaintImages temp1 : extraCards) {
g.drawImage(temp1.getImage(), temp1.getX(), temp1.getY(), this);
}
}
}
};
This is a black jack game with 4 players a dealer.
repaint() is called by 4 functions:
The constructor for the initial draw.
An update method that creates an ArrayList of objects to print for the initial deal.
An another update method that creates an ArrayList for each card drawn.
And the reset which clears all ArrayLists and repaints the new initial deal.
I won't go into the backend, but every one of those four methods only run the desired number of times. just once for every time its called.
My problem is that when paintComponent is invoked by repaint(), paintComponent() runs almost 200 times, not including the for loops that run around 10 times a piece on average per game.
My question is:
1) Is this common behavior for a paintComponent method? Does paintComponent call itself repeatedly over and over again until all painting necessary has been completed?
OR
2) Does this have to do with the JPanel tableBottom? at this point nothing is actually being added to the JPanel because it is top most JPanel. But maybe paintComponent is ran repeatedly for every JPanel, JFrame, ContentPane, Label, etc.,
OR
3) Did I do something wrong in my code below? Again through testing using increments and print statements I found the update methods are called the appropriate amount of times and doing their jobs correctly.
Thanks for any help.
being a inner class I call repaint like tableBottom.paintComponent()
Never invoke the paintComponent() method directly. To repaint the panel you do:
tableBottom.repaint();
The request will be passed to the RepaintManager which will then combine repaint() requests for all components and then paint the components as necessary. This will make painting more efficient.
g.drawImage(temp1.getImage(), temp1.getX(), temp1.getY(), this);
The "this" means that images can be repainted as they are being read. That is sometimes the painting method is invoked before the image I/O has completed. So in this case when the I/O is finished another paint request will be made so the image is painted completely. If you are reading the images at the start of you class and storing them in some data structure then you can probably just use "null" instead of "this".
Did I do something wrong in my code below?
The code provide looks reasonable, but we can't see the context of how/when you invoke the painting code. I already mentioned one problem.
Post a proper SSCCE that demonstrates the problem.
I'm writing an app which runs in a headless environment and needs to output to a BufferedImage instead of a screen. I have a Display class managing the BufferedImage. My app extends JPanel and in order to make it automatically repaint when a component updates, I've re-implemented repaint() as:
public void repaint(){
Graphics2D g = getDisplay().getGraphics();
paint(g);
getDisplay().repaint();
}
Whenever I start up my app, though, I get a NullPointerException when it tries to draw to the Display. This is supposedly some code in the JPanel constructor that tries to repaint. The problem is that getDisplay() returns null. However, the Display has already been instantiated and passed to the app at this point. I've verified this by having the Display print out its own properties on creation, before sending it to the app.
The exception is as follows; the topmost location refers to the line containing getDisplay():
Exception in thread "main" java.lang.NullPointerException
at com.mypapyri.clay.ui.App.repaint(App.java:28)
at javax.swing.JComponent.setFont(JComponent.java:2746)
at javax.swing.LookAndFeel.installColorsAndFont(LookAndFeel.java:208)
at javax.swing.plaf.basic.BasicPanelUI.installDefaults(BasicPanelUI.java:66)
at javax.swing.plaf.basic.BasicPanelUI.installUI(BasicPanelUI.java:56)
at javax.swing.JComponent.setUI(JComponent.java:655)
at javax.swing.JPanel.setUI(JPanel.java:153)
at javax.swing.JPanel.updateUI(JPanel.java:126)
at javax.swing.JPanel.<init>(JPanel.java:86)
at javax.swing.JPanel.<init>(JPanel.java:109)
at javax.swing.JPanel.<init>(JPanel.java:117)
at com.mypapyri.clay.ui.App.<init>(App.java:18)
at ClayOS.<init>(ClayOS.java:22)
at ClayOS.main(ClayOS.java:84)
EDIT: I've researched this and could not find a satisfactory resolution.
The repaint() method and the GUI thread
Javadocs for Component
PaintManager and RepaintManager
nidu told it first, but since he doesn't answer I put it.
Probably you're calling super() in the constructor method, and the JPanel constructor is trying to repaint before the display has been set.
I have the following scenario: If I have a while block in the paint() method (used for example to simulate a simple animation such as rotating a polygon, done by multiple drawing and erasing the figure), is there a way to break the while block, when clicking the mouse inside the applet?
The animation of the polygon is done without recalling the paint() method. Also would it be possible to do so if the while block looked something like this:
while (count<n)
{
//code that draws the polygon rotating
count++;
}
Yes there is a scenario to hold on your while loop.
The simpliest way would be to set up a variable in your classfile private boolean stopLoop=false and within your while loop check for this attribute while (!stopLoop).
Now the MouseEvent just set the attribute stopLoop=true and you are done (if you need help, here you are How to Write a Mouse Listener
The other solution is using Swing Timer as mentioned by #camickr (see other answer). Lets assume you have a general Timer method outside your paint() method. Then you sould't use a while loop in there. I would suggest to just paint a static picture and if you want that your poligon rotates, just draw the next one, but with another angle and so on.
The idea is that you cut out your while loop into the Timer method so paint() gets called a lot of times. If you want to stop the poligon from circling around use a boolean flag for it or stop the timer. In the first case you can handle more then one polygon and each of them can be started and stopped, if you handle the boolean variables and the mouse event correct.
If you have further questions please add some more detail, or bedder show us some minimized code.
Don't use a while loop.
Instead use a Swing Timer to schedule the animation. Then you can simply start/stop the timer as required.