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.
Related
I was wondering how would I change this block of code to be able to have a dynamically changing background colour that switches from (red -> black -> green -> black -> blue -> black ->red) and the loop starts again. The background colour should be continuously changing per tick. Right now I have a render method that will continuously run over the loop and I wonder if anyone is able to change is so that it also includes this dynamic colour changing.
private void render() {
BufferStrategy bs = this.getBufferStrategy();
if (bs == null) {
this.createBufferStrategy(3);
return;
}
Graphics g = bs.getDrawGraphics();
g.setColor(Color.black);
g.fillRect(0, 0, WIDTH, HEIGHT);
g.dispose();
bs.show();
}
Hello and welcome to SO!
You are not using swing right. You should be doing all your rendering in paintComponent, which gets automatically called when needed. However paintComponent on JFrame doesn't do anything, as the JFrame contains a ContentPane (JFrame.getContentPane) and that is the background you want to change. Changing the background of the contentpane should be as simple as
myJFrame.getContentPane().setBackground(newColor);
However not all (J)Components paint their background (JLabel for one), so you may need to create a JPanel and use myJFrame.setContentPane(...); before the code above
Note: To get swing to be single-threaded (as it should be) use SwingUtilities.invokeLater(...) to create/modify Swing classes.
Note 2: Looping in swing should be done using javax.swing.Timer. You don't need a loop though: Set the new background in your click listener, and then call repaint
I have a JFrame which contains a single panel.
In the panel I use the paintComponent method to resize its elements according the size of Jframe. The elements of the JPanel are an image as a background and 4 JLabel that cointains 4 ImageIcon and work like buttons. The method paintComponent of Jpanel is like below
public class MyPanel extends JPanel
{
//Declarations
private BufferedImage backGround;
public MyPanel()
{
//Some code here
}
public void paintComponent(Graphics graphics)
{
super.paintComponent(graphics);
Graphics2D graphics2d = (Graphics2D) graphics;
if(backGround != null)
{
graphics2d.drawImage(backGround, 0, 0, getWidth(), getHeight(), this);
}
/* This code is repeated 4 times because I have 4 labels */
label1.setSize(getWidth()/7 , getHeight()/10);
label1.setLocation(getWidth()/2 - getWidth()/14 , getHeight()/3 );
image1 = button1.getScaledInstance(label1.getWidth(), label1.getHeight(),
Image.SCALE_SMOOTH);
label1.setIcon(new ImageIcon(image1));
}
}
The frame has just a simple method , add(myPanel) so I did not write it here.
When I run the application , it takes me around 300 MB of ram and around 30% of CPU (Inter core i5-6200U) , which is quite unsual for me , expecially the amount of CPU. What is causing my application to take so much resources and is there any way I can reduce it ?
Whenever you repaint your component you change your labels' dimensions and create resources (the Image and the ImageIcon derived from it) and assign them as a new icon. These are changes to visible parts of your application and hence must cause repainting the components in question. Basically your paintComponent method
causes a repaint every time it is called effectively creating an endless loop and
is very heavyweight because it allocates expensive resources.
Both of these points are pretty bad ideas. Your paintComponent method should do just what the name suggests, i.e. painting the component. All actions that cause a repaint (changing icons or text, adding or removing components from the tree etc.) must not occur in it.
See also:
The API documentation on paintComponent(Graphics)
Painting in AWT and Swing
EDIT: When you want to resize components dependent on the size of other components create a ComponentListener and add it to the component you want to depend on by calling addComponentListener(ComponentListener). The ComponentListener instance will then have its componentResized(ComponentEvent) method called whenever the size changes.
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.
As a coursework piece for school, we had to come up with a self-defined project, which I chose a game idea I was originally going to write on actionscript but decided to push for it on Java. This was initially going well, with the game code working, the sprite animations were being handled fine and everything was being maintained within a game loop. That was until i began to try and add components such as buttons and labels to it.
Currently the structure of my game is as this( GameSystem[handles loop and redrawing] -- GameMenu [Simple intro screen with start game ] <---swaps between ---> GameContainer [holds information about the game] )
My loop inside the GameSystem updates all necessary objects, repaints and then tells all the objects to repaint after.
Game System:
/**/for(int i = 0; i < UpdateList.size();i++){
/**/UpdateList.get(i).Update(delta * 1.1); // tell list the element is an object that extends an interface
/**/}
/**/Game.repaint();
/**/#Override
/**/public void paint(Graphics g) {
/**/super.paint(g);
/**/Graphics2D g2d = (Graphics2D) g;
/**/g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
/**/ RenderingHints.VALUE_ANTIALIAS_ON);
/**/for(int i = 0; i < UpdateList.size();i++){
/**/UpdateList.get(i).paint(g2d); // tell list the element is an object that extends an interface
/**/}
/**/}
This is where it starts getting iffy, because the game system repaints it's self each loop, clearing the frame of previous stuff, the buttons which I add in my gamemenu which is created inside the game system get cleared and only reappear briefly when you mouse over them.
Game Menu:
//////////////////
// Start Button //
//////////////////
Buttons = new JPanel();
Buttons.add(Start_game = new JButton("Start Game"));
this.add(Buttons);
Start_game.addActionListener(new Load());
/**/}
///////////////////
//////////////////
//Paint sprite //
//////////////////
#Override
/**/public void paintComponent(Graphics g) {
/**///super.paintComponent(g);
/**/Buttons.paintComponents(g);
/**/}
////////////////////////////////////
At this point I've tried paint, paint component, revalidate() and a variety of other stuff I've gleamed from other posts but none have helped. The only way I've had the button appear visible is if I remove the call to repaint in the game loop. However this then impacts the game as none of the objects are repainted.
TL DR: How can I Handle repainting the various objects in my update list and refreshing the Gamesystem panel without making any components such buttons disappear? Sorry if this is a noobish question but this is my actual first time working with Java as I wanted to expand outwards from actionscript, if any more info is required i will gladly add to the post, thank you for your help.
The problem is that you are trying to handle the painting of the buttons differently than the painting of your game.
Game System
{
paint loop
{
painting Game
}
}
Components //managing the painting itself through paintComponent, trying to run at same time as Game System.
{
paintComponent
}
So in effect, you are wanting to switch one to the other. You could either use paintComponent() in the GameSystem instead of paint(), which manages disposing of the graphics and repainting for you (if it is already extending a jComponent)...
or you need to start managing the buttons' painting similar to how you do it for your game, instead of relying on paintComponent()
A mouse listener calls repaint() and I can see that it does actually go past the drawing part because I see globalcounter incremented in the output of System.out.println(). On the screen, however, I don't see any change until I minimize the window and maximize again, resize it, or move it out of the visible screen area and back in. Obviously I'd like it to update without my intervention.
class GUI extends javax.swing.JFrame {
int globalcounter=0;
class MyCanvas extends Canvas {
#Override
public void paint(Graphics g) {
globalcounter++;
g.drawString(globalcounter,100,100);
System.out.println(globalcounter);
}
}
}
(Originally I was loading an image from a file that got constantly updated (webcam) and painting it on the canvas. When I dragged it partly out of the visible screen area and back in, the part that has been 'outside' was refreshed, the rest not.)
revalidate() instead of repaint() didn't change anything.
I know this post is a duplicate to Java repaint not working correctly but when I posted it there it was deleted.
Why are you adding an AWT component, Canvas, to a Swing component, JFrame? You should stick with Swing components only. And also do you know the size of your MyCanvas, and how have you added it to the JFrame as you don't show this code.
Consider
using a JPanel instead of a Canvas object,
drawing in its paintComponent method,
showing us an sscce if you're still stuck.
And also, if all you're doing is drawing text, use a JLabel rather than drawing in paint/paintComponent, and change its text with its setText(...) method.