Adding multiple graphics to a single JPanel - java

I am attempting to add 3 graphics, two of which have to move(presumably through each other, moving on a single axis) and only the lattermost one added to the panel shows.
In other words, I have many panels added to my JFrame, and in the biggest panel I have put in graphics objects using specific coordinates. It may be more helpful to show the code.
//the gameArea is the referred-to JPanel, above this code
TankOne tank1 = new TankOne(Color.GREEN);
TankTwo tank2 = new TankTwo(Color.MAGENTA);
FieldBar fieldb = new FieldBar(Color.getHSBColor((float) Math.random(),(float) Math.random(),(float) Math.random()));
JPanel tank1panel = new JPanel();
JPanel tank2panel = new JPanel();
tank1panel.add(tank1);
tank2panel.add(tank2);
gameArea.add(tank1panel);
gameArea.add(tank2panel);
gameArea.add(fieldb);
//repaint code here
As you can see, it is a tank game.
The one that shows up on the GUI is the last gameArea.add. [Here it would be fieldb, a bar that shows the game floor].
The attempt made here is me trying to put two new panels into the gameArea Jpanel and then placing the two tank objects inside those. Still no dice.
Is there a workaround for this that would allow me to move the tanks by pixels?
I have seen some answers include switching to gridlayout, but I don't think that will help seeing as the extra Panels did nothing.
Thank you for your answers.

I'm guessing that each tank JPanel shows an image of a single tank (? not 100% sure). Some suggestions, but please do tell me if my assumptions are way off base:
Keep the logic and view well separated a la M-V-C.
Do all graphics in a single JPanel, perhaps called a DrawingPanel, in its paintComponent(...) method.
The Background image will be a BufferedImage that is draw in the DrawingPanel's paintComponent(...) method.
The a tank itself would not be represented by a JPanel but would be its own small BufferedImage sprite, again draw in the paintComponent method, but drawn after the background image.
Each tank would need at least 4 sprites, one for each direction.
You may need more sprites if your tanks will move along a diagonal.
And a separate sprite/image for the turret.
You would move a sprite's drawn position in response to changes of it's model representation's position.
Same thing for turret rotation.

Related

Swing JLayeredPane stop repainting all layers

I'm trying to make a game with Swing and I need to make a board with players on the board, so I've used the JLayeredPane. At layer 0 I drew the board and then on layer 1 I've painted the players.
This works well but the problem is when I redraw layer 1 (e.g. change the position of a given player) the performance is very bad. My assumption is it's repainting the background board again and this is causing the issue.
Here's the code:
JLayeredPane layeredPane = new JLayeredPane();
layeredPane.add(boardView, new Integer(0));
layeredPane.add(creepsView, new Integer(1));
creepsView and boardView override the paint method and when changes to the state of the creeps happens, it's calling the creepsView.repaint() method, but then the boardview.paint() is called by the JLayeredPane and I don't understand why. How can I avoid it? (I don't want to redraw the things that didn't change).
I guess it's because it's repainting the background board again.
I doubt that is the problem since painting an image that is loaded into memory is very efficient.
, it's calling the creepsView.repaint() method and then the boardview.paint is called by the JLayeredPane
In order for you to see the background that means the panel containing the players must be transparent. This means when you repaint the player panel, the background panel must also be repainted to make sure there are no painting artifacts. For example, the player must be removed from its old position and painting in the new position.
You can try to make the painting more efficient by only painting the affected area of the panel. That is instead of repainting the entire player panel you only repaint the player at its old position and at its new position. Read the section from the Swing tutorial on Custom Painting for an example of this approach. ThemoveSquare(...) method shows how this approach works.

Add more than one panel on a frame on top of each other

I'm working on a project where I am displaying a square and a circle.
The circle moves on its own, but the user moves the square via the arrow keys. Whenever the circle touches the square, it rebounds.
Square and circle are different classes (2 different panels). I want to add those two to a frame, one on top of the other such that both are visible.
Can someone tell me how to do so?
JFrame n = new JFrame();
n.setTitle("Background Color for JFrame");
n.setSize(1000,600);
n.setLocationRelativeTo(null);
n.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
n.setResizable(false);
n.add(new Ball());
n.add(new Team());
n.setVisible(true);
User interface components at the same level in a hierarchy are assumed to be non-overlapping by default. You can explicitly work around this by making your components transparent with setOpaque(false), assuming you are taking care to only draw whats needed in the components, e.g. in case of a JPanel ensure that its background is not drawn. Its still somewhat random (implementation dependent) which component has precendence over another when doing this.
There is a component explicitly designed for that: JLayeredPane (https://docs.oracle.com/javase/tutorial/uiswing/components/layeredpane.html), which manages "layers" in which components can be put, giving you full control which overlays which.
Games often implement this by themselves, since the full features of JComponent are not needed to represent a simple graphical element. In that case a single component is used as a "canvas" to paint self-defined objects onto making use of an override of paintComponent (See: https://docs.oracle.com/javase/tutorial/uiswing/painting/)
If you want to do this in swing, as it sounds, I would really recommend making a new class that extends JPanel, and override it's paintComponent method. In this method you use the Graphics in the argument to paint to the canvas. Then you can add this custom panel instead of two separate components to your JFrame, and handle the rendering in there. This render panel can then keep track of all objects that needs to be rendered, preferable implementing some interface (Drawable?) with a draw(Graphics g) method. That way you can make your classes that needs to be rendered implement your Drawable interface, keep then as a list in your render panel and just iterate through them in your paintComponent method and call draw on your Drawables.

How to paint graphics from multiple classes to a single panel

At the moment, I have two JPanel classes that draw images and shapes to a JFrame (I will have more in the future), I'm doing this to make things organised.
At first I tried to add each JPanel to the JFrame, but one JPanel would paint over the other.
Each class should be able to call other classes that may draw images to screen as well.
The problem I have is that I cannot get them to draw to the screen.
Should I use paintComponent or paintAll? And how should they be used?
Thank you for any help :)
It sounds as though you are adding both panels to the same location in the JFrame probably in the BorderLayout.CENTER position. One solution is to use a GridLayout with 2 columns for the JFrame and add the 2 panels.
paintComponent is the correct method to override in your panels.
Follow the custom painting trail to see how it should be used.

Painting on JPanels

I'm writing a program that will be just a simple shape maker, I'm supposed to my main panel, ShapeMakerPanel, along with 2 panels on that one, controlPanel(which holds buttons for choosing the shape and clearing it, etc) and drawingArea (where the shapes are actually drawn), but no matter what I do, I can't get the paint to show up on drawingArea. If I just use paintComponent and comment out add(drawingArea) then the drawing stuff works, but on the bottom layer, how can I paint on the drawingArea Jpanel. Also, when I do draw the shapes, I can only have one at a time, because every time I start a new one, the panel is wiped clean`
super.paintComponent(g);
g.setColor(penColor);
if (p1 != null && p2 != null)
{
if (shapeChoice.getSelectedItem().equals("Line"))
{
Line line = new Line(p1.x, p1.y, p2.x, p2.y);
line.draw(g);
}
}
I know its the super.paintComponent(g) messing me up, but without that, as I drag the mouse, it draws hundreds of lines.
If you were wondering about the Line class, we had to make a class for each shape we drew, the draw() method just uses the coordinates of the line and puts them into drawLine().
Don't override paintComponent() in ShapeMakerPanel; override it in drawingArea's class (if drawingArea is a plain JPanel, then create a new subclass of JPanel). In general you need to subclass the component on which you're going to paint.
Also, when I do draw the shapes, I can only have one at a time, because every time I start a new one, the panel is wiped clean`
See Custom Painting Approaches for a couple of ways to solve this.

Moving and resizing JPanels object inside JFrame

Continuing my quest of learning Java by doing a simple game, i stumbled upon a little issue. My gameboard extends JPanel as well as each piece of the board. Now, this presents some problems:
Cant set size of each piece, therefore, each piece JPanel ocupy the whole JFrame, concealing the rest of the pieces and the background (gameboard).
Cant set the position of the pieces.
I have the default flow manager. Tried setbounds and no luck.
Perhaps i should make the piece to extend other JComponent?
Added image:
That's the piece, now the greyed area is also the piece! Checked that by making a mousePressed listener and assigning some stuff to it. Below the grey area, is the gameboard (or at least, should be!), another JPanel.
alt text http://img42.imageshack.us/img42/2227/screenshotvdy.png
Some code:
package TheProject;
import java.awt.Color;
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class GameWindow extends JFrame {
public GameWindow() {
setSize(800, 600);
setLocationRelativeTo(null);
Map map = new Map(800, 600, 2);
add(map);
MilitaryUnit imperialRussia = new MilitaryUnit(30, Color.BLACK, Color.YELLOW, Color.WHITE);
imperialRussia.setPreferredSize(new Dimension(30, 30));
add(imperialRussia);
}
}
This happens when i apply the pack() method:
alt text http://img442.imageshack.us/img442/5813/screenshot2ml.png
Packs around the Unit, not the map which is bigger and fills the JFrame.
For a game that has random movement of pieces you would probably use a "null layout".
Read the section from the Swing tutorial on Absolute Positioning for more information.
I wrote a few games using JPanel. Basically the way I use JPanel is like I'm using a Canvas, viz I draw directly on it by overriding the paint() method. The reason why I use JPanel is because I can determine the size of my game world, then use the setPreferredSize() to set the size of the panel. I then add the panel to a JScrollPane. So this will take care of the panning, etc.
Say I'm writing a 2D game. This is how I use JPanel. I have a logical map (a 2D array) which holds my game map. Say each location is 32x32 pixel. So you start drawing the ground and what is on that ground in that location. eg in x=1, y=2 which is screen location x=32, y=64, you draw the ground first, then draw what is on the ground. So a rough outline of the render loop would be something like this
for (int y = 0; y < map.length; y++)
for (int x = 0; x < map[y].length; x++) {
drawGround(map[y][x])
for very element on on map[y][x] - render them
}
You set a MouseListener listener to the JPanel, so every mouse click you translate back to the map eg. mouse click x=54, y=72 would correspond to x=1, y=2. The calculation is a bit tricky if you have an isometric view.
The thing you have to be careful here is that everytime when you scroll the panel via the scroll panel, paint() will be called. So it is good to render your game board on a BufferedImage and then in the paint() method just draw the BufferedImage otherwise it'll be too slow.
Have you tried NetBeans' visual editor? You can use it to drag, drop, and resize to your convenience Swing objects in Design View, and can then switch to Code View to see the generated code. You can learn that way.
Have you tried setPreferredSize(Dimension d)?
Edit: You need to call pack() on your JFrame, after you've added your components:
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(800,600));
JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(200,200));
frame.add(panel);
frame.pack();
frame.setvisible(true);
Also, you add a Map to your JFrame, which has the same dimensions as your JFrame - fine. But then afterwards, you add another component, to the default flowlayout. This cannot fit into your frame, as the Map already occupies 100% of the space.

Categories

Resources