4

i need your help badly because i cannot solve this problem on my own. I am trying to create a GUI and want to draw something in it after pressing a button, but i seem to have some kind of refresh/revalidate or threading issue. The drawing is painted, but when I resize the window, the painting disappears. Also, when moving the window very quickly, parts of the drawing disappear. I have tried many things, but I can't get this problem to work, maybe you can help me. I was instructed not to write my own code to begin with, but use the NetBeans Design functions to generate Buttons and Panels etc. Maybe this impairs the drawing process/functions, but I don't know. I'll post you the relevant code and would be very thankful for suggestions (the outcommented stuff are just artefacts from what I've tried before, so don't mind it):

public class NewJFrame extends JFrame  {
  public NewJFrame() { initComponents(); }

  @SuppressWarnings("unchecked")
  private void initComponents() {
    jButton1 = new javax.swing.JButton();
    jPanel1 = new javax.swing.JPanel();
    setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
    setMinimumSize(new java.awt.Dimension(1200, 1000));
    jButton1.setText("Draw");
    jButton1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        jButton1ActionPerformed(evt);
      }
    });
    GroupLayout jPanel1Layout = new GroupLayout(jPanel1);
    jPanel1.setLayout(jPanel1Layout);
    jPanel1Layout.setHorizontalGroup(
        jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGap(0, 1000, Short.MAX_VALUE)
    );
    jPanel1Layout.setVerticalGroup(
        jPanel1Layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGap(0, 0, Short.MAX_VALUE)
    );
    GroupLayout layout = new GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
        layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addComponent(jPanel1, GroupLayout.DEFAULT_SIZE, 1000, Short.MAX_VALUE)
            .addGap(18, 18, 18)
            .addComponent(jButton1)
            .addGap(33, 33, 33))
    );
    layout.setVerticalGroup(
        layout.createParallelGroup(GroupLayout.Alignment.LEADING)
        .addGroup(layout.createSequentialGroup()
            .addContainerGap()
            .addGroup(layout.createParallelGroup(GroupLayout.Alignment.LEADING)
                .addGroup(layout.createSequentialGroup()
                    .addGap(0, 745, Short.MAX_VALUE)
                    .addComponent(jButton1)
                    .addGap(237, 237, 237))
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(jPanel1, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                        .addContainerGap())))
    );

    pack();
  }// </editor-fold>

  private void jButton1ActionPerformed(ActionEvent evt) {
    Graphics g = jPanel1.getGraphics();
    draw(jPanel1, g);
  }

  protected void paintComponent(Graphics g){
    jPanel1.setSize(1000, 1000);
    Dimension d = jPanel1.getSize();
    g.setColor(Color.BLACK);
    for (int i=0; i<=1000;i++){
      if (i%100==0){
        g.setColor(Color.RED);
        g.drawLine(i, d.height/2, i, (d.height/2)+100);
      }
      else if(i%50==0 && i%100!=0){
        g.setColor(Color.BLUE);
        g.drawLine(i, d.height/2, i, (d.height/2)+100);
      }
      else {
        g.setColor(Color.BLACK);
        g.drawLine(i, d.height/2, i, (d.height/2)+100);
      }
    }
    g.setColor(Color.green);
    g.drawLine(0, d.height / 2, d.width, d.height / 2);
  }

  public void draw(JPanel Jpanel1, Graphics g) {
    System.out.println("wuffkowski");
    Jpanel1.setSize(1000,1000);
    Dimension d = Jpanel1.getSize();
    g.setColor(Color.BLACK);
    for (int i=0; i<=1000;i++){
      if (i%100==0){
        g.setColor(Color.RED);
        g.drawLine(i, d.height/2, i, (d.height/2)+100);
      }
      else if(i%50==0 && i%100!=0){
        g.setColor(Color.BLUE);
        g.drawLine(i, d.height/2, i, (d.height/2)+100);
      }
      else {
        g.setColor(Color.BLACK);
        g.drawLine(i, d.height/2, i, (d.height/2)+100);
      }
    }
    g.setColor(Color.green);
    g.drawLine(0, d.height / 2, d.width, d.height / 2);
    Jpanel1.paintComponents(g);
  }

  public static void lala () {
    try {
      for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
        if ("Nimbus".equals(info.getName())) {
          javax.swing.UIManager.setLookAndFeel(info.getClassName());
          break;
        }
      }
    } catch (ClassNotFoundException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (InstantiationException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (IllegalAccessException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    } catch (javax.swing.UnsupportedLookAndFeelException ex) {
      java.util.logging.Logger.getLogger(NewJFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        NewJFrame JF =new NewJFrame();
        JF.setVisible(true);
      }
    });
  }
  private javax.swing.JButton jButton1;
  private javax.swing.JPanel jPanel1;
}

Again thanks a lot for your precious time.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
user1365291
  • 55
  • 1
  • 1
  • 6
  • Please Learn [Java Naming Conventions](http://www.oracle.com/technetwork/java/codeconv-138413.html) and stick to them :-) – nIcE cOw Apr 30 '12 at 08:29

4 Answers4

6

Java doesn't remember drawing commands for you; your graphic is rendered once when you click the button because that's the only time when draw() is called.

If you want to refresh the rendering after a resize, override paint(Graphics) and call draw() in there.

If that is related to the button click, you must add fields to your class in which you remember everything that you need in draw() including the fact whether it should draw anything:

private boolean drawAtAll = false;

private void jButton1ActionPerformed(ActionEvent evt) {
  drawAtAll = true; // ok to draw now
  draw();
}

@Override
public void paint(Graphics g) {
   super.paint(g);
   draw();
}

public void draw() {
  if( !drawAtAll ) return;

  Graphics g = jPanel1.getGraphics();
  ...
}

Further reading:

Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820
  • thank you for your suggestion, I'm just trying it; makes sense what you mention. But result is by now: Still painting disappears when resizing the window, but not always ;). Sometimes after resizing, the drawing is still there. I'll just try to change things and tell you, what the results are. Thanks. – user1365291 Apr 30 '12 at 08:46
  • Painting isn't as simple as it looks. Read the two articles which I've mentioned. They will help you understand what is going on. After that, it should be much more simple for you to find&fix your problem. – Aaron Digulla Apr 30 '12 at 09:03
  • again thanks to you all for your help, i voted this one as "the answer" because basically the override of the paint method is what I use right now, but the other answers were helpful as well. However, I am still cheating to avoid the disappearing problem: Since i use the design section of NetBeans to use Swing, i unchecked the horizontal resizeable and vertical resizable buttons of my JPanel, which combined with the override of paint method and the fixation of a minimum size of my JFrame (as I told you, i still cannot fully trust my layout manager), it does the job. Thank you again. – user1365291 May 02 '12 at 11:47
5

Try your hands on this code, and ask any questions that may arise, do painting inside the paintComponent(...) method of the JPanel. Instead of providing size everytime for the said JComponent you can simply override getPreferredSize(), of the said component. In order to call your paintComponent(...) you can simply write repaint() instead of explicitly making a call to paintComponent(...) from within your program, Swing will do that automatically.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class PaintingExample
{
    private CustomPanel paintingPanel;
    private Timer timer;
    private int x = 1;
    private int y = 1;
    private ActionListener timerAction = new ActionListener()
    {
        public void actionPerformed(ActionEvent ae)
        {
            x++;
            y++;
            paintingPanel.setPosition(x, y);
        }
    };

    private void createAndDisplayGUI()
    {
        JFrame frame = new JFrame("Painting Example");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

        paintingPanel = new CustomPanel();
        final JButton startStopButton = new JButton("STOP");
        startStopButton.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent ae)
            {
                if (timer.isRunning())
                {
                    startStopButton.setText("START");
                    timer.stop();
                }
                else if (!timer.isRunning())
                {
                    startStopButton.setText("STOP");
                    timer.start();
                }
            }
        });

        frame.add(paintingPanel, BorderLayout.CENTER);
        frame.add(startStopButton, BorderLayout.PAGE_END);
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        timer = new Timer(100, timerAction);
        timer.start();
    }

    public static void main(String... args)
    {
        SwingUtilities.invokeLater(new Runnable()
        {
            public void run()
            {
                new PaintingExample().createAndDisplayGUI();
            }
        });
    }
}

class CustomPanel extends JPanel
{
    private int x = 0;
    private int y = 0;

    @Override
    public Dimension getPreferredSize()
    {
        return (new Dimension(800, 600));
    }

    public void setPosition(int a, int b)
    {
        x = a;
        y = b;
        if (x <(getWidth() - 10) && y < (getHeight() - 10))
            repaint();
        else
            System.out.println("Nothing is happening...");
    }

    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.clearRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.MAGENTA);
        g.fillOval(x, y, 10, 10);
    }
}
nIcE cOw
  • 24,468
  • 7
  • 50
  • 143
2

I did not went through all of your code, but what is immediately visible is that you should not override the paintComponent method without calling super.paintComponent. And your commented out line calls super.paintComponents (note the s), which is not the same.

I am also unsure what you mean 'when I resize the window', and how that is tied together with your Jpanel1.setSize( 1000, 1000 ) calls which appear all over your code. Your layout manager will take care of the size of the panel. You should not set that to a fixed size.

Robin
  • 36,233
  • 5
  • 47
  • 99
  • thank you very much, i will try it and answer you whether it worked. The out commented stuff just shows, that I had no idea what to put where and what to use anyways :p. so I just spammed different things i read somewhere that might help at different points of the code and see, what changed. but nothing did help :p EDIT: when i remove all set.Size methods, nothing is drawn anymore ;). This GUI stuff I never worked with before is really driving me nuts^^. – user1365291 Apr 30 '12 at 08:19
  • Ahha, too true, but looking closely the whole thing, I realized he is not overriding `paintComponent(...)` method, it is just a wicked name given to his own personal method, since he inherited `JFrame` and I guess it doesn't have such a method – nIcE cOw Apr 30 '12 at 08:22
  • yeah, you are right, i cannot call this method, seems i dont really call the paintComponent method^^. Based on your answeres and the one below, overriding the paint method seems to "work" when i dont set a size for the JFrame, but the first drawing is immediately drawn without pushing the button and is at the top of the Frame. Also, the layout concerning the button is wicked then. But I'll try on and let you know, whether it worked or not. – user1365291 Apr 30 '12 at 08:40
0

When you resize your panel or change it position or minimize it and maximize it, a paint(...) method is called that repaints the content. You have to overwrite this function and let it paint your line or what ever. To do this, you must probably save your drawing in a data-structure to be able to repaint it when every necessary.

The paint method is described here.

Thomas Uhrig
  • 30,811
  • 12
  • 60
  • 80