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
Related
I see a lot of people casting the Graphics type to a Graphics2d type inside their Paint method in an effort to have more functionality over the images they draw. Is it not possible cast the graphics type to a graphics2d type outside of the paint function? To me this screams performance issue because every time the paint method is called (i.e every frame) you are needlessly casting to a Graphics2D type every single time.
Also, does Java do any optimization whenever the paint method is called and the same screen is being drawn again? For example if you are only moving one element on the screen then you will generally only need to update that element. It seems java redraws and re-processes the whole screen every time the paint method is called. To me this all seems unnecessarily processing intensive.
Example code:
public void paint(Graphics g) {
AffineTransform transformer = new AffineTransform();
transformer.translate(5,5);
transformer.scale(2,2);
Graphics2D g2d = (Graphics2D)g;
g2d.setTransform(transformer);
// draw to g2d.
}
You state:
To me this screams performance issue because every time the paint method is called (i.e every frame) you are needlessly casting to a Graphics2D type every single time.
There is minimal cost to this, and so I wouldn't worry about it. Instead profile your program and concentrate on the bottle necks that the profiler shows you matter.
Is it not possible cast the graphics type to a graphics2d type outside of the paint function?
No.
Also, does Java do any optimization whenever the paint method is called and the same screen is being drawn again? For example if you are only moving one element on the screen then you will generally only need to update that element. It seems java redraws and re-processes the whole screen every time the paint method is called. To me this all seems unnecessarily processing intensive
I don't think so. What I've done is to 1) create a BufferedImage to display my static images, and then draw directly my dynamic images, and 2) if need be, limit the area being drawn by using the repaint(...) method overload that accepts a Rectangle.
Right now I have a main game loop that constantly redraws the screen. Since I need to slow this thread down but continue to draw other items at a faster rate I need to make a new thread. The problem is I am not sure how to go about making a new thread that also draws to the screen I know how to make a new thread, I am just stuck on how to implement the Graphics2D drawing in the new thread. For example I have the code below which is the typical starting point and then there is the draw method defined in the other class that directs what and when to draw. If I wanted to branch off and have another thread drawing and doing its own thing how do I do that?
Do I have to make a new class that creates an entirely new PaintComponent()? Or would I simply create a new Graphics2D object so I can use different font colors and such? I guess what confuses me most is that I can't just call a different draw method because I still need to pass g2d as the argument. So it appears to me that I need to make the thread from within another method that already has the g2d object.
If this is confusing I do apologize as I am still a beginner to JAVA. If you need more information just let me know. Thank you in advance.
public abstract void draw(Graphics2D g2d);
#Override
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D)g;
super.paintComponent(g2d);
draw(g2d);
}
In the first place, Swing is inherently single-threaded. This was once summarized in the "single thread rule"
Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread.
(Unfortunately, the respective site did not survive the migration of Java from Sun to Oracle, but some information can be found here http://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html or when doing a websearch for "swing single thread rule")
In general, this applies also to painting : The paintComponent may only safely be called by the Event Dispatch Thread (EDT). And it will be called "automatically". That is why this technique is called "passive rendering": You overwrite the paintComponent method, expecting that it will be called by the EDT.
However, particularly for game development, you can use a technique called "active rendering". In this case, painting is slightly more complicated and involves setting up an own BufferStrategy. The potential advantage is that any thread may perform rendering operations in this case, because you can obtain a Graphics object by calling BufferStrategy#getDrawGraphics.
Information can be found at http://docs.oracle.com/javase/tutorial/extra/fullscreen/rendering.html (while this refers to fullscreen rendering, similar concepts can be applied to active rendering in a window, but I'd recommend to consult further tutorials/resources that can be found with keywords like "swing active rendering").
Hi I've been trying to get rid of my flickering on a JFrame app. Have searched around and seen that setDoubleBuffered(true) can be used for paintComponent of Jpanel, but not paint method of JFrame, nor applets.
Managed to diminish but not eliminate flickering by introducing the instructions this.createbufferstrategy(2) within paint method, and further reduced flickering with the instruction this.setignorerepaint(true) inside paint.
But I finally found an example of code that completely removes flickering and it works by drawing the static elements within the update function.
Tested fillRect within update in an applet and it works, but when copy pasted into a regular java application it does not work there within the jframe's update function.
Here's the code
Graphics graphics;
Image image;
public void update(Graphics g)
{
if (image == null) {
image = createImage(this.getWidth(), this.getHeight());
graphics = image.getGraphics(); }
graphics.setColor(Color.blue);
graphics.fillRect(0, 0, this.getWidth(), this.getHeight());
g.drawImage(image, 0, 0, this);//}
With an empty paint function this draws to the screen and fills it with blue in an applet, it also gets rid of flickering. But in a normal application of jframe it does nothing.
What needs to be done to allow either fillRect or drawImage to work from within update in a non applet regular application environment?
BTW, I'm a bit new to this if the graphics object is being modified itself by calling fillRect, how does that modify the image object? Because drawImage is necessary for the screen to turn blue.
PS I've tried not using both createbufferedstrategy and setignorerepaint, and nothing changes.
When using setIgnorePaint(true), its not allowing you to mess with the Graphics.
I'm guessing by the looks of your update(Graphics g) parameter, you call that within your paint method, using the paintMethod's graphic g to paint (inside paint method, you call update(g))
If you ignore paint, its not gonna allow you to use the paintComponent's Graphic parameter.
Post all code that includes graphics (Where you made your strategy, where you're calling this method, ect..)
The flickering is a pretty mainstream issue with the strategy, and I can't promise that I'll be able to fix it (my friend brought the problem up to me a while ago, but i didnt care enough to try and figure it out), but that should at least explain why your graphics aren't rendering
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
I have trouble understanding a fundamental concept in Java 2D.
To give a specific example:
One can customize a swing component via implementing it's own version of the method paintComponent(Graphics g)
Graphics is available to the body of the method.
Question:
What is exactly this Graphics object, I mean how it is related to the object that has the method paintComponent? Ok, I understand that you can do something like:
g.setColor(Color.GRAY);
g.fillOval(0, 0, getWidth(), getHeight());
To get a gray oval painted. What I can not understand is how is the Graphics object related to the component and the canvas. How is this drawing actually done?
Another example:
public class MyComponent extends JComponent {
protected void paintComponent(Graphics g) {
System.out.println("Width:"+getWidth()+", Height:"+getHeight());
}
public static void main(String args[]) {
JFrame f = new JFrame("Some frame");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(200, 90);
MyComponent component = new MyComponent ();
f.add(component);
f.setVisible(true);
}
}
This prints
Width:184, Height:52
What does this size mean? I have not added anything to the frame of size(200,90).
UPDATE:
I understand that I must override paint to give in the Graphics g object the hints required to do the repaint and that I do not have to create a Graphics object as one will be given by platform.
What happens after that is what I can not understand.
E.g. does Graphics represent the screen and the object is painted accordingly on screen as soon as I start calling the various g.setXXX methods?
Does it get stored in a queue and there is a 1-1 association among g and each component? So the framework uses each g of each component to paint it one at a time?
How does this work?
Any help on this is highly welcome
Thanks
I understand your problem as I struggled with it for some time when I was learning Java graphics. It's not just Java 2D graphics - it is part of AWT.
When you create a JFrame or some other top-level object, it does a lot of work "behind the scenes" - part of which is creating a Graphics object. (There is not explicit notification of this, though if you stepped through the code with a debugger you may see classes which create the Graphics).
You then create components which you add, or register with, the top-level object. These all have to implement a call-back method, including
paint(Graphics g);
You will then #Override these methods so that when the component is rendered it uses YOUR paint method.
Do not try to save the Graphic or create a new one. Think of it as the framework taking the responsibility off you.
The size of components is often taken out of your hands. If you use a layout manager then it may decide to resize your component.
If you are coming from a procedural imperative background you may well have problems (I came from FORTRAN). My advice would be to try a number of tutorials and - at some stage - enlightenment will start to come.
The general documentation for Java graphics is poor. There are many concepts which are opaque (see How does Java Graphics.drawImage() work and what is the role of ImageObserver ). The early implementation was rushed through and had many bugs. Even now it is often unclear whether and in what order you should call methods such as setPack() and setVisible().
This doesn't mean you shouldn't use it! Just that the learning curve is a bit longer than IMO it should be.
MORE:
Also YOU don't decide when something is painted, the framework does. paint(g) really means "The framweork is repainting its components. What to you want this component to provide at this stage".
Maybe providePaintingInstructionsWhenRequiredForComponentGraphics(Graphics g) would be a useful name.
Similarly repaint() does not repaint at your orders, but when the system thinks it should. I haven't found it useful.
If you (say) resize a component interactively every slight change will normally trigger a paint(g). try putting a LOG.debug() in the paint code and seeing when it gets called.
What does this size mean? I have not added anything to the frame of size(200,90).
You added your component to the frame and set the size of the frame to be (200, 90). The default layout manager for the content pane of the frame is the BorderLayout, which means the component you added gets all the available space. The frame needs some space for the title bar and borders, so your component gets the remaining space.
The component does not create a static Graphics object association.
The graphics object is the wrapper for a platform handle giving access to a physical device, like the screen. It's valid for the time when "paint" is executed only, you can't store it and reuse it later. It is a resource managed by the "toolkit".
The component itself is an abstraction on top of the windowing system, that gets asociated shortly with this device for getting rendered.
EDIT
You can force such an association calling "getGraphics" if you feel the need to paint out of the "paint" callback. This should be a very rare case and you ALWAYS should dispose the Graphics afterwards.
Think of a Graphics like a piece of paper which you draw on to show how the Component looks like at that moment. After you've drawn it, the framework toolkit will trim off the edges and show what you've drawn to display the component. Moreover, the next time you draw the component, you'll be drawing on a different piece of paper, so don't keep the old Graphics around.