Using two paint methods in two jpanels in one jframe - java

I recently stumbled upon a problem when attempting to create an overlay for my frame. The frame consists of 2 panels, a GamePanel and an OverlayPanel, each with their own paint methods. I seperated these in order to keep my code cleaner and for efficiency. The problem I'm having now, though, is that my paintComponent methods are overlapping each other, causing only one painted panel to be visible at a time.
I understand that this is caused most likely due to the fact that both panels cover the entirety of the screen. What is being painted on the OverlayPanel, however, only covers a part of the screen.
The goal is that the GamePanel will draw a map of some sort and the OverlayPanel will then draw something such as a rectangle at a given location on top of this map.
Is my approach to this wrong, or is there something I'm missing?

Is my approach to this wrong, ..
Yes. It is possible to separate drawing operations into separate methods in separate classes, yet still have the entire paint operation done by a single method.
Imagine there is a Map class with a draw(Graphics2D) method, and a RectangularPlayer class also with a draw(Graphics2D) method. Each class knows how to draw its own parts to a common graphics instance. In the paintComponent(Graphics) method of the GameField class, call the relevant draw methods of the map and player classes, as well as any other game elements that need to be rendered.

Related

Multiple 2D Graphics Drawing Functions in Java

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.

Flickering when updating overlapping JPanels inside a JLayeredPane using timestep

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

Using a paintComponent with layout

How do I convert a paintComponent to something that I can manipulate with a layout in a JFrame?
So, I'm running into an issue. I haven't really been taught (and don't have access to a book) how to use layouts/GUI stuff in my courses yet.
My issue is this: I have a program that the user inputs a number. Based on this number, the program calculates a circle and draws it out with a paintComponent method that has a for loop inside of it. The "pixels" that the circle is drawn with are actually fillRect methods. The current method of getting a user-input that I am using is a JOptionPane showInputDialog. This is MOSTLY fine, but I want the user to be able to select from a set of pre-defined numbers. Somebody suggested that I use a JComboBox, but I don't know how I would convert the paintComponent to something that would be usable by a layout manager (which a JComboBox must use, as far as I've learned). I know the dimensions of the paintComponent (805px by 805px) and there is no situation where it will change. If I could get some help with this bit, I am confident that I can figure out using a layout manager myself.
Another way to paint (besides custom painting) is to paint to a BufferedImage. The image can then be displayed in a JLabel.
Examples:
Painting in a BufferedImage inside Swing A fairly complicated one.
Dynamic Graphics Object Painting Another one.
Yet another one.
You don't know the dimensions of paintComponent because it's a method, and methods don't have dimensions. You probably know the dimensions of a JPanel or a JFrame or whatever your component is.
You should separate the panel where you do the painting, and a different panel which would contain any comboboxes or other inputs you decide to put in. That way you can keep your drawing panel as is, and they won't interfere with each other. You'll want to search for the tutorial on LayoutManagers.

How to get the inner frame in java swing?

I was building a simplistic "game" as sort of tutorial into developing apps or such in java.
My Main class extends JFrame. It was just moving a ball around the screen. After getting to the point where I can move the ball can move I started implementing collision with the boundaries of the window and spent several minutes trying to figure out why the only went some beyond the border on 3 sides and then far beyond the top before I realized that the boundaries were being obeyed but that they were the edges of the actual window, beyond the display area.
How would I set up the Main class so that the boundaries are the visible area? Would it extend a different class? And then what it be inside of something else?
It's hard to say what you may be doing wrong without code,
but for one thing, you should never be drawing directly in the JFrame and should avoid extending JFrame.
Instead extend JPanel, get it's boundaries, and draw in this JPanel.
Also, make sure to override the JPanel's paintComponent(...) method,
to also call the super.paintComponent(g) inside the override.
Put the JPanel into a JFrame for display.
Make sure to check out the Swing drawing tutorials before doing this coding because often you have to change basic assumptions when doing graphics program and especially animation programs.

Jpanel / Jframe / buffering graphics etc game structure direction

I'd like some advice regarding structure of a game I'm working on. Specifically where to place painting methods.
Currently there is a applet wrapper class for a Jpanel which runs the game loop.
The game itself is meant to simulate a very large area. objects will have x&y values which themselves will part of a larger x&y grid.
i.e. object1 position is 150000x30000 in grid block 1,5.
objects will need to be able to move into neighbouring grids, however I'd rather not run each grid block until needed as 99% of them will be empty.
Currently the UI is a Jpanel with a few buttons + listeners, a large drawing pane is needed to display the objects.
my question is:
what class should this internal drawing pane be based on? I'd like to have control to zoom and pan around the grid. it only needs to draw what is visible, but object movements will continue in the game loop.
what painting strategy would be applicable for simple (icons really when zoomed out) moving around vast areas, I'm guessing relying on the EDT to repaint isn't going to be good enough?
I'm not really after specific code, I want to learn myself how to do this, I just need pointing in the right direction, as most things I read don't seam to quite cover what I'm after, or don't make use of JRE6+ features.
Many Thanks
Rather than paint each grid cell in your drawing pane, why don't you have each object repaint itself onto the grid?

Categories