How to add 2 JComponent to JPanel at the same place stretched on full JPanel? I tryed to:
add(ship,null);
add(ground,null);
I'm guessing as to your use case, but is "ground" a background image containing JPanel? If so, then add it in such a way so that it fills the container, perhaps via BorderLayout.CENTER with the container using BorderLayout of course.
The ship, I'm guessing is a sprite that is drawn on the background. If so, consider having it not be a JPanel but rather a logical object that holds an image Sprite that can be drawn in the ground's paintComponent method.
As always the devil will be found in the details. You first.
Edit
You state in comment:
Stage is my background and it extends JPanel. Ship is a player element (JComponent). Ground (JComponent) is something which player can't touch. I wanted to have this two elements (ground and ship) like layers where the image is drawn. I need to have one point reference to check collisions.
I assume that you have a paintComponent(Graphics g) override method in your Stage object where you draw your background image.
Based on this assumption, I change my previous recommendation in that I feel that neither ground nor ship should extend JPanel since you don't really need for them to do this. You already have a JPanel on which you can do your drawing and game interaction, so why create more when they'll only clutter things up? The only exception I see is if either ground or ship need to hold other components, and if so, then yes, they should extend JPanel.
Consider:
What is important to both of these objects, both ground and ship, are their locations and their images.
Give both ground and ship a BufferedImage field that can hold their images, with getters and setters.
Give them x and y int position fields and width and height, with getters and setters that can be used to test for collision and can be used to move their respective sprite (image).
Give them a draw(Graphics g) method that draws their respective images at the x an y location when called and passed a valid Graphics instance.
Have Stage hold an instance of each ground and ship, and have stage's paintComponent(Graphics g) method draw both instances by calling their respective draw methods.
Edit 2
You now ask:
One more question: When should i have keyListener?
I recommend that you not use a KeyListener.
KeyListener is a low-level construct, and in general you should prefer to use higher-level constructs such as Key Bindings as they are safer and easier to use without causing side effects or having problems. For instance, it is easy to run into problems with focus issues if you use a KeyListener since it only works if the component listened to has the focus. This is easily circumvented if you used key bindings instead.
You can find the Key Bindings tutorial here
and an example of using it with animation in my answer here.
Related
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.
I've just started coding video games and I've heard that doing all your drawing on a JPanel and attaching that panel onto a JFrame is better than simply drawing onto the JFrame. I was just wondering why is this better?
It is better for various reasons, including:
In most Swing components, custom painting is achieved by overriding the paintComponent(Graphics) method. Top-level Swing containers (e.g. JFrame, JApplet, JWindow) have only paint(Graphics). As a result of the common method for painting, people who answer often forget about this difference between common and top-level components, and therefore suggest silly advice. ;)
A JComponent can be added to a JFrame, or a JApplet, or a JDialog, or a constraint of a layout in a JPanel, or a JInternalFrame, or a.. Just when you think your GUI is complete, the client says "Hey, wouldn't it be great to throw in a tool-bar & offer it as an applet as well?" The JComponent approach adapts easily to that.
As explained (complete with code!) by Richante, it is easier to calculate the co-ordinates required for painting the custom component, and if it has a preferred size, to size the JFrame to be 'exactly the right size' to contain the GUI (using pack()). That is especially the case when other components are added as well.
Now, two minor disagreements with the advice offered.
If the entire component is custom painted, it might be better to simply put a BufferedImage inside an ImageIcon/JLabel combo. Here is an example of painting to an image. When it comes time to update it:
Call getGraphics() for a Graphics or createGraphics() for a Graphics2D
Draw the custom painting to that graphics instance
Dispose of the graphics instance
Call repaint() on the label.
It is an easy way to do Double Buffering.
Let me elaborate a bit. In video games, to avoid the flicker caused by redrawing and display smoother graphics, people usually use double buffering. They create an offscreen surface, draw everything on that and then display the entire off-screen surface on the screen in one go.
In Java2D and Swing, the easiest way to do this, is to simply do your game sprite drawing on a JPanel, and then add the JPanel to a JFrame.
Secondly, by drawing things on a JPanel, you allow more GUI widgets and other graphical objects to be displayed on the JFrame without having to paint them manually in the game loop. For example buttons, menus, other panels, even other rendering JPanels.
Thirdly, it allows you to use automatically translated co-ordinates for your game. You can draw everything from the top-left to the bottom-right without having to worry about the window manager specific things like window border-widths, task panes, titles etc.!
Moreover, this is not just a convention only used by Game Programmers in Java. Creating a separate Game Board, Render Panel or Graphics Widget is quite popular when programming games using a library with an internal mainloop such as a GUI Toolkit. You can use a User Form in Windows Forms and a Drawing Board in GTK+.
The JFrame includes things like the menu, title bar and border. Therefore, when you refer to coordinates you have to account for these. You might also decide to add a menu bar, or some other components, to the frame. If your painting is all in a JPanel, then this won't change how you need to refer to coordinates.
For example, try:
public class Test extends JFrame {
public Test() {
super();
setVisible(true);
setBounds(100, 100, 200, 100);
}
#Override
public void paint(Graphics g) {
g.fillRect(0, 0, 50, 50);
}
public static void main(String[] args) {
new Test();
}
}
and you will see that the black square is not square! Because (0, 0) is the top left corner of the entire frame, not the corner of the visible area.
Implementing "Kings' Corners" (glorified multiplayer Solitaire) in Java.
I'm trying to allow a player to drag a card (image) from their hand to somewhere else on the table. The problem is that the player's hand is "fanned" so the images of the cards are rotated and they overlap.
Here is an example of a hand:
I've considered making each card a JPanel, but the issue then is that I'd have to paint the card rotated inside its rectangular JPanel, as they themselves can't be rotated. Ideally I'd like to avoid mouse-x,y formulas to determine which card is being chosen.
Using an event-driven approach, how can I determine which card is chosen from the hand?
AWT (and Swing) components are normally rectangular (aligned to the axes).
But this does not have to be the case - while the real bounds must be rectangular, the actual area which a component uses can be smaller. Component supports a contains(Point) method, which will get called by the event dispatch mechanism whenever the question arises to which component a point belongs - for example, for mouse clicks. (Overlapping of different components will be handled by the z-order inside the parent container.)
You can implement this method based on the Shape.contains() method, using a affine transformed rectangle as your shape. Each of your rotated components would know its own shape (or generate it on the fly from its AffineTransform, the same one which would also be used for painting itself).
Have a custom LayoutManager which arranges your cards, too. (Don't use CardLayout, despite the name.)
I'm not sure I would follow the way of having separate components for each card, but you certainly need some objects which represent the rotated rectangles.
I am trying a project called white board sharing in which I need to get the information from a panel and that information is like some drawings so how can I get it from a panel. In that panel I am drawing some rectangles circles.
In case you want to react on mouse events you might want to investigate the following sections of the Java API.
MouseListener
MouseMotionListener
Also if you want to react on mouse events that are triggered when the users moves his mouse over a drawn element you might be interested in Graphics2D and the classes that implement Shape.
You can pass a Graphics object to the panel for it to paint the items that were drawn.
It may help to think of the board as a view of some model that records an abstract representation of the board's content. As a concrete example, this GraphPanel has a very simple model containing nothing more than a List<Node> and a List<Edge>. These two members could be wrapped and serialized as discussed in this tutorial.
I have a JPanel which has a line, circle, etc. Now when I click on the line, will the event get reported as a line event or a general JFrame event. I need to be able to move the line if the user clicks on the line and moves it. Is this possible in Java2D?
Yes, but you will need to do some work (see java.awt.Shape). Basically you need to track a list of Shapes. The JPanel will recieve a mouse event, which you can translate to (x,y) coordinates. You can then call Shape.contains(x,y) to see if your various shapes were clicked on.
This will work well for Circle, Polygon, Arc, etc; however in the case of Line2D, it won't work as easily, but you can use Line2D.intersects() with a small rectangle around the mouse click (this is also good UI since you don't want to force the user to click exactly on a pixel that is hard to see).
There is no such concept as a "line event" unless you decide to implement one.
I would suggest adding a MouseListener and a MouseMotionListener to the Canvas or JPanel onto which your geometric shapes are drawn. Use the MouseListener's mousePressed(MouseEvent) callback to determine whether a given shape has been clicked on. Once you've established this, use MouseMotionListener's mouseDragged(MouseEvent) method to move and redraw the shape as the mouse cursor is moved.
Here's a simple example that demonstrates some of the techniques adduced in other answers.
I created a canvas markup library in Java a few years back and if you don't need to worry about transforms on the canvas (scaling, rotation, etc.) it is very easy to do.
Basically you just need to maintain a collection of the canvas shapes in a List (not a Set because Z order is probably important). The mouse listener will be on your canvas, and not on individual shapes. Add new items to the beginning of your collection (or iterate the list backwards later).
When the canvas receives a mouse down event iterate through your collection of shapes until you find one that is underneath your mouse coordinates. The easiest way to do this is to have your shapes implement an interface that defines some sort of hitPoint(int x, int y) method. That way your rectangles can implement a contains(), lines can do intersects() or graphics paths, you can account for some hit padding, etc.
Taking it one step further, your shapes should define their own draw(Graphics2D g) method so that you can easily do things like selection boxes, or set the paint mode to XOR to make shape 'moving' easier. The paintComponent method of your canvas would just have to iterate through your collection of shapes, calling shape.draw(g) on each one, passing in the graphics instance provided to the paintComponent method.