Recently I've started coding some Java 2D.
I made this:
public void paintComponent(Graphics comp) {
Graphics2D comp2D = (Graphics2D) comp;
Font fontx = new Font("Verdana", Font.BOLD, 5);
comp2D.setFont(fontx);
comp2D.drawString("Hello World!", 5, 50);
}
I did import JFrame and java.awt.*, but there's still a problem.
When I run it, I get this:
Exception in thread "main" java.lang.NullPointerException
at game.Game.paintComponent(Game.java:41) - comp2D.setFont(fontx); - Sets Font
at game.Game.next(Game.java:36) - paintComponent(null); - calls the paintComponent public void from the next() public void
at game.Game.main(Game.java:26) - next.next(); - calls a public void called "next" using an object called "next" (this public void throws InterruptedException)
Java Result: 1
How can I solve it?
You state:
Exception in thread "main" java.lang.NullPointerException
at game.Game.paintComponent(Game.java:41) -
comp2D.setFont(fontx); - Sets Font
This means that comp2D is null and you're trying to call a method on a null variable.
at game.Game.next(Game.java:36) - paintComponent(null);
- calls the paintComponent public void from the next() public void
This means that you're calling paintComponent directly and passing in null!
So you're calling paintComponent directly and passing in null! It should come as no surprise that the Graphics object is null and will throw a NPE if you try to call methods on it.
Solution:
You almost never call paintComponent directly.
Instead have the JVM call it when you call repaint(). The JVM will pass in a valid Graphics object.
Most important -- read the painting with Swing tutorial. You can't guess at this stuff and expect it to work.
Be sure that your paintComponent method is held within a JPanel or other JComponent derived component.
Be sure that your override is valid by using the #Override annotation for paintComponent.
Don't neglect to call the super.paintComponent(...) method within your override.
For example, have your other method change a class field, say have it change a String field called text, then call repaint(), and then have your paintComponent(...) method use the text field for the text to print in the JPanel. This is just an example. You can change any of the drawing component's fields, and then use them inside of paintComponent(...).
Related
Here is my code
boolean boo = true;
ItemListener itemListener = new ItemListener() {
public void itemStateChanged(ItemEvent event) {
boo= false;
aSwingObj.repaint();
boo = true;
}
}
I want the repaint() method to run while boo is set to false, before it becomes true .
The problem is that repaint() function is only executed after the variable boo has been set to true again. I have tried other methods like revalidate(), validate() but it didn't work. How should I fix my code?
This is an XY problem. You don't want to force JPanel to immediately repaint. You want to enter a particular state immediately before painting begins and exit that state as soon as painting is over.
One way of accomplishing that would in fact be to enter that state, force a repaint right on the spot, and then exit that state. But as you have seen, this is a bit hard to accomplish.
So, another approach is to create a new class that does extend JPanel (or whatever the class of aSwingObj is) so that you can override the paintComponent() method and make it exit your special state once painting is done.
So, the paintComponent() method of your extended JPanel would look like this:
#Override
public void paintComponent( Graphics g )
{
super.paintComponent( g );
resetBoo();
}
where resetBoo() is a method which does boo = true;
There are two java files Animate and Anim1.The Anim1 file has the JFrame and I want to attach the Animate file which has the logic of text scrolling by the screen(supposed to be the JFrame screen).But I cannot find a way.And also the code is throwing the following compile time error-
Exception in thread "Thread-0" java.lang.Error: Unresolved compilation problem:
The method repaint() is undefined for the type Animation
import java.awt.Graphics;
public class Animation implements Runnable {
int x=500;
String s="hello world";
public void run(){
while(true){
repaint();
try{
Thread.sleep(50);
}catch(InterruptedException e){
e.printStackTrace();
}
}
}
public void paint(Graphics g){
g.drawString("hello world", x,-10 );
x--;
if(x< -100){
x=500;
}
}
}
import java.awt.Component;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class Anim1 {
public static void main(String[] args){
Animation a= new Animation();
Thread t= new Thread(a);
t.start();
JFrame frame= new JFrame("animate");
frame.setVisible(true);
frame.setSize(400,400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
The repaint method is found in Swing components -- same for the paint and paintComponent. Calling it inside of a class that does not extend a Swing comopnent does not make sense unless you're making the repaint call on another object that is a component. Likewise giving a non-component class a paint method makes no sense since you're not overriding any painting method.
Likely your Animation class should extend JPanel so that it can override paintComponent (not paint) and so that the repaint() call makes sense. Also always pre-pend your painting method (or any other method that you think overrides a parent method) with the #Override annotation. This way the compiler will complain to you when you're not overriding the method correctly (or at all). You'll also want to call the super's painting method inside of your override.
Most important: read the Swing painting tutorials as it's all explained there. Check out: Performing custom painting
Your painting method would look something like so:
#Override
protected void paintComponent(Graphics g) {
// always call the super's method to clean "dirty" pixels
super.paintComponent(g);
// then draw the String. Make y a field too, so it can be controlled
// more easily
g.drawString(s, x, y);
}
Note that I don't change the x value or call any state-changing code within my painting method, and that's by design. The paintComponent method is for painting only. You don't have full control over whether or even if it will be called, and it can be called multiple times.
Instead the x value should be changed within the "game loop", here your Runnable's run() method. Also, as per my comments, while this code can be created using Thread/Runnable, it's safer to instead use a Swing Timer to drive the animation instead, since this saves you from having to worry so much about Swing threading issues.
Perhaps .repaint() needs to be passed something to work. Often animations will take place on a canvas then you would update that. The update method would have to be made separate with all of the things you wish to update.
canvas.update()
public void update(){
what it is you wish to update
canvas.draw()
}
I hope this helps. EDIT so your canvas is your JFrame
I've written a program which displays balls in a window which are moving and which absorb each other with a certain probability when getting in contact.
The current version works, the balls's movement is been calculated every time the paintComponent method is (implicitely) invoked:
public class ColliderPanel extends JPanel {
...
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// calculate balls's movement
Random r = new Random();
ListIterator<Ball> it = cp.getColliderPanel().balls.listIterator();
Vector<Ball> ballsToRemove = new Vector<Ball>();
while (it.hasNext()) {
Ball b = it.next();
b.move(1.0 / 60.0);
b.collideFrame(cp.getColliderPanel().getSize());
ListIterator<Ball> it2 = cp.getColliderPanel().balls.listIterator(it.nextIndex());
while (it2.hasNext()) {
Ball b2 = it2.next();
if (b.collide(b2)) {
if (r.nextDouble() < 0.5) {
if (b.m > b2.m) {
b.swallow(b2);
ballsToRemove.add(b2);
} else {
b2.swallow(b);
ballsToRemove.add(b);
}
}
}
}
}
cp.getColliderPanel().balls.removeAll(ballsToRemove);
try {
Thread.sleep((long) (1000.0 / 60.0));
} catch (InterruptedException e) {
e.printStackTrace();
}
for(Ball b : balls) b.draw(g);
repaint();
}
...
}
Now I want to outsource the calculation of the balls's movement to a second thread. I tried to create another class SimulateBallsMovement implements Runnable which does the calculation in the overriden run method and created a new Thread in ColliderPanel, which has SimulateBallsMovement as Runnable-object.
public class ColliderPanel extends JPanel {
private Thread simThread = new Thread(new SimulateBallsMovement());
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// calculate balls's movement
// what to to here? how to synchronize the painting and the calculation?
for(Ball b : balls) b.draw(g);
repaint();
}
...
}
My problem is that I don't know how to synchronize the painting of the balls and the movement calculation? Does ColliderPanel even need the Thread as a member? I just found tutorials on how the synchronize two threads which invoke the same method, but what do I want to do here?
The main thing to remember with Swing is that almost none of the Swing methods should be called from any other thread except the Swing Event Dispatch Thread (EDT).
The EDT is what sits in a loop, waiting for key presses, mouse clicks, and other events, and calling your handlers each time an event happens that interests your program.
Whenever any of your other threads wants to do something that will affect the GUI, it should call the SwingUtilities.invokeLater(r) method where r is some Runnable object. The invokeLater(r) method will post an event containing r to the event queue, and the EDT will handle the event by calling r.run(). The r.run() method can then safely call whatever Swing methods you need it to call.
This looks like classic producer consumer scenario. The thread which calculates ball movements is producer and the thread which paints them is consumer. Check out these tutorial on the topic: http://www.tutorialspoint.com/javaexamples/thread_procon.htm or https://docs.oracle.com/javase/tutorial/essential/concurrency/guardmeth.html
One suggestion is to move the calculations into a swingworkers background processing method and calling repaint in done method of the worker.
To simplify the use of the AWT thread mechanism, and async component data fetching and component enable/disable while loading data, I wrote the ComponentUpdateThread, a long time ago. It makes it terribly easy to do updates of data and get the right things done in the right thread context.
https://github.com/greggwon/SwingUtil/blob/master/java/main/src1.5/org/wonderly/swing/ComponentUpdateThread.java
new ComponentUpdateThread( button1, button2 ) {
}.start();
is the basic premise of how you use it. All listened components will recursively be traversed and disabled by the actions of start(). There are three methods that you can implement.
The first one, setup(), is invoked by an AWT event thread, and should do anything to components (aside from disabling things that the cons parameters will make happen). This maybe simple things like emptying a list model etc.
The construct() method is invoked by an async, random thread. This method should "go get the data" to be used to populate controls, and put it into an appropriate container structure that it will return.
Finally, finished() is invoked by an AWT Event thread after construct() returns, and it should call getValue() to get the returned value from construct() activities, and then push that data into models/components as appropriate. finished() needs to call super.finished() at the right moment to "enable" the components passed into the cons. You can then disable things conditionally such as last selection in a list, options in checkboxes etc, and then return.
Here's an example of these methods taken from the javadocs. This shows the use of older APIs and doesn't include the fact that with generics, you can now make construct() a generic method with getValue() returning the same type. I have a version of this code that does all kinds of things that have been added more lately into Java.
This code is just to demonstrate the concepts around separation of thread use into separate methods so that you don't have to use SwingWorker directly, all over the place, but can use a more generic mechanism such as this.
My latest version of this code, includes the ability to chain together and next invocations so that more complex data retrieval and population can occur.
Ultimately, it would be really nice to just provide a ModelUpdater class that you could provide the component and any related model details to so that there was a compartmentalized use of data sourcing from remote access mechanisms.
public void setup() {
super.setup();
list.setEnabled(false);
list.clearSelection();
}
public Object construct() {
try {
Vector v = remote.getData();
Collections.sort( v );
return v;
} catch( Exception ex ) {
reportException(ex);
}
return null;
}
public void finished() {
try {
Vector v = (Vector)getValue();
list.setListData(v);
} finally {
super.finished();
list.setEnabled(true);
edit.setEnabled(false);
del.setEnaled(false);
}
}
I'm new to Java. I need help figuring out some of the code I'll be displaying below. The point of the code is to simply create an applet which displays a ball moving from left to right using a change in X position. I have began following a tutorial for applets from a website which made this code available to me (http://www.javacooperation.gmxhome.de/BallBewegungEng.html). Basically, I need someone to explain to the following methods and their contents: the start method (what is a thread? I'm aware it's an object, but what purpose does it serve here?). The run method (what exactly am I doing when I set the thread priority to MIN/MAX? Why does this method call the repaint() method even when no such method has been created?). Lastly, the paint method (what exactly is the g.fillOval line doing and how?). I've tried googling these things, but I'm having a hard time understanding understand the jargon that I see with most answers. I need things explained in a more simplistic way so that I may understand the jargon later on.
Thanks for any help in advance. The code:
import java.applet.*;
import java.awt.*;
public class MovingBall extends Applet implements Runnable
{
int x_pos = 10;
int y_pos = 150;
int radius = 20;
public void init()
{
setBackground (Color.blue);
}
public void start()
{
Thread th = new Thread(this);
th.start();
}
public void stop()
{
}
public void destroy()
{
}
public void run()
{
Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
while(true)
{
x_pos++;
repaint();
try
{
Thread.sleep (20);
}
catch(InterruptedException ex)
{
}
Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
}
}
public void paint (Graphics g)
{
g.setColor (Color.red);
g.fillOval (x_pos - radius, y_pos - radius, 2 * radius, 2 * radius);
}
}
A thread is something you use when you want to run multiple pieces of code at the same time, without interrupting the other threads. In this case you use the thread to repaint the screen and pause the loop without affecting the rest of the program.
The run method is overriding from the Runnable object that you pass to the thread to run. When you create a thread, you pass it a runnable object with a run method defined, which will run when the thread starts.
The repaint method is not defined in this class, however it is defined in the parent class(Applet), so you can call it in this class just fine.
The paint method is overriding from Applet as well, so you are defining what the applet will do when it runs the paint method.
I have a component (JPanel) inside a Window.
I always get false when calling panel.isShowing(),
when calling from a windowGainedFocus() event (when the parent window gets focus).
I assume that when the windowGainedFocus() event is called, the painting of the JPanel within this Window had not been finished yet.
I was trying to place that call isShowing() on the paint() method of this Window,
but I always get isShowing() = false.
Is there a way I could get an event when the JPanel is fully shown on screen and the isShowing() method will return true ?
Thanks
You should probably best approach this with a hierarchy listener on the panel itself:
panel.addHierarchyListener(new HierarchyListener() {
public void hierarchyChanged(HierarchyEvent e) {
if ((HierarchyEvent.SHOWING_CHANGED & e.getChangeFlags()) !=0
&& panel.isShowing()) {
//do stuff
}
}
});
If you don't want an event but have some specific code that needs to be run after your component has been drawn, you can override addNotify(), which gets called to make the component displayable. Example:
public void addNotify()
{
super.addNotify();
// at this point component has been displayed
// do stuff
}
You component will be fully displayed after you receive WindowListener.windowActivated. You will also run into timing problems and race conditions trying to assign focus before the windowActivated event.