Hijack `repaint()` call in Java Swing component - java

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.

Related

When the Graphics instance is created

I know that when paint is happening an instance of the Graphics class should be created. That Graphics object (Actually Graphics2D object) is going through paint() method and all the details that should be printed or updated on the screen are stored in that object.
As I know of this process is handled by RepaintManager when user called repaint() method or when repaint is needed to the UI. So, a Graphics instance has to be created to store the information regarding the painting.
As this process is handled by RepaintManager, I thought that the Graphics instance is also initialized inside RepaintManager. But I found source code of RepaintManager recently. And couldn't find a place that a new Graphics instance is created.
So, is it really created inside RepaintMananger or anywhere else..?
Thanks..
It's created in Component.getGraphics() see the API for more information

paintComponent() is being invoked 200 times

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.

JFrame cannot find 'pack' method

I'm taking a beginning Java class and an assignment requires that I write a class to represent a JPanel with buttons to increment and decrement a value and a label to display the value. Then, I have to create a separate class which instantiates the panel and adds it to a frame. I'm trying to have the frame resize to fit the size of the panel by running the pack method. I try to call the frame's pack method by using:
SwingUtilities.getAncestorOfClass(JFrame.class, this).pack()
I get a "cannot find symbol - method pack()" error. The getAncestorOfClass is definitely returning a JFrame, and it is the correct JFrame. When I run the pack method from inside the driver class where the JFrame is created, there are no problems. Any ideas why it can't find the pack method? Is it because I'm trying to run this from a separate class file? I also can't access some other JFrame methods such as getContentPane, but I am able to access some others such as add. Huh?
The method SwingUtilities.getAncestorOfClass returns a Container. Now, you know that Container is really gonna be a JFrame, but the compiler doesn't. And Java is a static language, not a dynamic one that'll just try to call the method regardless of whether the class declares it or not.
Since Container doesn't have pack method, the compiler's gonna complain. You'll need to cast to JFrame to make it work:
((JFrame)SwingUtilities.getAncestorOfClass(JFrame.class, this)).pack();
Careful, though... The method can return null if no suitable ancestor was found. You might want to check that first.
You need to cast it to JFrame:
((JFrame) SwingUtilities.getAncestorOfClass(JFrame.class, this)).pack();
The SwingUtilities.getAncestorOfClass(Class, Component) method return a component, and not a JFrame.

Java Swing: repaint() vs invalidate [duplicate]

This question already has answers here:
Closed 12 years ago.
Possible Duplicate:
Java Swing revalidate() vs repaint()
Hi all
I'm fighting with my program to make it refresh at the right time.
And not having a lot of success lol
I have 2 questions
Q1: which should I use when my interface has changed: repaint or invalidate?
Q2: when should they be called? I know it sounds stupid but I'm actually having problems because of SwingWorker and other threaded operations.
Q1: which should I use when my
interface has changed: repaint or
invalidate?
If the layout is not up to date because of resizing , font change etc then you should call invalidate. Invalidating a component, invalidates the component and all parents above it are marked as needing to be laid out. Prior to painting, in the validation step if no change is found then the paint step is left out.
If there is some part of component which is being updated (defined by the graphic's clip rectangle, called "damaged" region) then you should consider calling repaint. One of the reason a damaged regions may occur is from the overlapping of a part of your component because of some other component or application.
As per my experience the repaint() is more effective if you call it on the innermost enclosing component (i.e. using public void repaint(int x, int y, int width, int height) rather than using public void repaint()).
Q2: when should they be called?
Invalidate(): marks a component as not valid -- that means, it's layout is or may not be "up to date" anymore: i.e. the component is resized, a border is added, it's font changes, etc. you should never need to call invalidate() by hand, as swing does that for you on pretty much for every property change.
When more than one region within the control needs repainting, Invalidate will cause the entire window to be repainted in a single pass, avoiding flicker caused by redundant repaints. There is no performance penalty for calling Invalidate multiple times before the control is actually repainted.
Repaint() : If the component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.
Also have look at Update method.
NOTE: Swing processes "repaint" requests in a slightly different way from the AWT, although the final result for the application programmer is essentially the same -- paint() is invoked.
Refer to the link below for an excellent link on how painting is done in AWT and Swing:
http://www.oracle.com/technetwork/java/painting-140037.html
Hope this will help.

why PaintComponent event in Java happen everytime I use its Graphics Event?

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.

Categories