Repaint never reaches paintComponent(); - java

I'm back with a problem about java-graphics by swing... I want to paint some stuff at a jframe, here is the code:
PaintUtil-class:
public class PaintUtil extends JPanel{
public PaintUtil(){
this.setFocusable(true);
this.requestFocus();
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
System.out.println("Repainted");
g.drawstuff...
}
}
Main-class:
public static PaintUtil util = new PaintUtil();
JFrame frame = new JFrame();
frame.setSize(500,600);
frame.setRezisable(false);
frame.add(util);
frame.setDefaultCloseOperation( 3 );
frame.getContentPane().setColor(Color.BLACK);
setup(); //This add some buttons
frame.setVisible(true);
util.repaint(); //not working
util.paintComponent(frame.getGraphics()); //works
Can you guys help me?

There is no error, no message in the console, just nothing
frame.setLayout(null);
Don't use a null layout. Swing was designed to be used with layout managers. Get rid of that statement.
By default the size of your panel is (0, 0) so there is nothing to paint.
You will need to override the getPreferredSize() method of your panel so the layout manager can do its job.
Read the section from the Swing tutorial on Custom Painting for more information and working examples.

Related

How to successfully draw background JPanel once and update foreground JPanel constantly?

I have a custom JLayeredPane, and I am repainting it in my game loop. There are two custom JPanels added into the JLayeredPane. These are foreground and background JPanels. How do I successfully only draw my background JPanel once, (And repaint when window is re-sized or any other reason) to reduce impact on system resources, while continuing to update my foreground JPanel constantly.
To re-iterate, I dont want to constantly repaint the background JPanel in a loop. I want to repaint it only when it is nessessary, as the background does not change. and is large.
In my attempt to do this, I have only drawn the background once. However. the background JPanel is simply not visible. while the foreground JPanel updates as normal. It is almost as if the foreground JPanel paints ontop of the background JPanel, even though I have both of the JPanels set to setOpaque(false)
I have made a mvce which shows my attempt at only drawing the background JPanel once, while updating the foreground JPanel constantly.
The problem with my code is that the background JPanel does not show.
Now. I know that if I were to draw it constantly it would show. But that defeats the purpose of what i'm trying to do. I am trying to only draw it once, and have be seen at the same time
My code successfully only draws the background JPanel once. The problem is that the background JPanel does not show. How do I fix THIS problem
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Main extends JLayeredPane {
static JFrame frame;
static Main main;
static Dimension screenSize;
public Main() {
JPanel backPanel = new BackPanel();
JPanel frontPanel = new FrontPanel();
add(backPanel, new Integer(7));
add(frontPanel, new Integer(8));
new Thread(() -> {
while (true){
repaint();
}
}).start();
}
public static void main(String[] args) {
screenSize = Toolkit.getDefaultToolkit().getScreenSize();
frame = new JFrame("Game"); // Just use the constructor
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
main = new Main();
frame.add(main, BorderLayout.CENTER);
frame.pack();
frame.setSize(screenSize);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
public class BackPanel extends JPanel{
public boolean drawn = false;
public BackPanel(){
setVisible(true);
setOpaque(false);
setSize(screenSize);
JLabel test1 = new JLabel("Test1");
JLabel test2 = new JLabel("Test2");
add(test1);
add(test2);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
drawOnce(g);
}
public void drawOnce(Graphics g){
if (!drawn){
g.setColor(Color.red);
g.fillRect(0, 0, screenSize.width, 200);
drawn=true;
}
}
}
public class FrontPanel extends JPanel{
public FrontPanel(){
setVisible(true);
setOpaque(false);
setSize(screenSize);
JLabel test = new JLabel("Test");
add(test);
}
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(Color.blue);
g.fillRect(0+screenSize.width/2, 0, screenSize.width/4, 300);
}
}
}
Try RepaintManager.currentManager(component).markCompletelyClean(component). It will prevent the component from repainting. You might need to do this after each time you add new components.
http://docs.oracle.com/javase/6/docs/api/javax/swing/RepaintManager.html#markCompletelyClean%28javax.swing.JComponent%29
I don't know if this two lines of code
super.paintComponent(g);
drawOnce(g);
are the root of problem, I sincerly don't remember how paintComponent works (a test could help) but try to swap them :
drawOnce(g);
super.paintComponent(g);
maybe, on your original version, you tells JVM to paint the whole component and, only after the AWTEvent has been added to the queue, to draw what you need.
I guess that the awt's documentation will explain it.

Drawing with AWT and components in Java

I'm currently making a game in Java with AWT. The main class extends Frame, and I've been using it to draw the graphics using .getGraphics() and .drawRect(). This has been working fine, except that when I add components like labels to the frame it stops rendering the graphics and only displays the components.
Don't
Use getGraphics() to paint. That is not the proper way.
Try and paint on top-level containers like JFrame
Instead
Paint on a JPanel or JComponent (I prefer the former)
Override the paintComponent(Graphics g) method of the JPanel. Do all your painting in this method, use the implicitly passed Graphics context. You never have to actually call paintComponent as it will be implicitly called for you.
See
Performing Custom Painting for more details on painting in Swing
Edit
Just noticed you are using AWT. You really should consider upgrading to Swing. Otherwise, instead of paintComponent, you're going to want to override paint, as AWT components don't have a paintComponent method. But I strongly urge you to use Swing
Example (Using Swing)
public class SimplePaint {
public SimplePaint() {
JFrame frame = new JFrame();
frame.add(new DrawPanel());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
class DrawPanel extends JPanel {
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillRect(50, 50, 150, 150);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable(){
public void run() {
new SimplePaint();
}
});
}
}

Java: Undecorated JFrame not displaying Graphics?

I've been programming in Java for about six months now and have done many work with Graphics in JPanels and JFrames. But recently I got a problem. All the JFrames I've been making before were always setUndecorated(false), but I needed to make one that was setUndecorated(true). So I tried, like usual, just putting the frame.setUndecorated(true) above all the frame's specs, so it looked something like this:
public static void main(String[] args){
JFrame frame = new JFrame("Frame");
frame.setUndecorated(true);
frame.setSize(600, 800);
frame.setVisible(true);
frame.add(new custompanel());
}
And the custompanel class:
public class custompanel{
public void paintComponent(Graphics g){
g.fillRect(100, 100, 100, 100);
}
}
The g in custompanel doesn't paint anything.
However, if I remove the frame.setUndecorated(true) or change it to frame.setUndecorated(false) it will paint a rectangle.
Any thoughts?
Assuming CustomPanel extends JComponent or JPanel, make the frame visible after adding CustomPanel. Calling super.paintComponent(g) is a good idea to paint any background components.
frame.setVisible(true);

Painting on a JPanel inside a JScrollPane doesn't paint in the right location

So I have a JPanel that's inside a JScrollPane.
Now I am trying to paint something on the panel, but it's always in same spot.
I can scroll in all directions but it's not moving. Whatever I paint on the panel does not get scrolled.
I already tried:
A custom JViewPort
switching between Opaque = true and Opaque = false
Also I considered overriding the paintComponent method of the panel but that would be really hard to implement in my code.
public class ScrollPanePaint{
public ScrollPanePaint() {
JFrame frame = new JFrame();
final JPanel panel = new JPanel();
panel.setPreferredSize(new Dimension(1000, 1000));
//I tried both true and false
panel.setOpaque(false);
JScrollPane scrollPane = new JScrollPane(panel);
frame.add(scrollPane);
frame.setSize(200, 200);
frame.setVisible(true);
//To redraw the drawing constantly because that wat is happening in my code aswell because
//I am creating an animation by constantly move an image by a little
new Thread(new Runnable(){
public void run(){
Graphics g = panel.getGraphics();
g.setColor(Color.blue);
while(true){
g.fillRect(64, 64, 3 * 64, 3 * 64);
panel.repaint();
}
}
}).start();
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new ScrollPanePaint();
}
});
}
}
The mistake I make is probably very easy to fix, but I just can't figure out how.
How to implement the paintComponent() on JPanel?
Override getPreferredSize() method instead of using setPreferredSize()
final JPanel panel = new JPanel(){
#Override
public void paintComponent(Graphics g){
super.paintComponent(g);
// your custom painting code here
}
#Override
public Dimension getPreferredSize() {
return new Dimension(40, 40);
}
};
Some points:
Override JComponent#getPreferredSize() instead of using setPreferredSize()
Read more Should I avoid the use of set(Preferred|Maximum|Minimum)Size methods in Java Swing?
Use Swing Timer instead of Java Timer that is more suitable for Swing application.
Read more How to Use Swing Timers
Set default look and feel using UIManager.setLookAndFeel()
Read more How to Set the Look and Feel
How to fix animation lags in Java?

BG image with Swing without overriding paintComponent

I'm currently designing a menu with several screens with multiple buttons on each screen. To use buttons on top of the background image, which is in a jLabel (by default, I can't put buttons on TOP of the jLabel), I used GridBagLayout with two panels/menu screen, one panel containing the buttons (opaque = false) and one panel with the background image, or jLabel. In order to switch the current panels being displayed, depending on where the user is in the menu, I made each menu screen (aka. every 2 panels) in separate methods, not classes.
Now, I've come to the point where I'm working on parts of the interface that are unnecessarily complicated, and I don't feel GridBag will serve my purposes, so I was wondering if there was a different way to draw my background image, still being able to use my buttons on top of the image.
The most popular way I looked up was overriding the paintComponent method, but I can't do that, since I've made my JPanels in separate methods, not classes. They're all contained in my original JFrame.
Help would be greatly appreciated, thank you!
Just added this code, but my background remains white for some reason? Trying the other suggestion right now, thanks guys!
private void mainPanel() {
icon = new ImageIcon(getClass().getResource("/phantasma/menuv1.png"));
mainContainer1 = new javax.swing.JPanel() {
#Override
protected void paintComponent(Graphics g) {
g.drawImage(icon.getImage(), 0,0, null);
super.paintComponent(g);
}
};
BG image with Swing without overriding paintComponent
I have no idea why all the postings suggest doing custom painting for this. You would only do custom painting if you need to automatically scale the background image.
If you want the image painted at its real size then use a JLabel.
I can't put buttons on TOP of the jLabel),
Sure you can. Just set a LayoutManager for the JLabel and then you can add any component to it the same way you add components to a panel.
In my comment above I state:
You can always create an anonymous inner JPanel-derived class and override the paintComponent method there if need be.
As an example of what I mean, you can override paintComponent in any JPanel that you create whether it's derived from a stand-alone class or created within a method. For e.g.,
import java.awt.Dimension;
import java.awt.Graphics;
import javax.swing.*;
public class AnonInnerPanel {
private static void createAndShowGui() {
JPanel mainPanel = new JPanel() {
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(300, 200);
}
};
JFrame frame = new JFrame("AnonInnerPanel");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(mainPanel);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGui();
}
});
}
}

Categories

Resources