Jr Java-er Wants to Pass Params to Paint - java

I'm currently able to draw rectangles, elipses, and lines in Java by means of adding a component that extends JComponent in which I modify a paintComponent method:
public class myComponent extends JComponent
{
public void paintComponent(Graphics g)
{
/* do simple draw stuff */
}
}
I also know how to have my class extend either JApplet or JPanel and then draw in a paint method:
public class myClass extends JPanel
{
public void paint(Graphics g)
{
/* do simple draw stuff */
}
}
But, both of these methods suffer from not allowing me to pass them parameters. In the case of a multiframe animated sprite, I could conceivably have some external variable that it reads to determine the frame number and then internally draws only the appropriate "sprite" contents based on that frame number, but I'd prefer to be able to pass the frame number to it directly. Unfortunately, not only do I not know where this is called from, I don't know where to the the Graphics g that it requires as input.
There may be a better way to accomplish what I want, to directly communicate with the draw routine to tell it to draw only what I want, whenever I desire, but I don't know how to accomplish this.
If such a method is possible, how would that be done?
If it is better to use the existing paint or paintComponent methods, how can I best pass additional information to them?
Apparently I wasn't clear in what I asked. I wish to have a component or other entity that has its own paintComponent or paint method, inside of which, based on either a frameNumber parameter that is passed to it, or apparently-more-likely, a class property such as frameNumber that it can access, the method determines which frame of a sprite to draw.
Importantly, though, I wish to be able to re-call paint or paintComponent to redraw the sprite when the frame number changes. My big confusion comes in not knowing how to re-call the method, which, to the best of my understanding, only is called when the frame is resized or otherwise redrawn.
So, how can I redraw my component/object/entity, frame-by-frame?

Firstly, don't override paint, use paintComponent.
Secondly, you need to define some kind of model which records the state of all the graphical objects. When paintComponent is called, you then need to render that state. Instead of trying to pass parameters to the paint methods, you should have a method which allows the paint methods to access the model (ie getModel) which is passed to the component at some earlier time.
Then the update engine would update the model and the component would paint that model
For an example ... Use a timer when a key is pressed

I could conceivably have some external variable that it reads to determine the frame number and then internally draws only the appropriate "sprite" contents based on that frame number
Your class would need to have some internal state, i.e. instance variables.
You can then inspect those within the paint method.

Think "member variables":
public class MyClass extends JPanel {
private final int frameNumber;
public MyClass() {
this(0);
}
public MyClass(int f) {
this.frameNumber = f;
}
public void paint(Graphics g)
{
if (this.frameNumber == x) {
/* do simple draw stuff */
}
}
}

Related

Local repainting in JPanel

How can I repaint local field on JPanel? I'm writing a snake game. When the snake moves to the next cell, we need to repaint only changed cell (not whole JPanel). Cell can throw PropertyChangeEvent object and then I can call repaint(x, y, h, w) method. Is this the right way?
First of all, I'll assume that you really do want to use a panel instead of a table, though I think you may want to look into the JTable component because that may be better suited to your application.
The answer to your question is that you shouldn't explicitly request a repaint for a cell. Instead each cell should be represented as an instance of a JComponent subclass that contains code like the following:
public class SnakeGameCell extends JComponent {
private boolean snakePresent;
public boolean isSnakePresent() {
return snakePresent;
}
public void setSnakePresent(boolean present) {
if (snakePresent != present) {
snakePresent = present;
repaint();
}
}
}
In other words, each component should be responsible for knowing when it should be repainted and for making that happen when appropriate. It's rare to find a situation where it's appropriate for repaint() to be invoked "externally". To put it another way, don't have the controller class responsible for initiating the repaint -- make the thing (component) that needs to be repainted decide for itself.

Graphics G in another method

I have a canvas and I want to draw a rectangle based on a JButton click.
So in other words
private void jb_drawActionPerformed(ActionEvent evt) {
// draw a rectangle method
}
Basically, how do I encorporate the pain(Graphics g) thingamagic in that method? or should I make the rectangle an object and call a "render" method from that object? If so, can someone link a tut?
private void jb_drawActionPerformed(ActionEvent evt) {
myrectange.render(x,y); // ????
}
General Comments and Recommendations
One way: Draw in a BufferedImage getting your Graphics object from the BufferedImage, and then draw the BufferedImage in the JComponent's (JPanel's?) paintComponent method.
If you do it this way, you will use the Graphics object directly obtained from the BufferedImage to do your drawing.
Don't forget to dispose of this Graphics object when done with it.
The actual drawing though is done in the JPanel's paintComponent(...) method (see below).
Another way: change a class field, and have the JPanel's paintComponent method use that field when painting. For instance, if you want to paint multiple Rectangles, create an ArrayList<Rectangle> add to it in your ActionListener, call repaint() and have the paintComponent(...) method iterate through the List, drawing rectangles held by it.
Note that the paintComponent(...) method is never called directly but rather you suggest to the JVM that it call it by calling repaint().
Never dispose of a Graphics object that was given to you by the JVM, for instance the one passed into the paintComponent(Graphics g) parameter.
Links
Basic Tutorial: Lesson: Performing Custom Painting
More advanced concepts: Painting in AWT and Swing

How to construct my graphic structure in Java using Swing?

I was wondering if you could help me out with the structure of my program. I'm making a game with Java and I have 2 classes. 1 class is a graphics class that extends JFrame with a paint method:
Graphics Class
paint() and calls various objects that use JFrame as a parameter.
Inside the class is a subclass that implements MouseListener and Mouse Motion Listener which interacts with paint method.
Canvas Class
I was planning to embed the first class into a larger canvas class that would have buttons, panels, and so forth so essentially use the class as a smaller (sub-program) inside a larger program.
Is this possible/ am I doing this the right way. Whenever I try to call the graphic class inside the canvas class, the graphic doesn't turn up.
public Canvas(){
graphic = new Graphic(name);
}
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Canvas canvas = new Canvas();
canvas.setDefaultCloseOperation(EXIT_ON_CLOSE);
canvas.setSize(1500, 1500);
canvas.setVisible(true);
}
}
Any help/guidance would be appreciated. I just want to mainly to know if I'm thinking about graphic programming correctly.
Canvas is not "Window". In order to display anything on the screen, you components must be added to a window delegate.
I would, personally, avoid overriding the paint methods of top level containers. The main reason for this is top level containers are not double buffered and it makes your application less portable. It's much easier to add a component to other components, a frame is pretty final.
I would also use JPanel over Canvas, simply because JPanel is double buffered.

How can I ensure correct drawing order in an OverlayLayout?

I am using a JPanel with an OverlayLayout to draw two unrelated components on top of each other. Specifically, I have a transparent component which contains my own line drawings, and beneath that, I am using a JMapViewer component, which displays OpenStreetMap tiles. This works.
Except when the JMapViewer loads tiles asynchronously. In that case, it calls repaint() on itself when the loading is finished, and it draws itself over my line layer. My line layer cannot know this, since it cannot know when the JMapViewer chooses to repaint itself.
Now I would have expected the JPanel to repaint my line layer when the map layer repaints, since it knows the correct drawing order and knows that my line layer has to be repainted. But it doesn't do this.
How would you solve this?
JMapViewer implements TileLoaderListener and simply calls repaint() when loading is finished. You should be able to update the map and then forward the event to your layer, as suggested below.
MyViewer map = new MyViewer();
...
private class MyViewer extends JMapViewer {
#Override
public void tileLoadingFinished(Tile tile, boolean success) {
super.tileLoadingFinished(tile, success);
lineLayer.repaint();
}
}
it calls repaint() on itself when the loading is finished,
Call repaint() on the parent panel instead.
This depends on how the JMapViewer repaints itself. If it just updates its content, the parent(s) might not even notice that something has changed.
I don't know if this is the best approach, but it's the only one I can think of. You could replace the RepaintManager for the JMapComponent with a custom one that also manages repaints of your overlayed component. That way, you can guarantee that your overlayed component always gets repainted last.
...do this from the AWT event thread via SwingUtilities
RepaintManager myManager = new RepaintManager() {
public void addDirtyRegion(JComponent c, int x, int y, int w, int h) {
....implemnt code here to guarentee your top level component gets repainted whenever 'c' is the JMapComponent
}
}
RepaintManager.setCurrentManager(myManager);

How do I initialize a Graphics object in Java?

this is the code:
import java.awt.*;
import java.applet.*;
public class anim1 extends Applet{
public void paint (Graphics g)
{
g.drawString("",400,300);
}
public static void main(String ad[])
{
anim1 a=new anim1();
Graphics g1;
a.paint(g1);
}
}
It says that g1 is not initialized. But how do I initialize an abstract class?
Well there are two issues here 1:
Graphics g1;
a.paint(g1);
And you are getting the error that G1 is not initialized. That's because the variable g1 is never set to anything, and that causes a compile error. To get the code to compile, you would need to, at the very least do this:
Graphics g1 = null;
a.paint(g1);
However, that obviously won't help you out too much. You'll get a NullPointerException when you try to run your code. In order to actually cause your graphics to draw you need to this:
anim1 a=new anim1();
Graphics g1 = anim1.getGraphics();
a.paint(g1);
However, that still won't work because Anim1 will not appear on the screen. To get it to appear on the screen you need something like:
import java.awt.*;
import javax.swing.*;
import java.applet.*;
public class So1 extends Applet{
public void paint (Graphics g)
{
g.drawString("hello",40,30);
}
public static void main(String ad[])
{
JFrame jp1 = new JFrame();
So1 a=new So1 ();
jp1.getContentPane().add(a, BorderLayout.CENTER);
jp1.setSize(new Dimension(500,500));
jp1.setVisible(true);
}
}
Now notice, we don't actually call the paint() function ourselves. That's handled by the awt, which actually picks the graphics context, and calls our paint function for us. If you want, though, you can pass in any graphics object you want and ask it to draw on to that. (so if you want to draw your component onto an image, you can do it)
(note, I changed the classname from anim1 to So1)
An applet doesn't need a main method like a regular Java application does. I'd recommend starting with Sun's Applets Tutorial. In particular you may want to skip ahead to the section Life Cycle of an Applet to see how the Graphics object is handled within the applet.
All you need to do is simply remove the main method like so:
import java.awt.*;
import java.applet.*;
public class anim1 extends Applet {
public void paint (Graphics g) {
g.drawString("Hello",100,100);
}
}
instead of a call to paint(Graphics g) you need to invoke the repaint or update method. But for this your class must belong to the hierarchy in the java.awt.Container.
For your class you have overriden the Paint method and in the main you are trying to invoke the paint method. Instead of paint you need to invoke the repaint or update method (if your class is in the hierarchy of java.awt.Container) and the event dispatching system of java invokes your overridden paint method itself.
You should manipulate the graphics of a component within the paint method and invoke repaint() or update(), but not the paint method directly.
Start here for some more information.
You dont initialize a Graphics object.
You get the graphics object from a component via Component#getGraphics() method.
In your particular case I think repaint() is all you need!!
You don't, you use getGraphics, but, if you really want to initialize it, then type new Graphics(){}; And have fun filling all the abstract methods. Most of the times just putting code in paint(g) should do, you need to remember to set your applet visible, and usually, it should be the last line in your constructor or even outside it, I have made a mistake once where I made visible and then initialized a bunch of variables, it showed a black screen for a while.

Categories

Resources