I am looking for a dedicated drawing surface in Java to draw 2D very fast in succession, very much like Android's SurfaceView. I have been using JPanels but I am not sure about the performance and efficiency when calling repaint() multiple times. The documentation says that:
If this component is a lightweight component, this method causes a call to this component's paint method as soon as possible. Otherwise, this method causes a call to this component's update method as soon as possible.
Note the as soon as possible. I want instantaneous. Using the SurfaceView in Android I had full control of the Canvas and could draw when I wanted.
Should I be using for instance the Canvas from AWT or JComponent from Swing, or something else? Note that I want a dedicated drawing area and I do not care about other compontents. I would like to register mouse events though. And again, I want the full control to draw on the area without having to call repaint or some other method, like I do with SurfaceView on another Thread.
I asked a similar question but now I feel like I can be more specific thanks to the answers from that question.
Related
I was trying to draw a circle in JPanel with paintComponent, when I call repaint() every time it remove all original paint. But when I remove super, it will show the trace of circle moving. So how should I do for keeping the circle after moving without showing the trace of it?
Painting in Swing is destructive, that's how it works.
When a paint cycle occurs, you are expected to repaint the component state from scratch.
This would suggest that you need to maintain some kind of model which the paint methods can use to repaint the state in it's entirety
I would recommend having a look at Painting in AWT and Swing for more details about how painting works
Start by reading the section from the Swing tutorial on Custom Painting. It shows how to draw a square at the location where the mouse is clicked.
So your logic would be similar except that instead of using the mouse to determine the new location of the circle you will use your programmed logic to change the x/y location of the circle.
You can use a Swing Timer to schedule this animation. The tutorial also has a section on How to Use Swing Timers which contains a working example to get you started.
This question already has an answer here:
How to define multiple JButton actions from a different class
(1 answer)
Closed 6 years ago.
So the program draws a car and I'm going to make three buttons, one for flash to initialize the flashing ability, one left, to move the car one space to the left and one right, to move the car one space to the right. My question is how do I make it change color each time I press the button? So to sum it up, I don't know how to have an object change it's color each time the button is pressed while flashing is on. I assume I use paint()
Any help would be appreciated.
If you are drawing an image, you will need to load a different image file which is a different color, and then draw that image instead. You will do this inside whatever method you are currently using to draw the car.
If you are drawing a shape or text of some kind, you can call g.setColor() on the graphics object passed to the paint() or paintComponent() method before drawing the shape.
There are any number of ways to do it. The basic requirement though, is to have a Object of some kind which you can tell when it should change color, it would then undertake the appropriate action and update the UI accordingly.
You could...
Use a simple JPanel as the representation of the object and simply call it's setBackground color method when you want it to change color.
This assumes you want to make use of a LayoutManager to position the panel. While it is certainly doable, it will require some thought into the overall design
You could...
Use a JPanel and override it's paintComponent method and paint the color change there. At the simplest level, this is overkill, but if you also want to draw a "car" or an image of "car", then this becomes a little more meaningful, especially if you want to rotate the car based on the direction it's moving
See Painting in AWT and Swing, Performing Custom Painting and 2D Graphics for more details
Flashing
I assume you mean you want the object to be animated in some way and "blink" on and off.
This can easily be accomplished through the use of a Swing Timer which can be used to change the state of a simple flag which changes the way in which the component is rendered.
See How to use Swing Timers for more details
The important concept to take away from this is to create a object which encapsulates the requirements in away which is ease for you to use, so when you enable flashing for example, all you do is call the setFlashing(boolean) method and the object takes care of the rest
In my program I am using Swing windows for my GUI, and I know that I'm supposed to use repaint and paintComponent methods to render swing components. I also have several custom class objects that need to be rendered inside the main window. For the sake of understanding, my program is a game that will have moving objects that need to be rendered 60 times per second.
In a game development tutorial I watched, the guy used a Jframe with Canvas, but he didn't use the paintComponent method. He simply made his own render() methods to draw all the graphics using graphics context he obtained from creating a bufferStrategy.
So if that works (which it does), why does everyone say to use the paintComponent methods and what exactly is the difference between them?
If I were to use the paintComponent way of doing things, how would I use bufferStrategy with that?
In a game development tutorial I watched, the guy used a Jframe with Canvas, but he didn't use the paintComponent method. He simply made his own render() methods to draw all the graphics using graphics context he obtained from creating a bufferStrategy.
Canvas is an AWT component, using a BufferStrategy, you take over the painting process and become responsible for update the Graphics context and scheduling it's push to the hardware/screen.
This is commonly known as "active painting", as you are constantly (one would assume at a constant frame rate), updating the buffer.
Swing uses a passive paint process, so you never know when a paint process might occur. Swing has it's own mechanisms for determining what should be repainted and when. Using repaint, you make a request to these mechanisms that your component be repainted, but there is no guarantee that a paint cycle will be initiated because of it.
If you use any Swing component for you painting, you MUST use repaint and paintComponent, as the Swing is responsible for providing the context onto which you can paint.
If you want to use Canvas, then you can use a BufferStrategy instead.
Essentially, they are different approaches to painting. Remember though, if you use a BufferStrategy, you lose ALL of the Swing API, you CAN NOT use Swing components with this approach, as they are not designed to work this way...
The program I am working on includes a class named GameForm that extends JFrame. This form is going to contain a map (just a series of rectangles), as well as certain objects on the map.
However, I would not be able to draw all of these objects with a single paintComponent(Graphics g) function, since not all objects in the game always have to be drawn at the same time. For example, the drawMap() function would only be called when the form first loads, whereas all other drawing functions would be called after each turn.
However, from what I have read (and please correct me if I am wrong), only one paintComponent function is allowed in the class, and other functions cannot make use of its Graphics2D object.
Are there any ideas as to how this can be implemented?
People who are new to Swing / GUI programming often imagine JFrames to be like a draw surface or paper. However, you will have to get used to the fact that this is not the case.
First of all, a GUI program has some kind of EDT (Event Dispatch Thread). This thread is where all the GUI action happens. Updating the GUI and responding to user input happens here. This is necessary because user interaction and programmatic changes to the GUI need to be synchronized well.
Back to the topic, a JFrame is basically just a rectangle that is registered to the System to be your "draw surface". Rather than just painting on top of it, you are asked to paint it.
That's what paintComponent(Graphics) is good for. Obviously, you don't want to paint all the time. It just works like:
user opens your window
system tells your app: "hey, you wanted this surface, please paint it"
the Graphics from paintComponent() is used to repaint your frame (quickly)
your application remains inactive until the user makes the next input
If you want to animate your frame, you have to work like this:
tell the system: "hey, I'd like to repaint my surface" (calling repaint())
system calls paintComponent() and you repaint your stuff
the next call must be delayed
start over, paint the next image
Note that the delay is important because all of this happens on the holy EDT. The EDT handles everything and needs to "breathe" so the user can do stuff while you're doing your animation.
All in all, what you've learned is:
Save all the state you need for painting in variables.
When paintComponent() is called, draw onto the surface
If you want to animate, call repaint() -> paintComponent() will be called
never block the EDT
Last thing to consider: don't use JFrame to paint directly to it.
Rather than that, add a JPanel to the frame and override its paintComponent() method.
Generally speaking, what you wish to achieve can be done in a couple of ways. It's strictly related to so-called sprites (http://en.wikipedia.org/wiki/Sprite_%28computer_graphics%29) and image buffering (http://en.wikipedia.org/wiki/Multiple_buffering). Simplest approaches would be:
a) in paintComponent() of a JPanel added to your JFrame generate the resulting image by processing all the input data/user events/machine state,
b) you can prepare & store the overlay as e.g. BufferedImage, updating it as needed, and then paint it over your JFrame during a single call - the state of JFrame will be updated only on paint events (paint(), paintComponents() etc, so you must force invalidation by hand if the map changes without direct JFrame interaction (resizing the window, covering it with other frames etc), e.g. by calling repaint() etc.
c) you can get the drawing context by calling getGraphics() (http://docs.oracle.com/javase/7/docs/api/javax/swing/JFrame.html#getGraphics%28%29), and then using the returned object (probably casted to Graphics2D) as your canvas whenever the need arises. Note that this is actually the worst solution in terms of efficiency.
They ain't the only ones possible - I, for once, use OpenGL/JOGL for most of my 2D rendering needs, since it allows insane rendering speed with all the profits of 3D graphics [interpolation, scaling, rotations, alpha-blending, perspective, geometry morphing, shading etc] with only minimal functional overhead.
Also, note it is usually advisable to draw on a dedicated canvas component (e.g. JPanel) instead of global JFrame - it's connected to so-called lightweight vs heavyweight component difference and other OOP/Swing/AWT/EDT concerns; it also allows to hide the map and reuse the JFrame for something else with one simple JPanel#setVisible(false) call.
See java what is heavier: Canvas or paintComponent()? for more information.
I am making a game in Java. Basically, I have two different "planes" of updating that I need to take care of the. The base layer is the actual game painting itself. It is simply a JPanel that covers the entire JFrame, and is drawn to using its Graphics object.
I use a fixed timestep to take care of these first graphical updates. I have overwritten the paintComponent() method to do absolutely nothing, as I have written a custom render(float interpolation) method that takes care of that, as to prevent unwanted updates.
However, this panel can take no input beyond primitive mouse clicks and keyboard input. I need the ability to create various menus, text boxes, etc, that are also on the screen. Like various abilities, or even the "Menu" button that usually appears in the upper left corner of most games.
To take care of that input, such as creating buttons, I have a second JPanel that has setOpaque(false) applied to it. Then I create various Swing components that I might need, such as a JButton.
To contain the two JPanels, I use a JLayeredPane, and set their layers appropriately, as seen below. This way the input layer should always be on top of the actual game layer.
The code below shows how I create and add the Swing components to each other. addLoginDialog() is a method that adds a Swing component for the login. It has been tested and works properly, and isn't the problem.
private void initComponents()
{
//This code is inside of the JFrame
wholePane = new JLayeredPane();
add(wholePane);
guiPanel = new GUIPanel();
guiPanel.setOpaque(false);
gamePanel = new RPGPanel();
gamePanel.setOpaque(false);
wholePane.add(gamePanel, JLayeredPane.DEFAULT_LAYER);
wholePane.add(guiPanel, JLayeredPane.POPUP_LAYER);
guiPanel.addLoginDialog();
}
So when I run the code, I get horrible flickering. This is the code that is run from my fixed timestep ~60 times per second.
public void handleRepaint()
{
//I don't use repaint() for the game drawing so I can be sure that fps is controlled.
Graphics g = gamePanel.getGraphics();
gamePanel.render(g);
g.dispose();
wholePane.repaint();
}
The problem is, I think, that the two different systems of updating the screen are clashing. The standard paintComponent() system is great for more static screens, but when I need to update consistently and keep track of the fps, I can't have updates going off randomly.
However, for the input layer, I only want to update as Swing normally does. When the mouse moves over a button, when I component is moved or is resized, etc.
Also, note the way the screen flickers: The Background image goes blank and then comes back again repeatedly. The input panel is always there, but is actually painted behind the game drawing, which shouldn't happen, because it is put in the default layer. The reason I know it isn't completely disappearing is because the game painting is partially transparent, so I can see underneath it, and the buttons I added are still there.
My main question is, how can I stop the flickering? Why is the game drawing being drawn on top of the input components when the game drawing is being done on the Panel that is in a lower layer in the JLayeredPane? And I supposed most importantly, what is causing the flickering? Thank you for any help.
Why is the game drawing being drawn on top of the input components
when the game drawing is being done on the Panel that is in a lower
layer in the JLayeredPane?
Mostly because you've circumvented how Swing works.
Let's start with the fact that the Graphics context is a shared resource (typically there is a single Graphics context per native peer), that is, every component gets the same context, this means, when you use your own painting routine, you are basically painting over every thing else.
The RepaintManager is responsible for making decisions about what and when something should be painted. So what you now have is two artist fighting over the same canvas, wanting to paint on it simultaneously, which is just making a mess.
Add into the fray that Swing's painting process is not thread safe and you end up with a complete mess.
If you absolutely must have control, then you need to remove Swing's painting engine from the equation.
Start by taking a look at Passive vs. Active Rendering
ps- There is also hard ware acceleration benefits to using a BufferStrategy