We can override the paintComponent(Graphics g) method of JComponent.
It is called automatically to refresh the screen.
What can I do that is called regularly, for example every 100 ms.
Is this possible?
You can request that the component repaint itself with a call to repaint(). You most certainly do not want to call repaint every 1 ms though; no monitor in the world could display at 1000 Hz, and no human eye would distinguish that either. Furthermore the repaint calls would be coalesced into a few separate ones and you would not achieve that number of repaints.
What are you trying to achieve? I assume it's some sort of animation; if so you should start googling for "java 2d swing animation" or some variant of that. Try this 2d java tutorial for starters.
Maybe your purpose is refreshing the component every certain ms?
If so, there's a few options available.The use of Timer is a first option. Example here.
The option most people use is Thread animation. Here is an example.
Also there's a timing framework available to download. I can't find an available link, but just search for it on the internet.
Hope this helps.
Related
Been Googling for a few days and I can't figure out how to tell if paintComponent is being called while I'm processing paintComponent. The process is long and complicated. If I have a second (or third) request to paint, I want to abort the current paint process and start over with the most recent request.
You can't; calls to paintComponent() are queued, blocking the EDT until completed. Use the approach shown in this AnimationTest to self-time your implementation on a typical target platform. Optimize as required. As a concrete example, this KineticModel illustrates several animation techniques that may apply to your use case.
Addendum: Your update suggests that the "long and complicated" process involves constructing a BufferedImage for later display. To avoid blocking the EDT, do this in the background of a SwingWorker from which you can publish() interim results as they become available. This example simulates building a raster image one line at a time.
This related example constructs a TexturePaint in a similar manner.
For specific guidance, edit your question to include a Minimal, Complete, and Verifiable example that shows your revised approach.
As usual, I think of a solution after asking for one... My solution is to launch a thread that progressively updates a BufferedImage. Then, the paintComponent method is just two lines:
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(myImage, 0, 0, null);
}
The image is drawn very quickly. Calling super is required to erase the existing view of the image before redrawing it.
The rest of the solution is creating a thread that updates the myImage attribute of the panel. In my work, the image takes about 30 minutes to process completely, depending on the input to the program. It isn't a big deal unless I drag the window or accidentally touch the mouse wheel while the application is running. Then, paintComponent is called again and hangs the program. With this solution, the update can take days and you can resize or move the window all you want. You keep seeing the image as it has been processed so far.
I am a complete novice when it comes to any kind of graphics. So, I want to create a method in a class Creature that would be able to draw lines on a screen (turtle graphics style). I have no idea what would be a good way of doing this. I mean I could store all lines drawn by user in a container or whatever and every time the repaint() method is called I would redraw all lines but it looks bothersome. Or perhaps it's the best way and I am just being silly? As I said, I don't have any experience with this and everything is starting to look like black magic to me. I would appreciate any help or suggestions. Thanks!
See Custom Painting Approaches for two common ways to do this:
Keep a List of objects to be painted and repaint them every time
Paint to a BufferedImage and just display the image
Updating what to draw and actually drawing it should be separate, because you can't control when repaint() is called. You usually want to control how often the updating is done so it's always a good idea to separate. This also reduces the time it takes to draw so it increases performance as well.
so today I'm was making a program and as i'm still a beginner I'm still learning but i'd like to know how to add another circle, for instance I have two units, Red and Blue, I have added the randomize which randomly selects the x and y position, but when I click start it only shows one circle which is red, the blue one is not even there, I know i have not done some coding, but here's my program, please help thanks :)
so yh :) thanks in advance.
A few things to change here:
Drop all AWT components (Canvas, Panel, etc...) and replace them with their equivalent Swing one (JPanel, JTextField...). This will avoid rendering issues and bring double buffering (without any code to perform).
Don't ever use c.getGraphics().
Override paintComponent(Graphics g) and use the Graphics g parameter provided there (see also this link for some example)
To perform "animation" use a javax.swing.Timer. All updates to the UI must be done on the EDT (Event Dispatching Thread). Read also about concurrency in Swing
When using JOptionPane.showMessageDialog (or any other dialog), provide a valid parent component and not null. This will allow proper parenting of windows (avoiding dialogs to be hidden by other frames).
I'm planning to write a simple spaceshooter. I have read that the repaint() method is only a request, and it doesn't execute every time it's called. I believe I'm noticing the effects of this, as my spaceship tends to lag ever so slightly when I'm moving it. Currently I'm simply drawing my ship in a a JPanel's paintComponent() method, and keep calling repaint() on regular intervals (my panel's also Runnable). Seeing as repaint() may potentially screw me over, I'm trying to find a way to work arround it, however I've ran out of ideas. The code I have so far:
private void renderGraphics() {
if (MyImage == null) {
MyImage = new BufferedImage(getPreferredSize().width,
getPreferredSize().height, BufferedImage.TYPE_INT_RGB);
}
MyGraphics = MyImage.getGraphics();
MyGraphics.setColor(Color.BLACK);
MyGraphics.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
MyGraphics.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
}
The idea was to create my own graphics, and then make the JPanel draw it, and keep calling this instead of repaint() in my run() method, however I have no idea how to do that. I'd appriciate any input on the matter.
There are multiple ways to approach this.
The best is probably to use BufferStrategy and draw to that, of which I have included a code snippet that should work for you.
You can take this one step further and abandon Swing altogether, just using Frame/BufferStrategy. There is a fully working example (from which the code snippet was taken and adapted) in my question here:
AWT custom rendering - capture smooth resizes and eliminate resize flicker
Anyway, here is an implementation BufferStrategy that you should be able to just drop in:
// you should be extending JFrame
public void addNotify() {
super.addNotify();
createBufferStrategy(2);
}
private synchronized void render() {
BufferStrategy strategy = getBufferStrategy();
if (strategy==null) return;
sizeChanged = false;
// Render single frame
do {
// The following loop ensures that the contents of the drawing buffer
// are consistent in case the underlying surface was recreated
do {
MyGraphics draw = strategy.getDrawGraphics();
draw.setColor(Color.BLACK);
draw.fillRect(0, 0, getPreferredSize().width, getPreferredSize().height);
draw.drawImage(ship.getImage(), ship.getCurrentX(), ship.getCurrentY(), null);
draw.dispose();
// Repeat the rendering if the drawing buffer contents
// were restored
} while (strategy.contentsRestored());
// Display the buffer
strategy.show();
// Repeat the rendering if the drawing buffer was lost
} while (strategy.contentsLost());
}
any drawing will still be performed in the Swing Thread, so no matter what you try work around, it wont help.
Make sure you are not doing any lengthy calculations in the swing thread, this may be stopping repaint from being executed as soon as it needs to be executed
Separate all the logic into 2 parts. Static and Dynamic. (e.g. sea and moving ship. Ship changes shape/location on a static image of sea)
Draw static content in an image once and use the image in your paintComponent(). Call dynamic parts painting after the static image.
Use setClip() to restrict repainting areas.
Calling repaint without any arguments means that the whole panel is repainted.
If you need to repaint parts of the screen (the spaceship has moved to a different location) you should make shure that only those parts of the screen are repainted. The areas that stay the same should not be touched.
Repaint takes coordinates of a rectangle that should be repainted. When moving the ship you should know the old coordinates of the ship and the coordinates the ship should move to.
repaint( oldShipCoordinateX, oldShipCoordinateY, shipWidth, shipLength );
repaint( newShipCoordinateX, newShipCoordinateY, shipWidth, shipLength );
This is usually much faster than calling repaint() without arguments. However you have extra effort to remember the last position of the ship and must be able to calculate the new position of the ship.
See also: http://download.oracle.com/javase/tutorial/uiswing/painting/index.html - especially step 3
Just for code that you post here:
1/ if you want to display Image/ImageIcon, then the best and easiest way is to Use Labels
2/ as you mentioned Runnable{...}.start(); Swing is simple threaded and all output to GUI must be done on EDT; you have to look at Concurrency in Swing, result is that all output from BackGround Task(s) must be wrapped into invokeLater(), and if is there problem with perfomancie then into invokeAndWait()
3/ if you be switch (between JComponents)/add/delete/change Layout then you have to call revalidate() + repaint() as last lines in concrete code block
EDIT:
dirty hack would be paintImmediately()
I have read that the repaint() method is only a request, and it doesn't execute every time it's called
It consolidates multiple repaint() requests into one to be more efficient.
I believe I'm noticing the effects of this, as my spaceship tends to lag ever so slightly when I'm moving it.
Then post your SSCCE that demonstrates this problem. I suspect the problem is your code.
Regarding the solution you accepted, take a look at Charles last posting: Swing/JFrame vs AWT/Frame for rendering outside the EDT comparing Swing vs AWT solutions.
I'm writing a program to input a number and draw that number of circles of random color and location on an applet. I've been up all night trying to figure out how to add a delay between each of the circles appearing. Right now if I have a for-each statement with a delay in it, and say I input 20 circles and have a delay of 1000, it won't do anything for 20 seconds, then all the circles will appear at once, because the screen doesn't get refreshed until the end of the paint() method.
The only other alternative I could think of was to have a for-each statement in the start() method that would add a color and coordinate to an array, and have the paint() method draw all the circles in this array. I could be wrong, but I would imagine that this would use up way too much memory.
Another possibility would be to just add a circle on to the existing frame without clearing it, but I couldn't find a way to do this.
Use a javax.swing.Timer to add a new Circle object to an expandable list such as an ArrayList. Call repaint() after each addition. In paintComponent(Graphics) draw every Circle in the list.
Update
Unfortunately I cannot add comments at the moment (see External JS failed to load for the gory details). For that reason, I'm adding this as an edit.
#mKorbel: No I sure have not tried it on 1.6.0_26! If I'd tried it at all, I'd have posted the code. ;)
#Tycho: I did not notice you added the awt tag and presumed you were working with Swing.
Are you really using AWT? (If so.) Why?
#Tycho: "The only thing I could tell by quickly searching was that Swing is used more for user interfaces, which is not what I'm going for here."
Umm.. both AWT and Swing (using Applet/JApplet or Frame/JFrame) are used for developing Graphical User Interfaces. Or to put that another way, whether using AWT or Swing, or developing an applet or free-floating frame, you are developing a (G)UI.
Either the applet extends java.applet.Applet (AWT) or javax.swing.JApplet (Swing).
If your applet extends Applet, change it to a Swing JApplet. Few GUI developers can even remember AWT well enough to give good advice on it. My advice was all related to JApplet/Swing. It would not work using AWT.
Use a timer. For example, when you start drawing your circles, set a value:
time_press = System.currentTimeMillis();
circles_to_draw = 20;
Then somewhere in your draw method, do the following:
while(circles_to_draw > 0 && System.currentTimeMillis() < time_press + 1000)
{
time_press += 1000;
circles_to_draw --;
//Draw your circle
}