Sorry, Im newer on this site, but I have a problem with my code, Im drawing a set of images on a JPanel, so I Override the paint method, but when I run the project, I looks like it is running twice.. because I tried to put a println, and its appears twice on the Output. Please a help :(
public class PanelDibujo extends JPanel {
String cadenaOficial;
public PanelDibujo(String cad){
cadenaOficial=cad;
}
#Override
public void paint(Graphics a){
Toolkit t=Toolkit.getDefaultToolkit();
Image imagen=t.getImage("imagenes/muro.jpg");
g.drawImage(imagen, 20, 20, this);
System.out.println(cadenaOficial);
}
}
I created the Panel from this Frame:
public class VentanaPrincipal extends JFrame{
public VentanaPrincipal() {
PanelDibujo panel= new PanelDibujo(cadenaOficial);
setLocation(300, 10);
setDefaultCloseOperation(3);
setSize(660, 700);
add(panel);
}
}
First rule of Swing, you don't control the paint process. Painting will occur when the system decides it needs to be done, this is known as passive painting. You can make suggestions to the system that a repaint should occur, but it's up to the system to decide what and when that might occur
Don't override paint, override paintComponent and make sure you call super.paintComponent before you do any custom painting. Painting is done through a series of chained method calls, it's far to easy to break this chain and end up with no end of weird paint artifacts. Common convention recommends that you override paintComponent instead, as it's generally a safer place to perform painting
Don't load resources or perform any long running operations within any paint method, this WILL slow down your repaints and painting should run as fast as possible
Painting should paint the current state of the component and should avoid performing any calculations and have little logic within in. Decisions about how the state should be changed should be done externally (like via setters) which then trigger a repaint of the component
See Painting in AWT and Swing and Performing Custom Painting for more details about painting
The paint method is called by the JVM whenever the UI requires to be redrawn. It is the responsibility of the JVM. Like when you minimize a window an then maximize it the paint method will be called.
I would suggest that you first minimize the window and then again maximize it you would again find that the output is getting printed again.
Related
We have following methods:
java.awt.Component#repaint()
This is old method that repaints in AWT. It does not repaint immediately, it schedules repaint.
javax.swing.JComponent#repaint(long, int, int, int, int)
This is new swing method that repaints in Swing. It schedules repaint with the RepaintManager.
Both of them may be invoked from a user thread as well as from the event-dispatching-thread.
Which of them is the most correct way to repaint Swing component (JComponent)?
Which of them is the most correct way to repaint Swing component (JComponent)?
Both of them are the correct way.
Swing components always invoke repaint() when you change a property of the component by using setText(), setForeground(), setBackground() etc. This will make sure the entire component is repainted.
The repaint(...) method can be invoked if you need to optimize painting of the component. If you have a large component and only a small part of the component changes you can use this method. However, I would recommend you don't worry about this. Swing painting is double buffered and efficient so there is rarely a case when you need to optimize the painting code.
I am a novice Java programmer and I'm finding quite some difficulty in figuring out the actual difference between the functioning of the paint() and repaint() method.
Also in some of the programs that I studied I found paint() and repaint() interchangeable.
Can someone please explain the difference? Thank you
Assuming that you are referring to the void paint(Graphics g) method that is declared in the Component class:
This paint method is called automatically, whenever it is necessary to paint (parts of) the component. For example, when the window was obstructed by another window and then becomes visible again: The window manager will determine this, and call paint on the top level component (e.g. a Frame) and this call will make its way down to the actual "bottom" components (e.g. a Button). The Graphics object that is passed to this method is provided by the Window manager, and corresponds to the area on the screen where the component should be painted. (And this Graphics object is only valid during the paint method).
In contrast to that, repaint() just triggers a new painting process. It is telling the system: "Please call paint on this component as soon as possible". You can call this method manually. And you can call it freuqently: The calls to repaint are coalesced. That means that when you issue many calls to repaint in a short period of time, then these calls may be summarized and may eventually only trigger one call to paint.
The paint method should not be called directly as the javadoc states:
Invoked by Swing to draw components. Applications should not invoke
paint directly, but should instead use the repaint method to schedule
the component for redrawing.
The repaint method should be used instead if you want the component to be repainted (redrawn). The javadoc also refers to the following documentation: Painting in AWT and Swing
paint() get called automatically at runtime. If you want to call paint() manually(again) then repaint() is used.
The paint() method contains instructions for painting the specific component.
The repaint() method, which can't be overridden, is more specific: it controls the update() to paint() process. You should call this method if you want a component to repaint itself or to change its look (but not the size).
So I'm making this program with a GUI and I haven't worked with Swing/SWT too much but a little bit to know what's going on.
Anyway, I add an actionlistener for a button so it'll add an image to the contentPane when I click on the button but it doesn't work unless I have it as a JComponent (as seen below) and add my other things (button, JLabel, etc) to it afterwards...AND set this JComponent to the content view (which doesn't make sense).... I've also tried making it extend JPanel and just clearing out original contents and re-adding them to the new JPanel. The thing is, when I do this it recreates the text for my JLabel in a weird way, and I just know there's gotta be a simpler, more efficient, way.
class ShowImage extends JComponent{
public ShowImage(){
super();
monkey = Toolkit.getDefaultToolkit().getImage(("D:/monkey.png"));
}
public void paintComponent(Graphics g){
g.drawImage(monkey, 20, 100, null);
repaint();
}
}
Do not invoke repaint inside paintComponent
Invoke super.paintComponent and then draw the image
Also, depending on the layout manager, this component will have a preferred size of (0, 0), and therefore will not be visible.
For more information, see 2D Graphics.
Edit -
Note that dynamically adding a component will force you to revalidate the container and issue a repaint request so the layout manager will layout its components again and remove any visual artifacts. Also, for more information regarding images, see Working with Images.
Anyway, the simplest approach would probably be to set the image as the icon of a JLabel instance and add that to the container. There's really no need to reinvent the wheel here.
g.drawImage(monkey, 20, 100, this);
..would most likely have fixed the problem in the original code. It was a combined problem of:
Loading the image in an asynchronous way. (Toolkit.getImage() as opposed to ImageIO.read().)
Painting it to a 'blinkered' ImageObserver. The JComponent implements ImageObserver. As soon as the image is totally loaded (as well as a few points before that), the observer will be informed, triggering a repaint().
How to use paint() such that when repaint() is called the previously drawn object should not get deleted when drawing the new object. That is the drawing area must get UPDATED only and not REDRAWN.
In my code when one of many button is clicked, some aplhabet get displayed. I want to have functionality such that when other buttons are clicked the previously drawn alhabets must be present.Take is as if a string of alphabets getting created as the buttons are clicked.
Im using Java Swing for coding.
Some piece of my code:
if(source == btnAlpha[i] )
bollyDraw.repaint(); //bollydraw is an object of a JPanel extended class having implemented the paintComponent(Graphics g) method
In the paint() method:
if (word[i] == key) {
g.drawChars(word, i, 1, x, y);
}
In a project I worked on I used a List to store the objects that were to be drawn as a member of a class. Then as the user interacted with my UI I added/removed items from this list. The JPanel that rendered the items painted the items that were in this list. It's helps separate the UI logic from the paint logic as you can determine what goes into the paint list when an event is fired rather than in the paint method ( which should be as clean as possible ). However this will force you to repaint everything on every paint call.
In conjunction with this Kim's RepaintManager is a great way to limit what gets repainted. It is region based so there is some complexity in determining what region of the screen has changed. If you have the time it is better to use something like this otherwise it could be difficult to add this functionality down the road.
Your app must be prepared to re-paint anything it has painted. From your description, I'm afraid that means you have to keep track of everything you've painted.
The Swing behavior is partially dictated by the underlying window manager and graphical system, which at any time may chose to paint over an area where your application is present. You can override update() to control repaints initiated by your own app, and might be able to improve performance by implementing your own RepaintManager.
This tutorial explains Swing painting in more detail: http://java.sun.com/products/jfc/tsc/articles/painting/
Custom Painting Approaches shows a couple of ways to do this depending on your exact requirement.
How would I force a Frame to repaint() immediately after it is maximized, or resized?
I can't find what method is called when that specific operation takes place. I have a bunch of graphics that are written with Graphic objects in paint and their orientation depends on the real time feedback from getWidth() and getHeight() but paint isn't called when I maximize, only when those pixels change unfortunately.
Register a ComponentListener:
final Component myComponent = makeTheFrameOrWhatever();
myComponent.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e)
{
myComponent.repaint();
}
});
You need to dig further because repaint() and paint() most certainly are called when you resize a frame - it's the only way the frame can cause it's contents to be painted. It is most likely that you're not seeing the repaint reach your specific component in the frame, perhaps because the particular layout you are using is not affected if the window is made larger. Or if you have no layout, then you must subclass Frame and explicitly have it call paint on the subcomponents, since there is no layout manager to do that for you.
Note that whether or not painting is done repeatedly while you are resizing, as opposed to just once after you let go the mouse button may be an operating system option.