so I have class Board that extends JApplet and in it's constructor I make a JPanel that I'll later draw boxes on, but when I try to do getGraphics it returns null :/
JPanel panel;
public Board(int x, int y, int wolfNumber, int hareNumber){
this.x=x;
this.y=y;
wolvesCoords = new int[wolfNumber][2];
haresCoords = new int[hareNumber][2];
panel = new JPanel();
panel.setVisible(true);
add(panel);
}
public synchronized void write(int xx, int yy, Color c){
int width=panel.getWidth()/x;
int height=panel.getHeight()/y;
Graphics g = panel.getGraphics();
System.out.println(g);
g.setColor(c);
g.drawRect(xx*width, yy*height, width, height);
g.fillRect(xx*width, yy*height, width, height);
}
public void paint(Graphics g)
{
super.paint(g);
}
It gives nullpointerexception at line g.setColor(c) as g is null.
You are using the Graphics object wrong. Instead of calling write from wherever you call it, instead override paintComponent. You could do something like:
private int xx;
private int yy;
private Color c;
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if(c != null) {
int width=panel.getWidth()/x;
int height=panel.getHeight()/y;
g.setColor(c);
g.drawRect(xx*width, yy*height, width, height);
g.fillRect(xx*width, yy*height, width, height);
}
}
public void write(int xx, int yy, Color c) {
this.xx = xx;
this.yy = yy;
this.c = c;
repaint();
}
Yours is a common problem and question and is yet another reason why you shouldn't use a Graphics object obtained by calling getGraphics() on a component. Another reason you shouldn't do this is that if you are successful at getting a non-null Graphics object (which is only available after the component has been rendered), it will not persist, and your image can turn null if any repaints occur.
Instead do what the tutorials advise you to do: Draw with the Graphics object provided to you in the JPanel's paintComponent method. If you want to draw a fixed background, then do so in a BufferedImage, and then draw that BufferedImage in the paintComponent method.
Edit
You ask:
Why would I call drawing code in the paint method? I need to draw only when the method write is called, not when the app starts.
Because that is how Swing graphics is done, because doing it your way is rife with problems (which you're already experiencing). Again, don't guess at this stuff -- read the tutorials where it is all well explained for you.
Edit
You state in comment:
Actually this error shows up when I try to add override - method does not override or implement a method from a supertype. Could it be that I am extending JApplet?
Yes, exactly so.
I have to though
Yes, you have to have a class that extends JApplet in order to produce JApplets, but you don't have to and in fact shouldn't paint directly in them. Instead create a separate class that extends JPanel, and do your graphics inside of that class's paintComponent method. Then display that JPanel in your applet.
Related
Hello fellow programmers!
So to be honest here, i'm not sure if the title question is correct, and you will see why.
Before i explain what i do, and why, here is the code snippet:
JPanel playerPanel = new JPanel() {
public void paint(Graphics g) {
X = 1;
Y = 1;
g.drawImage(player.getScaledInstance(player.getHeight()/2, player.getWidth()/2, Image.SCALE_DEFAULT), X, Y, null);
}
};
So this a snippet from a custom class i made, and my question would be that, you see there is an X and Y variable, i can change their values , but that changes nothing on the impact of the actual program, my first question would be that can i change the X, and Y of this JPanel's image, and if so , how can i "refresh" the actual JPanel/Image so that it looks like it moved?
Some notes:
-the X, Y are global variables
-playerPanel is inside a procedure, and a global variable
-i can access X, Y since they are global variables from outside the class
I'm having a hard time actually writing down my problem... Hopefully you understand what i would like to accomplish.
You're main problem: Don't use an anonymous inner class if you want to give the class new mutable fields. Instead, create a separate class, it can be an inner class, but it can't be anonymous, give it fields that are needed with getters and setters. Also all that Luxx recommends is correct -- override paintCompoent, call the super method, don't declare the fields within a method...
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.JPanel;
public class PlayerDrawingPanel extends JPanel {
private int playerX;
private int playerY;
private Player player;
public PlayerDrawingPanel(int playerX, int playerY, Player player) {
this.playerX = playerX;
this.playerY = playerY;
this.player = player;
}
public void setPlayerX(int playerX) {
this.playerX = playerX;
repaint();
}
public void setPlayerY(int playerY) {
this.playerY = playerY;
repaint();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(player.getImage(), playerX, playerY, this);
}
}
There is no need to create global variables.
You can use setBounds(x, y, w, h) from Swing's JComponent to move and resize the JPanel.
Though, you have to keep in mind that a Component cannot draw outside its borders. Meaning that the Graphics object that is passed into paint(Graphics g) comes clipped and translated to fit the Component from it's parent.
So, to solve your case, you can either make your JPanel take over the whole area in which you want to draw by using setBounds() or you can you the LayeredLayout from your root panel to draw anywhere.
Let me exemplify the last solution. Consider frame to be your JFrame and playerPanel the JPanel that you overwrote the paint() method:
frame.setGlassPane(playerPanel);
frame.getGlassPane().setVisible(true);
Now your playerPanel is at the topmost layer of your application, covering the whole area. This means you can draw anywhere over anything.
Im trying to get the point of the cursor in the paint part and simply draw an oval. No luck though!
public void paint(Graphics g){
Point ComponentPoint = PaintPanel.getLocationOnScreen();
Point CursorPoint= MouseInfo.getPointerInfo().getLocation(); //gets cursor point
int ComPX = ComponentPoint.x;
int ComPY = ComponentPoint.y;
int CurPX = CursorPoint.x;
int CurPY = CursorPoint.y;
int FinalX = CurPX - ComPX;
int FinalY = CurPY - ComPY;
g.drawOval(FinalX, FinalY, 20, 20);
}
private void PaintPanelMouseDragged(java.awt.event.MouseEvent evt) {
//when mouse is moved over paintpanel
//PaintPanel.repaint();
not working
}
This is it without paint method, the image:
http://i.stack.imgur.com/VOyhr.png
You can't add code in the paint method like that. YOu would not reference the MouseInfo class in the paint method since you have no control over when the paint() method is invoked. You should be using a MouseListener and MouseMotionListner to do custom painting. Also, custom painting should not be done in the paint method.
See Custom Painting Approaches for two solutions.
how to turn several graphics objects in to one?
(this part of code should generate tetris figure, where generate() create a figure)
public void paint(Graphics g){
Figure f = generate();
int length = f.getX()[0].length;
for(int j =0; j<f.getX().length;j++){
int xr=xs+10;
ys = 0;
for(int i=0;i<length;i++){
if (f.getX()[j][i] == 1){
int yr = ys+10;
Rectangle p = new Rectangle(xs,ys,xr,yr);
g.setColor(f.getY());
g.drawRect(p.x, p.y, p.width, p.height);
g.fillRect(p.x, p.y, p.width, p.height);
//g.translate(xs+40, ys+40);
}
ys+=10;
}
xs+=10;
}
xs=0;
ys=0;
//g.setColor(Color.white);
//g.drawRect(45, 95, 55, 105);
}
Well, I think you are starting with Java 2D, since your code has some problems.
First of all, you always need to call the paint version of the super class. This should be done because the component needs to have a chance to render itself properly. Take a look.
#Override
public void paint( Graphics g ) {
// you MUST do this
super.paint(g);
// continue here...
}
If you are dealing with a JFrame you will override the paint method. If you are working with some JComponent child, like JPanel, you need to override the paintComponent method, which has the same signature of paint, but it is protected, not public. You can override paint too, but in these cases (JComponent and its children), paint is a method that delegates the paint work to three methods (paintComponent, paintBorder, and paintChildren), so the best option is to override paintComponent.
Another detail. The best way to work with graphics is to create a new graphics context based in the current one and dispose of it after using it. Take a look:
#Override
public void paint( Graphics g ) {
// you MUST do this
super.paint(g);
Graphics newG = g.create();
// or Graphics2D newG2d = (Graphics2D) g.create();
// do your work here...
newG.dispose(); // disposes the graphics context
}
The graphics context that is created using the create method is a copy of the current graphics context (with the same states), but changing it does not affect the original one, so doing this, you will not mess with the state of the original graphics context.
To finish, I think that you need to have a draw method in your figure that receives the graphics context. So, the Figure instance will be responsible to draw itself. Something like:
public class Figure {
// figure's members...
public void drawMe( Graphics2D g2d ) {
// do the draw work here...
}
}
public class MyFrame extends JFrame {
#Override
public void paint( Graphics g ) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g.create();
// let's suppose that figureList is a List<Figure> or a Figure[]
for ( Figure f : figureList ) {
f.drawMe( g2d );
}
g2d.dispose();
}
}
Of course, you can create a new graphics context for each Figure if its draw method changes the graphics context too "deeply", like doing translations and rotations. You just need to dispose the new ones after using them.
I assume you are trying to put multiple components inside of an enclosing component so that you can move/manipulate them together.
One suggestion would be to add each of your objects to a panel object, like JPanel.
However it is somewhat unclear what you are trying to achieve exactly.
I have a problem making an inner class that extends from JPanel to draw anything on it. I overrided the paintComponent method, and whatever I set to draw from here works fine, but using another method to draw does not work.
Here is my inner class code:
private class Plot extends JPanel {
public Plot() {
this.setBackground(Color.WHITE);
}
#Override
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
Graphics2D graphic2d = (Graphics2D) graphic;
graphic2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphic2d.drawOval(0, 0, this.getWidth() - 1, this.getHeight() - 1);
}
public void drawTitle(final String title) {
Graphics2D graphic2d = (Graphics2D) this.getGraphics();
graphic2d.setColor(Color.red);
graphic2d.drawString(title, 1, 10);
}
}
Notice the drawTitle method. I just want a custom text to be shown. In my outer class which extends from a JFrame I create an instance of this inner class like this:
private Plot plot;
/** Creates new form GraphicsView */
public GraphicsView() {
initComponents();
plot = new Plot();
this.add(plot, BorderLayout.CENTER);
}
public void drawTitle(final String title) {
this.plot.drawTitle(title);
}
I even create a convenient method to call the inner class drawTitle method (with the same name). I do this because I want this JFrame outer class to be visible on button click, once it is visible (which ensures the init of the graphics) I call the outer class drawTitle which in turn calls the inner class method with the same name and where the string show be drawn... but this does not work, I can't see it on the panel. Here is my button click event:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
GraphicsView view = new GraphicsView();
view.setVisible(true);
view.drawTitle("Hello");
}
Thanks in advance, I will appreciate any help. :)
I overrided the paintComponent method, and whatever I set to draw from here works fine
Well, there is the answer to the question. Do all your drawing from the paintComponent() method.
but using another method to draw does not work.
Don't use the getGraphics() method. You should only ever use the Graphics objects passed to the paintComponent() method.
You can't control when Swing repaints() a component. Therefore every time the component is repainted the paintComponent() method is invoked and your other custom painting code will be lost.
Just call the drawTitle() function in the paintComponent override and pass the graphics as an argument. Something like this:
#Override
public void paintComponent(Graphics graphic) {
super.paintComponent(graphic);
Graphics2D graphic2d = (Graphics2D) graphic;
graphic2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
graphic2d.drawOval(0, 0, this.getWidth() - 1, this.getHeight() - 1);
drawTitle(graphic, title);
}
public void drawTitle(Graphics g, final String title) {
Graphics2D graphic2d = (Graphics2D) g;
graphic2d.setColor(Color.red);
graphic2d.drawString(title, 1, 10);
}
Also try to make the title a data member of the class. This might prove helpful later.
I have a JComponent with a listener on it. On the JComponent, I draw a big image and the mouse listener adds small images where clicks occur (one big map on which I add some dots).
How can I programatically draw something outside the paintComponent method?
public void paintComponent(Graphics g) {
Graphics2D g2 = (Graphics2D) g;
g2.drawImage(img1, 0, 0, this);
g2.finalize();
}
private MouseListener listener;
public void initListener() {
myCanvas = this;
listener = new MouseAdapter() {
public void mouseClicked(MouseEvent e) {
myCanvas.getGraphics().drawImage(img,e.getX(),e.getY(), myCanvas);
}
};
addMouseListener(listener);
}
My problem is with this:
public void drawDot(int x, int y){
myCanvas.getGraphics().drawImage(img, x, y, myCanvas);
}
It doesn't do anything. I have tried repaint().
You can't do this. All drawing occurs in the paintComponent() method. What you should do is build a model that represents what you want to draw, and modify the model in your mouse listener. Then call repaint() to ask that this component be redrawn when the model is modified. Inside your paint() method render the full paint from the model. For example:
List<Point> pointsToDrawSmallerImage = new ArrayList<Point>();
...
listener = new MouseAdapter() {
public void mouseClicked(MouseEvent evt ) {
pointsToDrawSmallerImage.add( evt.getPoint() );
repaint();
}
}
...
public void paintComponent(Graphics g) {
g.clear(); // clear the canvas
for( Point p : pointsToDrawSmallerImage ) {
g.drawImage(img, p.x, p.y, myCanvas);
}
}
You have to manage the drawing inside the paintComponent method. Java Graphics is not stateful, you have to take care of what you actually need to draw whatever you want inside the method. Every time the paint method is called, everything must be drawn again, there is nothing that "stays" on the canvas while adding other components
This means that you should store a list of elements that the paint method will take care to draw, eg. ArrayList<Point> points, then in paint method you should iterate them:
for (Point p : points)
draw the point
so that you just add the point to the list with the listener and call repaint.
You can find guidelines for Swing/AWT drawing here..
A particual API has the behavior you would like to have though, it is called Cocos2D and it has a port for Android/Java that you can find here.
that is not how draw works, the draw method paints everything which is in the method itself on every repaint,
that means if you call a method to draw something once, it will only be drawed for one repaint cycle and that's it.
if you want something t be drawn on click you have to add it on on click to a collection and draw the whole collection in every paint cycle, so it will stay permanently.