I'm really confused with the program flow for how the paintComponent function works within my JPanel. Ideally I'd like to have access to the Graphics object to draw stuff from other functions based on my program flow. I'm thinking along the lines of the following:
private Graphics myG;
public void paintComponent(Graphics g) {
super.paintComponent(g);
myG = g; //I want a graphics object that I can just draw with.
//Should I just initialize to myG = new Graphics(); or something?
//private Graphics myG = new Graphics(); does not seem to work
}
//this is what's getting called, where I want to call other functions that
//can use myG to draw graphics as I please
public void startPanelView() {
myG.drawRect(350, 20, 400, 300); //doesn't work
otherFunctionForGraphics(); //which will also use myG.
}
I hope I've made myself clear here. I just want to be able to do use the Graphics class as I please. Currently I can only do stuff like g.drawRect(...) inside of the paintComponent() function. This could work for my purposes but I'd like more flexibility.
Thanks.
EDIT - Alright, I understand that I should not try and reference a Graphics object outside. But how should I go about separating application logic from the paintComponent function? Right now this class is looking a little messy because I have the following:
public void paintComponent(Graphics g) {
if (flag1 == true) {
//do some graphics stuff, that I would prefer to be in another function
}
if (flag2 == true) {
//do some other graphics stuff, again, which I would prefer
//to be in another function
}
//... etc. More of these cases.
}
And basically the paintComponent function is getting stupidly long and complicated for me, so I would like to break it up in whatever ways possible.
Call repaint from your startPanelView method on the panel object. You should never act on the graphics object outside of the paint methods, nor should you maintain a reference to the graphics object for use outside of the paint method.
The others are right that you cannot keep the Graphics object as a member variable, but if the problem is that your paintComponent method is getting too long, you can still pass the Graphics Swing gives you as an argument to other methods:
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawRect(350, 20, 400, 300);
doSomeStuff(g);
if (flag1) {
doMoreStuff(g);
} else {
doDifferentStuff(g);
}
}
I'd like to have access to the Graphics object to draw stuff from other functions based on my program flow. I'm thinking along the lines of the following:
No, you shouldn't do that in a standard Swing application as the Graphics object obtained will not persist and your drawings will disappear whenever the JVM or the operating system decide that a repaint is necessary. Consider creating Lists or other collections of objects to be drawn (such as from classes that implement Shape) and iterating through these collections in the paintComponent method. Another technique is to draw on a BufferedImage and then display it in your paintComponent method.
basic JComponent for Painting/Custom Painting/2D Graphics in Swing or for Image/ImageIcon too, is JLabel,
don't call another viod(s) or class(es) from 2D Graphics or CustomPainting, some valuable examples are here or here, search on this forum for excelent suggestions about Custom Painting and 2D Graphics
Related
what does the paint method do after receiving the object created from the Graphics class as a parameter?
as for example in this code:
public class unaClase extends Applet{
public void paint(Graphics g){
g.drawRect(0, 0, 400, 200);
}
}
try to trace the source to see its code and thus be able to understand what it does, but it does not show me anything
What I want is to know what makes paint with the parameter it receives?
PD: I know that apple is dead, I just want to understand well what is happening, what it does
when I use the paint method (as in the example code), I'm technically overwriting it (unless I had used super.paint ...), and then its code would be the one I just defined; so my question is, how does paint know what to do with the parameter (Graphics) that I'm going through?
The actual term is overriding. And the first thing you would normally do is call super.paint() to the parent version. Graphics (or Graphics2D which has additional methods but needs to be cast) allows one to use those methods to draw, rotate, and in general manipulate pixels. It is handled internally using native method calls that are supported by the OS.
If you are going to paint you should do it in a JPanel and override paintComponent(Graphics g). Check out the tutorials on painting at https://docs.oracle.com/javase/tutorial/index.html
So, lets say I have some game, take Pong for example. Obviously, you generally speaking don't want to mix game-logic into graphics classes, so the class for Ball or Paddle is sepearte from the JPanel which actually draws them. Ball has the movement logic for the ball, its current location, hit detection, etc. However, is it bad practice for me to use graphics classes from Swing and awt in my Ball class? For example, if I were to use a java.awt.Rectangle to determine the hitbox. Even though I am not drawing it in this class, I am using it. Or if I were to use Java.awt.Point to store coordinates.
By the way, the reason I am asking is because I have been told many times on this site not to mix graphics with other parts.
Using Rectangle in non-graphics class: (Is this bad practice?)
public class Ball {
static Rectangle hitbox = new Rectangle(0,10,20,20);
static void checkHit() {
if(hitbox.intersects(Paddle.hitbox) //do something
}
}
My Graphics class:
public class DrawMyStuff extends JPanel {
void paintComponent(Graphics g) {
super.paintComponent(g);
setBackground(Color.BLACK);
Graphics2D g2d = (Graphics2D) g;
g2d.draw(Ball.hitbox);
}
}
I'd say that for most part, you shouldn't do this.
Exceptions from the rule
There are however a (small) set of helper classes inside that package that are actually only data holders of a "nice" type. Why invent wheels when you already got them? These would be "okay to use" in my world.
Dimension
Insets
Point
Rectangle (and all other Shapes like Polygon, Area and so on)
These can be used to describe graphical problems while they are not directly coupled to on-screen-resources.
This question already has an answer here:
paint() in java applet is called twice for no reason
(1 answer)
Closed 8 years ago.
This is my code:
public class Circles extends JApplet{
public void paint(Graphics g) {
Scanner in = new Scanner(System.in);
Random rand = new Random();
int position = rand.nextInt(200);
System.out.println(position);
}
}
and the output was:
199
152
What's happening is after it prints out the "position" variable, it jumps back and starts again. I cant figure out why it does this.
As MadProgrammer noted, you're trying to paint to a JApplet, which not only doesn't have a paint method, but is a top-level container like a JFrame and a JDialog. You don't want to paint to a top-level container. Put it in a JPanel or some lower level container that allows you to override the paintComponent method.
You do not want to put that in your paint method. Also, use the paintComponent method if you're using Swing (which you are, it's the ones with the J at the front of their names).
And make sure you call the original parent method of paintComponent with super.paintComponent(g); as your first line in the paintComponent method.
So it will look like:
public void paintComponent(Graphics g) {
super.paintComponent(g);
//anything else you want goes here
//don't get in the habit of creating Objects in here
//and don't do anything that's not event-driven
}
Don't put anything other than painting stuff in your overridden paintComponent method. You should never put user input into it and avoid creating objects because not only is there probably a better way to do it, creating objects can take a lot of time which will be terrible for a method that's called in quick, repeated succession.
You don't have control over when your application is repainted. The paintComponent/paint methods are called continuously, and your design should be based around that.
Design your GUI to be event-driven, not sequential.
Can somebody explain to me why this isn't working?
The error seems to be inside the Gen class but
I think it may something to do with BoxMan.
The error says cannot find symbol- variable g.
I also tried putting in ints and doubles but it gives me: Required (Java.awt.Graphics) Found(int) / (double). So how can fix this? I've looked everywhere and can't find the answer. Help a beginner!
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.WindowConstants;
import java.lang.Object.*;
public class JFrame_Test
{
public static void main (String [] args)
{
Gen Gen= new Gen (1500,1000,"A Name"); // this gives parameters for a Jframe later.
}
}
{
Gen (int size1, int size2, String title)
{
JFrame aFrame = new JFrame (title);
aFrame.setSize(size1,size2);
aFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
aFrame.setVisible(true);
//aFrame.getContentPane().add(new Canvas());
//Was trying to get it to work with a canvas
BoxMan.paint (g); // the error pops up here.
}
}
public class BoxMan
{
public Graphics2D g2;
public void paint(Graphics a )
{
g2 = (Graphics2D) g; // i even tried declaring "g" here.
g2.drawRect (10, 10, 200, 200);
}
}
Rather then repeating what Jantomedes has already said (which is all excellent), I'm going to expand on it...
Painting in AWT and Swing is done through the paint sub system. This system makes decision about what and when to paint and calls the appropriate methods to update the components on the screen.
See Painting in AWT and Swing for more details
Graphics is an abstract concept in Java and is used to standardise the concept of painting to a variety of possible outputs, including the screen, image and printers. Apart from images, you can't create your own Graphics context, you need it to be supplied by the system
Check out Perfoming Custom Painting in Swing for details
The Graphics object isn't declared anywhere. If you want to draw on your JPanel you should rather create a class extending JPanel and there add draw() method which will get an "automated" Graphics object.
Eventually you can create your own Graphics object but you didn't do that anywhere in that code. Your BoxMen class is very messy. You have to decide if you use Graphics object argument under paint() method or declare it yourself. I'm assuming you try the second one, if so, you should change the g to a (there isn't a g variable anywhere in BoxMen class). You can also get rid of the field g2 and use a local variable instead.
The error pops up because Java doesn't know what you mean by g (it isn't declared anywhere). It depends on you if you want to use the JPanel's Graphics or your own.
is there a possibility to draw a JPanel on a specific location op a Graphics (or Graphics2D) object?
I override the paint method of my canvas, and call panel.paint(g) in there, but it does not work the way I woul hope.
#Override
public void paint(Graphics g){
Dimension size = panel.getPreferredSize();
panel.setBounds(pos.x, pos.y, size.width, size.height);
panel.paint(g);
}
the size object is correctly defined as I would wish, so that's not the problem. Also, the pos contains a correct x and y on the screen.
You should probably be using paintComponent instead of paint, since the latter is the AWT method, and the former is the Swing method.
One nice thing about Swing's paintComponent is that the Graphics passed is actually always going to be a Graphics2D, so you can:
Graphics2D g = (Graphics2D)lg;
Now you can use the getTransform to save the old transform, then modify the transform of the Graphics2D using either setTranform or the scale, translate and rotate methods. Don't forget to restore the old transform, or you'll likely fudge the next thing being drawn by that context.
I'll throw in that, depending on the circumstance, drawing to a BufferedImage might be appropriate. You can get a Graphics context using BufferedImage.getGraphics(). Then you can draw the BufferedImage's context by whatever means suit you.