I'm working on a 2D game and am now stumped on a drawing issue. I'm repainting the JPanel with the background image and characters every frame, but the GUI is created in a setup function. I think that causes the JButton to appear behind the background image, and its worth mentioning this class extends JPanel. I'm using setBounds in order to arrange GUI elements a special way. What is a possible solution to this issue?
/** Draw game to the screen **/
private void gameDraw() {
Graphics g2 = this.getGraphics();
g2.drawImage(image, 0, 0 ,null);
g2.dispose();
}
public void SetupUI() {
uploadButton = new JButton("UPLOAD");
uploadButton.setBounds(WIDTH / 2, HEIGHT - 40, 50, 30);
uploadButton.setToolTipText("Press this button to upload your AI to the ship");
uploadButton.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
//TO DO: Make upload button compile and run the users code
}
});
this.add(uploadButton);
this.setVisible(true);
}
I decided to redo the code for rendering the game component. The issue seems to have been the GUI button and the image sharing the same screen space, then the image redrawing over the button each frame. What I was trying to go for was the gui overlaid over the image, but I still do not know how to achieve that.
Instead I created two separate JPanels, one to hold the GUI elements in a 'ribbon' above the image, and one to hold the image where neither panels are overlapping then packed both of those into another panel which was then assigned to the JFrame (feel like this is a scene from the Emperors New Groove lol) . Each panel has a layout assigned. The image in its own panel can now be rendered as frequently as needed without interfering with the gui. Just remember to draw whatever images you want in order e.g. draw the background, then the player.
I couldn't solve the original problem, but this is a decent workaround.
Related
I trying to make mini game and this game have option to choose map. Diffrent chooice, choose diffrent map. Every choice have own map ( background image ). For background image I useing JLabel and method: setIcon().
My problem is that when I set image, all my components get hide. This is picuture: http://prntscr.com/qi5m8a ( You can see that only image can be seen ).
For map choose I use this structure, here is picture: http://prntscr.com/qi5n4c There is Play button with event like this:
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
if(mapOneRadioButton.isSelected())
{
this.dispose();
GameWindow game = new GameWindow();
game.setVisible(true);
game.setLocationRelativeTo(null);
backgroundLabelGameWin.setIcon(new javax.swing.ImageIcon(getClass().getResource("/main/earthProject.gif")));
}else if(mapTwoRadioButton.isSelected())
{
}else if(mapTreeRadioButton.isSelected())
{
}else if(mapFourRadioButton.isSelected())
{
}else if(mapFiveRadioButton.isSelected())
{
}
}
I useing JPanel where I add JLabel for background image and I useing JLayeredPanel for rest of components.
My problem/question is, How can I change/set image without breaking order in my frame ?? I mean, I want to change/set image in background so all my components can be seen.
Please help me, I have no idea how to fix this.
For background image I useing JLabel and method: setIcon(). My problem is that when I set image, all my components get hide.
Two options:
add the components to the JLabel. Then the components will paint on top of the image. The restriction of this approach is that the components must fit inside the image, since the image is always painted at its actual size.
do custom painting of the image on a JPanel by overring the paintComponent(...) method of the panel and then invoke the Grapics.drawImage(...) method. Then add your components to the panel. See Background Panel for a class that provides this support. This provides more flexibility as you can scale the image to fill the panel.
It will be better if you change the background of the JPanel instead of using a JLabel for image. You can't directly change the background of a JPanel. But you can refer following link to do it
http://www.java2s.com/Code/Java/Swing-JFC/Panelwithbackgroundimage.htm
In my app, I show a popup dialog to show a large list of cards. I display them as images in many JLabel components in a JPanel subclass. I then put that object in a JScrollPane to allow for horizontal scrolling through the cards.
I want the unused space to be transparent with a dark background to show that what's behind it is disabled. I used setBackground(new Color(50, 50, 50, 200)) to achieve the look I want, but the content behind it does not redraw, so I get artifacting.
Here's what it looks like:
How would I go about fixing this? How do I get the content behind it to redraw when I scroll?
Thanks in advance.
Taking the window out of the equation for the momement.
The JScrollPane contains a JViewport which then contains you content. So you need to set your content pane to transparent, the viewport to transparent and then the scroll pane to transparent.
You can achieve this by using setOpaque(false) on each of these containers.
This will ensure that the repaint manager will now paint through the background.
The next problem is, Swing doesn't actually support "semi-transparent" components (that is, either it's opaque or transparent).
You can implement this by overriding the paintComponent method of the main component (the one on the viewport is probably sufficient)
Try the following...might give you some relief during scrolling.
You likely also have a problem when the main frame is maximized
or restored. You will need a listener for those events and a
similar fix.
jScrollPane.getVerticalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(final AdjustmentEvent e) {
sevenWondersframe.repaint();
}
});
jScrollPane.getHorizontalScrollBar().addAdjustmentListener(new AdjustmentListener() {
#Override
public void adjustmentValueChanged(final AdjustmentEvent e) {
sevenWondersframe.repaint();
}
});
I'd like to implement a DragAndDrop for an Image but can't seem to get the Swing repaint function to work on the specific Image.
Code:
public class playerFrame extends JFrame{
...
private void destroyerImageMouseDragged(java.awt.event.MouseEvent evt)
}
repaintCurrentPosition(evt);
}
public void repaintCurrentPosition(MouseEvent e){
this.setLocation(e.getX(), e.getY());
this.repaint();
}
this.repaint <- this function repaints the whole frame and not just the Image I'd like it to repaint, which is about 50x50 size.
How do you repaint a specific JPEG image without creating a new class?
thanks.
this.repaint will force the parent frame to be repainted. Call repaint only on the control holding your image.
Example: to refresh this image loaded onto the JLabel:
ImageIcon icon = createImageIcon("images/middle.gif");
label = new JLabel("Image and Text", icon, JLabel.CENTER);
You do:
label.repaint();
not just the Image I'd like it to repaint, which is about 50x50 size
JComponent#paintImmediately carefully with EDT
How are you doing the drag and drop?
The easiest way is to just add an Icon to a JLabel and then drag the label around. Everytime you invoke setLocation(...) on the label it will repaint() itself.
The Component Mover class does all the hard work for you.
Call repaint only on the panel where your image is drawn.
In my gui that I have created in Java, every time I minimize the window, repaint is called and the drawing that was originally there vanishes once the window is maximized (back to normal)
So I created an action Listener to detect when the window had been minimized and then maximized for it to draw each point that was originally on the panel back to the screen.
Unfortunately, I am not getting the results that I expected.
For some reason, when the window is maximized each point is drawn back onto the panel but the background of the entire window is black. Also, this can be very annoying for the user to have to wait for each point to be drawn back onto the screen each time they want to minimize the window.
Here is what I have so far:
//Redraw plot if window is minimized
window.addWindowStateListener(new WindowAdapter()
{
Graphics g = dPanel.getGraphics();
public void windowStateChanged(WindowEvent ev)
{
boolean minimized = false;
//If user minimizes window and then maximizes window
if(window.getExtendedState() == Frame.ICONIFIED )
{
minimized = true;
System.out.println("Window minimized");
}
if(ev.getNewState() == Frame.NORMAL || minimized == true)
{
System.out.println("Window back to normal state");
//Draw each Point back onto the screen
for(Point i: PointArray)
{
drawPoint(g, i, startColor);
System.out.println("Panel Repaint");
}
}
}
});
}
Is there some way that my code can be edited to achieve the desired results or is there a better way to do this. Basically, I just want that when the user minimizes the GUI, the painting that was there before minimization is still there once the user maximizes the window. Also, moving the window around can also cause parts of the panel to be repainted or the entire panel to be repainted.
//Draws point onto panel
public void drawPoint(Graphics g, Point PointArray, Color color)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setStroke(new BasicStroke(2f));
g.setColor(color); //g2d.setColor(Color.black);
g2d.drawOval((int)PointArray.a, (int)PointArray.b, 2, 2);
}
The more I read on your situation and need, the more I think you should actually use getGraphics, but do not call this on a JComponent such as a JPanel. Rather you should do your drawing in a BufferedImage, and you should get the Graphics object of the BufferedImage by calling getGraphics on the BufferedImage. You can then draw this BufferedImage in a JComponent's paintComponent method with the Graphics#drawImage(...) method, or even better for its simplicity (and if you don't want to use the image as a background for a JPanel or gui), draw the Image in an ImageIcon that is displayed in a JLabel. One caveat though is if you get your Graphics object in ths way, don't forget to dispose of it when you're done.
I just want that when the user minimizes the GUI, the painting that was there before minimization is still there once the user maximizes the window.
I gave you the answer in your previous question (about combo boxes).
You even thanked me for the suggestions.
So try implementing the suggestion BEFORE posting a follow up quesiton.
I just figured out a way to force the repaint of a JPanel and all its components. Instead of doing any special work, just call your JPanels.setVisible(false), then followed by setVisible(true). It will redraw everything! You won't see any flicker, just like a magic.
I'm working on recreating "Legend of Zelda a Link to the Past" as part of an assignment.
And I've got the following problem, the game world is a BufferedImage of which I subImage() the part I need for the current location of the player. The game works but uses 80 / 110 percent of the CPU. A profile revealed that the culprit is the drawing of the image.
So I figured I put the background in a separate JPanel from the Player, enemies etc JPanel.
Render them on top off each other (JLayeredPane) and repaint the background panel far less often.
But how do I do this how do I tell swing to draw one panel x times a sec and the other y times? If you have a better way of optimizing let me know.
Here's what I've got at the moment:
public class Main extends JFrame
{
private ZeldaGame game = new ZeldaGame();
private View view = new View(game);
private BackgroundView bckView = new BackgroundView(game);
private Controller ctl = new Controller(game, view, bckView, this);
public Main()
{
setLayout(null);
view.setBounds(0, 0, game.getWidth(), game.getHeight());
bckView.setBounds(0, 0, game.getWidth(), game.getHeight());
JLayeredPane pane = new JLayeredPane();
pane.add(bckView, 1);
pane.add(view, 0);
setLayeredPane(pane);
setSize(game.getWidth(), game.getHeight());
setResizable(false);
setLocationRelativeTo(null);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
public static void main(String[] args)
{
new Main();
}
}
Thank You.
It's not really possible to have different render times because of the way the framebuffer works -- what the result would be is loads of nasty flickering. What you need to do is using Canvas instead of JPanel and JLayeredPane and you can either override the paint() method of the canvas or use bi.getGraphics() and blit the background and the characters on a loop using either of these methods in the correct order. I'd advise using a thin engine like GTGE which will abstract from all the messy details of optimisation. These high level components you're using seriously aren't designed for games, and you shouldn't be using them at all.
Ok I've found the error of my ways. I was using passive rendering while I should have used active rendering. Active rendering basically shuts down the automatic repaints by calling setIgnoreRepaint(true); on the frame and do the loop yourself.
And as an added bonus I don't need to use JPanels.