Paint Method is not Called - java

After making an instance in a previous frame, I'm trying to the background image on the next frame but as a result, I just saw the debugged result and found out that the paint method was not called. From what I know, the paint method is inherited by the JFrame class and with this logic, I've made it overrided. As I guess, the reason happen the logical error is from what I used the event handler and made the instance in the EventHandlerClass.
if(e.getActionCommand().equals(ButtonTo))
if(idString.equals("USER"))
{
{
if("1234".equals(pwSt))
{
System.out.println("Wellcome");
if(gs==null)
{
gs=new GameStart();
}
}
else
{
System.out.println("Confirm your password");
}
}
}
This is a code that If an action is performed it will make an instance(gs). After doing this, I noticed that the instance has been used as to make a new console frame.
class GameStart extends JFrame {
private Image screenImage;
private Graphics screenGraphic;
private Image introBackgroundImage;
private ImageIcon img;
GameStart()
{
JFrame jf=new JFrame("Game Set");
jf.setBounds(300, 300, 400, 200);
jf.setLayout(new BorderLayout());
JButton bt1=new JButton("Start");
JButton bt2=new JButton("Exit");
JPanel panel1=new JPanel();
panel1.add(bt1);panel1.add(bt2);
setContentPane(panel1);
jf.add(panel1, BorderLayout.SOUTH);
bt1.addActionListener(new Choice());
bt2.addActionListener(new Choice());
jf.setVisible(true);
img=new ImageIcon("./Images/backGroundImage.jpg");
System.out.println("1");
}
public void paint(Graphics g) {
screenImage=createImage(200, 200);
screenGraphic=screenImage.getGraphics();
screenDraw(screenGraphic);
g.drawImage(screenImage, 0, 0, null);
System.out.println("2");
}
public void screenDraw(Graphics g)
{
this.repaint();
System.out.println("3");
}
Now, With making a frame and some buttons, I expect to show all the numbers(1, 2, 3) that indicate the result but Just did number 1.

There are some errors in your code that I can see at first glance:
You're extending JFrame, but you're not adding any extra functionality to it, see: Extends JFrame vs. creating it inside the program. Instead, build your GUI towards the use of JPanels and override their paintComponent(...) method and not the paint(...) one.
You're breaking the paint-chain: After doing the above point, in paintComponent(), call super.paintComponent(...)
Maybe there are others but I'm currently busy and can't test your code, but the ones above should help with your issue.

Related

JPanel wont appear until being resized [duplicate]

I subclass JPanel to overwrite paintComponent(Graphics), I want to draw an image onto jpanel in a jframe.
But my image hasn't shown up until I make a change to jframe's size.
This is my code:
public class ImagePanel extends JPanel{
public void setImage(BufferedImage bi)
{
image = bi;
revalidate();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(image != null)
{
g.drawImage(image, 0, 0, this);
}
}
}
Verify that you invoke setVisible() after adding components and calling pack(), as discussed in this related example. You may also need to adopt an appropriate layout. Invoking repaint(), as suggested here, may fix the symptom but not the underlying cause.
Take a look at the docs for JPanel.add(), which it inherits from java.awt.Container:
Appends the specified component to the end of this container. This is a convenience method for addImpl(java.awt.Component, java.lang.Object, int).
This method changes layout-related information, and therefore, invalidates the component hierarchy. If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component.
Emphasis added.
Therefore, if you modify a Container after it's already been displayed, you must call validate() in order for it to show up. Just invoking repaint() is not enough. You may have noticed that calling setVisible(true) also works; this is because it calls validate() internally.
If you want to "refresh" the JPanel then you should call repaint(), which will call your paintComponent(). This should fix your problem:
public void setImage(BufferedImage bi)
{
image = bi;
EventQueue.invokeLater(new Runnable()
{
public void run()
{
repaint();
}
});
}
Its good practice to update and change the GUI using the EDT. Heres more info on the EDT if you're interested:
How does the event dispatch thread work?
repaint doesn't need to be called from the EDT. If you're changing the GUI, such as setting text to a JLabel, it should be inside of the EDT. Heres more information on what can be called outside of the EDT (courtesy of nIcE cOw):
Safe to use Component.repaint() outside EDT?
I had the same problem and fixed it by call setVisible(true); the JFrame I was using.
Example : if your JFrame does not update after using :
jframe.setContentPane(new MyContentPane());
fix it with :
jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);
I know that it sounds silly to do this even though your JFrame is already visible, but that's the only way I've found so far to fix this problem (the solution proposed above didn't work for me).
Here is a complete example. Run it and then uncomment the "f.setVisible(true);" instructions in classes Panel1 and Panel2 and you'll see the difference. Don't forget the imports (Ctrl + Shift + O for automatic imports).
Main class :
public class Main {
private static JFrame f;
public static void main(String[] args) {
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new Panel1(f));
f.pack();
f.setVisible(true);
}
}
Panel1 class :
public class Panel1 extends JPanel{
private JFrame f;
public Panel1(JFrame frame) {
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 1");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setContentPane(new Panel2(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
}
});
add(b);
}
}
Panel2 class :
public class Panel2 extends JPanel{
private JFrame f;
public Panel2(JFrame frame) {
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 2");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setContentPane(new Panel1(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
}
});
add(b);
}
}
Hope that helps.
Regards.
I also had same problem but I found a solution. Just create a jframe object on top and call jframe methods at the bottom like jf.pack(), jf.setVisible(), jf.setSize(), jf.setDefaultCloseOpetion() should be at the bottom of the all UIs added in that frame you will find it work great.

Why doesn't repaint() work when called by a method of an object of the same class?

In a program I'm building for my class I have the same class extending a Swing JPanel and implementing MouseListener, for which I use two instantiations - one to function as a JPanel, and the other as a mouse listener for that JPanel.
But when I click in the window, repaint() the MouseClicked method in the mouse listener fails to call the first object's paintComponent() method. For example:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestPanel extends JPanel implements MouseListener{
static boolean black;
static TestPanel test = new TestPanel();
public void mouseExited(MouseEvent e){}
public void mousePressed(MouseEvent e){}
public void mouseReleased(MouseEvent e){}
public void mouseEntered(MouseEvent e){}
public void mouseClicked(MouseEvent e){ //Expected behavior: the square turns black immediately
System.out.println("CLICK!");
black = true;
test.repaint(); //this fails
try{
Thread.sleep(3000);
}catch(Exception ex){}
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
System.out.println("Painting...");
g2d.setColor(Color.white);
if(black){
g2d.setColor(Color.black);
}
g2d.fillRect(0, 0, 200, 200);
}
public static void main(String[] args) throws InterruptedException{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.addMouseListener(new TestPanel());
test.setPreferredSize(new Dimension(200, 200));
frame.add(test);
frame.pack();
frame.setVisible(true);
while (true){
black = false;
test.repaint();
Thread.sleep(100);
}
}
}
If you watch what happens on a click, the screen stays white for the 3 seconds after the click is registered, until the loop starts up again, i.e., the repaint() call in the mouse listener didn't work. Why does this happen?
I'm guessing it would work if I made different classes for the objects, but I'm mostly curious as to why it doesn't work this way.
for which I use two instantiations - one to function as a JPanel, and the other as a mouse listener for that JPanel.
There is no need to do that. All you need is a single instance of the TestPanel class.
In the constructor of your TestPanel class you just add:
addMouseListener( this);
The get rid of the static variable for the TestPanel class.
Then the code in your main method should look something like:
//test.addMouseListener(new TestPanel());
//test.setPreferredSize(new Dimension(200, 200));
//frame.add(test);
frame.add( new TestPanel() );
Also, the TestPanel class should override the getPreferredSize() method to return the Dimension of your panel.
Read the section from the Swing tutorial on Custom Painting for a working example with a MouseListener.
The AWT thread is responsible for calling MouseListener and for repaint.
Inside the repaint(); method, the AWT thread is told to call the paint();
Just call it using a different thread. In general, it is a bad idea to do anything intensive with the AWT thread. It already does a lot, taking too much of its time will mess your GUI up.
Depending on your needs, this might work:
new Thread(()->{repaint();}).start();

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.

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?

JPanel doesn't update until resize Jframe

I subclass JPanel to overwrite paintComponent(Graphics), I want to draw an image onto jpanel in a jframe.
But my image hasn't shown up until I make a change to jframe's size.
This is my code:
public class ImagePanel extends JPanel{
public void setImage(BufferedImage bi)
{
image = bi;
revalidate();
}
#Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
if(image != null)
{
g.drawImage(image, 0, 0, this);
}
}
}
Verify that you invoke setVisible() after adding components and calling pack(), as discussed in this related example. You may also need to adopt an appropriate layout. Invoking repaint(), as suggested here, may fix the symptom but not the underlying cause.
Take a look at the docs for JPanel.add(), which it inherits from java.awt.Container:
Appends the specified component to the end of this container. This is a convenience method for addImpl(java.awt.Component, java.lang.Object, int).
This method changes layout-related information, and therefore, invalidates the component hierarchy. If the container has already been displayed, the hierarchy must be validated thereafter in order to display the added component.
Emphasis added.
Therefore, if you modify a Container after it's already been displayed, you must call validate() in order for it to show up. Just invoking repaint() is not enough. You may have noticed that calling setVisible(true) also works; this is because it calls validate() internally.
If you want to "refresh" the JPanel then you should call repaint(), which will call your paintComponent(). This should fix your problem:
public void setImage(BufferedImage bi)
{
image = bi;
EventQueue.invokeLater(new Runnable()
{
public void run()
{
repaint();
}
});
}
Its good practice to update and change the GUI using the EDT. Heres more info on the EDT if you're interested:
How does the event dispatch thread work?
repaint doesn't need to be called from the EDT. If you're changing the GUI, such as setting text to a JLabel, it should be inside of the EDT. Heres more information on what can be called outside of the EDT (courtesy of nIcE cOw):
Safe to use Component.repaint() outside EDT?
I had the same problem and fixed it by call setVisible(true); the JFrame I was using.
Example : if your JFrame does not update after using :
jframe.setContentPane(new MyContentPane());
fix it with :
jframe.setContentPane(new MyContentPane());
jframe.setVisible(true);
I know that it sounds silly to do this even though your JFrame is already visible, but that's the only way I've found so far to fix this problem (the solution proposed above didn't work for me).
Here is a complete example. Run it and then uncomment the "f.setVisible(true);" instructions in classes Panel1 and Panel2 and you'll see the difference. Don't forget the imports (Ctrl + Shift + O for automatic imports).
Main class :
public class Main {
private static JFrame f;
public static void main(String[] args) {
f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setContentPane(new Panel1(f));
f.pack();
f.setVisible(true);
}
}
Panel1 class :
public class Panel1 extends JPanel{
private JFrame f;
public Panel1(JFrame frame) {
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 1");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setContentPane(new Panel2(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
}
});
add(b);
}
}
Panel2 class :
public class Panel2 extends JPanel{
private JFrame f;
public Panel2(JFrame frame) {
f = frame;
this.setLayout(new BoxLayout(this, BoxLayout.LINE_AXIS));
JButton b = new JButton("Panel 2");
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
f.setContentPane(new Panel1(f));
// Uncomment the instruction below to fix GUI "update-on-resize-only" problem
//f.setVisible(true);
}
});
add(b);
}
}
Hope that helps.
Regards.
I also had same problem but I found a solution. Just create a jframe object on top and call jframe methods at the bottom like jf.pack(), jf.setVisible(), jf.setSize(), jf.setDefaultCloseOpetion() should be at the bottom of the all UIs added in that frame you will find it work great.

Categories

Resources