-Hi all! I'm making a Java applet that simulates wave interference, which I have almost finished (will license under GPL). However, I have two questions regarding the AWT paint cycle that I am having difficulty finding answers to.
I want to make an 'about' overlay that appears when I press a button. The way I want to do this is to draw over the entire applet window with my static message and legend objects. The problem is stopping the AWT components from drawing themselves in the foreground without using remove(). Is there a way I can stop AWT from drawing itself temporarily?
For my standing waves mode I want to have node and anti-node markers calculated and drawn to a secondary graphics every time the standing wave reaches a maximum amplitude (all of which I can do myself), but drawn to the primary graphics (and thus displayed) every paint cycle. Could someone explain the steps to do so? I imagine it would involve creating a second graphics object, drawing to it once, then drawing it to the primary graphics every cycle.
If you are able to answer either of my questions I would be very grateful!
Cheers, Jack Allison
Responding to your first question:
You can't disable the paint()/paintComponent() method if you've inlcluded it in your code. If its there, it runs. However, you can create a flag so that only if the flag is true, the stuff gets drawn. Let me show you what I mean:
boolean flag;
...
public void paintComponent(Graphics comp) {
if (flag) {
Graphics2D comp2D = (Graphics2D) comp;
//drawing statements
}
}
public void actionPerformed(ActionEvent event) {
flag = true;
repaint();
}
Related
I am building a simple game rendering method. I have a static images like map background that isn't really changing at all . I am just using like 30% of the whole screen for changing graphics. And I don't feel like it is necessary to render all that stuff over and over again if it isn't changing..
on internet I found something about passive rendering - You draw what you need and wait... until something updates .. after that you update it and again wait.
Looks like a great method for this situation . But now ...
I have a render method like that :
public class X extends Canvas{
//some method
this.createBufferStrategy(3);
//....
public void render(){
BufferStrategy buffer = this.getBufferStrategy();
Graphics g = buffer.getDrawGraphics();
//Draws black background...
g.setColor(Color.BLACK);
g.fillRect(....
for(... //cycles every object and calls their render methods...
}
This is unable to maintain draw and wait method...becouse the background is redrawn every 1/30 of second so If you don't have anything to draw, you get black canvas with nothing on it.. so you have to always redraw everything each update...If I don't draw the background , buffer start to blink like hell... so I have to have something to cover that stuff up.
I searched on internet and found nothing much about other solutions for this rendering type.. Tuns of stuff for active rendering but nothing for that Draw and wait method..
I think it's impossible to do that with BufferStrategy. Is there something else to serve for this ? Also is there other source for Graphics g ? On internet was something about calling it directyl from Canvas but I didn't get it running for this. Or am I thinking about it from wrong angle?
You're confusing passive rendering with partial updates. In "passive rendering" you can redraw everything, but you don't do it 30fps. you only do it when something moves. In "partial rendering", you only draw on the part of the canvas that changed.
The two can be put together, so that you only draw what changes, and only when it changes. That's the ideal case.
But passive rendering doesn't work if something is always moving, and partial updates don't work if the whole background is updating constantly.
Making a paint-like application that works by saving mouse points in an arraylist. My idea is to have a "points" arraylist with all the previously drawn stuff, and a "temp" arraylist to get and modify the current brush stroke the user just entered. This is necessary as the user can change the color and size, so my idea is to modify the current brush stroke based off what buttons have been pressed, then add that brush stroke to the rest of the picture. I searched around StackOverflow and found some code but cant get it to work how I want to (assuming I found the right code).
#Override
public void paintComponent(Graphics g1) {
super.paintComponent(g1);
final Graphics2D g = (Graphics2D)g1.create();
try {
g.setColor(brushColor);
for (Point point : tempArrayList){
g.fillOval(point.x, point.y, brushSize, brushSize);
}
} finally {
g.dispose();
}
The problem is that I need to clear the tempArrayList for the next brush stroke, which I can do when they change the color/size, but then it erases what was previously there. I am starting to think that I don't even need the "points" arraylist as descibed above because I was hoping that the g1 graphic would just save what the g graphic created.
I guess I just need to figure out how to add the g graphic to g1
Painting is controlled by the Swing API, there is a expectation that whenever paintComponent is called, you will repaint the entire state of the component (as part of your component might have been damaged due to some system event), so the short answer is, no, you can't...however....
You Could...
Paint to a BufferedImage instead and paint the BufferedImage when paintComponent is called
You Could...
Establish a series of "paintable" objects which contain information about what is to be painted and how it is to the painted, including the brush stroke, stroke color and fill color.
These would then be added to some kind of List and "painted" when the paintComponent method is called
Check out Custom Painting Approaches for exampled of painting from:
A List of objects
A BufferedImage.
The examples show how to draw Rectangles of different colours.
so i am dabbling in making a game and i am a fairly messy worker and then i go back and tidy it up. So please ignore any stupid naming conventions or methods or anything. As I go back later and tidy up.
So basically I am trying to make a main menu, i just want to draw something to the screen and have it stay there. I am writing the graphics to a image ATM and displaying the image as i tried just drawing to the canvas and it just flickered up onto the screen and then it went blank. I changed it to a runnable so i could put in sleep() to try and error hunt. I've removed all my error hunting code now. It turns out when i have a sleep() before or after the image is put on the screen for longer than 50ms the rectangle stays on screen and doesn't flicker away like 1ms after it was drawn.
I'm not sure what's going on. I am probably not that clear and I apologies.
import java.awt.Canvas;
import java.awt.Graphics;
import javax.swing.JFrame;
public class test extends Thread{
public static void main(String[] args){
test t = new test();
t.start();
}
#Override
public void run() {
JFrame f = new JFrame("Test");
Canvas c = new Canvas();
Graphics g;
c.setSize(400, 400);
f.add(c);
f.pack();
f.setVisible(true);
c.setVisible(true);
try {
sleep(2000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
g = c.getGraphics();
g.drawRect(10, 10, 40, 68);
}
}
Basically, this is not how painting in AWT works. Painting should be done within the context of a component's paint method. In AWT Canvas seems to be the preferred base component to use.
You should never use getGraphics, apart from been able to return null, it will only represent the Graphics context from the last paint cycle, anything added to it could be wiped about by newer paint events...which is probably happening to you.
Take a look at Painting in AWT and Swing for details about how painting works.
Having said all that, I would discourage you from using AWT based API as it was replaced by Swing some 15 years ago.
Take a look at Performing Custom Painting for more details about painting in Swing
You're kind of getting the idea, but there are a few standard design patterns of creating a game, for starters check out this code.
Basically, you'll need something called a game loop which will update and render to the display a certain amount of times every second (framerate or fps). When it renders, it will clear and redraw the image in a new location at a certain interval, if your fps was 60 you would be rendering (clearing, and redrawing) 60 times a second. We can also introduce more advanced concepts such as buffer strategies (shown in the example above) to reduce tearing and flickering.
To sum it up, you're kind of there, you just need to constantly do that g = c.getGraphics() so...
while (true) {
g = c.getGraphics();
// set color
// draw a rectangle
g.dispose();
}
Note how I added the dispose, this will just free up any unused memory. Just to clarify, this is by no means good code, but it will give you a place to start :)
The flickering is due to only having 1 screen, to stop this flickering you need a buffer strategy. Basically having two buffers is like having two screens, whilst you render on one 'screen' you can clear and draw the next step on the second screen and switch between the two buffers; this reduces the flickering.
I've been working on a java game recently, and I have a lot of it figured out. One thing still plagues me, however. The way it's set up, a player moves across a background (the game board). Currently, every time the player moves, it repaints the whole frame, including the background. This causes a brief, yet annoying screen flicker whenever the player moves.
I've separated out my code to draw the background separately from the things that need to be repainted:
public void drawMap(Graphics pane) {...}
public void drawPlayer(Graphics pane) {...}
The problem is that I can't find a way to make the board stay on the screen when I use repaint(); , a necessity for the player to move. Any suggestions?
You should look into double buffering, basically you paint an image to the buffer, then paint the buffer. It should remove the flickering effect you are talking about. Below are a few helpful links:
http://docs.oracle.com/javase/tutorial/extra/fullscreen/doublebuf.html
http://content.gpwiki.org/index.php/Java:Tutorials:Double_Buffering
http://www.ecst.csuchico.edu/~amk/classes/csciOOP/double-buffering.html
Just comment if your having trouble understanding it.
UPDATE: I would also suggest you look in 'Killer game programming in java'. You can get a free ebook of one of the older versions. Some of it is a bit out dated, but the first few chapters about setting up a game loop and drawing to the screen etc are still very much relevant.
UPDATE 2: From the second link, try something like this:
private void drawStuff() {
BufferStrategy bf = this.getBufferStrategy();
Graphics g = null;
try {
g = bf.getDrawGraphics();
drawMap(g);
drawPlayer(g);
} finally {
// It is best to dispose() a Graphics object when done with it.
g.dispose();
}
// Shows the contents of the backbuffer on the screen.
bf.show();
//Tell the System to do the Drawing now, otherwise it can take a few extra ms until
//Drawing is done which looks very jerky
Toolkit.getDefaultToolkit().sync();
}
UPDATE 3: This post here gives a nice code sample that you can play with and adapt, that should give you the best idea on how to do double buffering
I suggest to avoid redrawing everything with every change. Instead draw the whole frame at a fixed interval, e.g. every 50ms. Just keep the status of every element in a class and if something changes just change the data value. Due to the fixed redrawing interval the display will pick up any changes at the next redraw.
How can I draw something in JPanel that will stay the same and not be repainted, I am doing a traffic simulation program and I want the road to be drawn once because It will not change.
Thanks
I'm not sure you actually want your road to never be repainted - repaint events fire (for example) when your window is resized, or when it becomes visible following another window obstructing it. If your panel never repaints then it'll look peculiar.
As far as I remember, Swing will only fire appropriate paint events for these circumstances, so you should be OK following the usual method of subclassing JPanel with a suitable override:
public class RoadPanel extends JPanel {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
// your drawing code here
}
}
If you cache your road into an image or another graphics format (to save calculating the display data multiple times) once drawn once, this might save you some time on subsequent paints.
To my knowledge, no, unless there is a trick with transparent overlays.
Most graphical applications I saw (and did) just re-draw the whole panel on each repaint. Now, you can do that once, in a graphic buffer, and then just paint the whole background at once, quickly, by copying the graphic buffer to the JPanel. It should be faster than calling all graphical primitives to draw the road.
Or, the way some 2D games do, perhaps paint it once and update the moving parts, like sprites: it needs to erase the old place used by the sprites (restore the background there) and re-draw the sprites at the new place. So you still have a copy of the road in a graphic buffer but instead of re-drawing it whole each time, you update only some small parts. Can be slightly faster.
The component will need to be repainted every time that the panel is obscured (ie frame minimized/another window put on top). Therefore drawing something only once will not work as you want it to. To make parts that do not change be drawn more efficiently you can draw them once to a 'buffer' image, and then just draw this buffer each time that the panel or component needs to be redrawn.
// Field that stores the image so it is always accessible
private Image roadImage = null;
// ...
// ...
// Override paintComponent Method
public void paintComponent(Graphics g){
if (roadImage == null) {
// Create the road image if it doesn't exist
roadImage = createImage(width, height);
// draw the roads to the image
Graphics roadG = roadImage.getGraphics();
// Use roadG like you would any other graphics
// object to draw the roads to an image
} else {
// If the buffer image exists, you just need to draw it.
// Draw the road buffer image
g.drawImage(roadImage, 0, 0, null);
}
// Draw everything else ...
// g.draw...
}
What I do is set a boolean value to whether or not a certain part needs to be redrawn. Then, in the paintComponent() method I can check the value and redraw the certain thing, or not.
protected void paintComponent(Graphics g){
super.paintComponent(g);
if (drawRoad) {
drawRoadMethod(g);
}
drawTheRest(g);
}
Kinda like that.