Question

When I run my code, I expect to see a JPanel in my JFrame, but nothing shows up. I had a button in the frame, and it shows up. But the JPanel doesn't show up, I even colored it in red. Here is the code for my JPanel:

import java.awt.*;
import javax.swing.JPanel;
public class graphic extends JPanel {
    private static final long serialVersionUID = -3458717449092499931L;
    public Game game;
    public graphic(Game game){
    this.game = game;
    this.setPreferredSize(new Dimension(400,400));
    this.setBackground(Color.RED);
}
public void paintComponent(Graphics g){
    for (Line l:game.mirrors){
        g.setColor(Color.BLACK);
        g.drawLine(l.start.x, l.start.y, l.end.x, l.end.y);
    }
}
}

And my JFrame code:

import java.awt.Container;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.*;
public class Viewer implements ActionListener {
public JFrame frame;
public JButton drawShoot;
public boolean draw;
public Game game;
public graphic graphic;
public TimerTask timert;
public Timer timer;
public Viewer(){
    draw = true;
    game = new Game();
}
public static void main(String args[]){
    Viewer v = new Viewer();
    v.setup();
}
public void setup(){
    frame = new JFrame("Laser Stimulator");
    drawShoot = new JButton("Edit Mode");
    graphic = new graphic(game);
    graphic.repaint();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setBounds(300, 300, 600, 600);
    Container contentPane = frame.getContentPane();
    SpringLayout layout = new SpringLayout();
    contentPane.setLayout(layout);
    drawShoot.addActionListener(this);
    timert = new TimerTask() {
        @Override
        public void run() {

        }
    };
    timer =new Timer();
    timer.scheduleAtFixedRate(timert, 0, 1000/30);
    contentPane.add(graphic);
    layout.putConstraint(SpringLayout.NORTH, graphic, 0, SpringLayout.NORTH, contentPane);
    layout.putConstraint(SpringLayout.WEST, graphic, 0, SpringLayout.WEST, contentPane);
    frame.setVisible(true);
}
@Override
public void actionPerformed(ActionEvent e) {
    if (e.getSource()==drawShoot){
        draw = !draw;
        drawShoot.setText((draw)?"Edit Mode":"Shoot Mode");
    }
}
}
Était-ce utile?

La solution

So the basic problem is you failed to honor the paint chain. You must call super.paintXxx when ever you override on the paint methods...

This method must call super.paintComponent(g), because it's responsible for clearing the background ;)

public void paintComponent(Graphics g) {
    for (Line l : game.mirrors) {
        g.setColor(Color.BLACK);
        g.drawLine(l.start.x, l.start.y, l.end.x, l.end.y);
    }
}

enter image description here

public class QuickTestPaintPane {

    public static void main(String[] args) {
        new QuickTestPaintPane();
    }

    public QuickTestPaintPane() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                Viewer v = new Viewer();
                v.setup();

            }
        });
    }

    public class Viewer implements ActionListener {

        public JFrame frame;
        public JButton drawShoot;
        public boolean draw;
//        public Game game;
        public graphic graphic;
        public TimerTask timert;
        public Timer timer;

        public Viewer() {
            draw = true;
//            game = new Game();
        }

        public void setup() {
            frame = new JFrame("Laser Stimulator");
            drawShoot = new JButton("Edit Mode");
            graphic = new graphic();
//            graphic.repaint();
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setBounds(300, 300, 600, 600);
//            Container contentPane = frame.getContentPane();
            SpringLayout layout = new SpringLayout();
            frame.setLayout(layout);
            drawShoot.addActionListener(this);
            timert = new TimerTask() {
                @Override
                public void run() {
                }
            };
            timer = new Timer();
            timer.scheduleAtFixedRate(timert, 0, 1000 / 30);
            frame.add(graphic);
            layout.putConstraint(SpringLayout.NORTH, graphic, 0, SpringLayout.NORTH, frame.getContentPane());
            layout.putConstraint(SpringLayout.WEST, graphic, 0, SpringLayout.WEST, frame.getContentPane());
            frame.setVisible(true);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == drawShoot) {
                draw = !draw;
                drawShoot.setText((draw) ? "Edit Mode" : "Shoot Mode");
            }
        }
    }

    public class graphic extends JPanel {

        private static final long serialVersionUID = -3458717449092499931L;
//        public Game game;

//        public graphic(Game game) {
        public graphic() {
//            this.game = game;
            this.setPreferredSize(new Dimension(400, 400));
            this.setBackground(Color.RED);
        }

        public void paintComponent(Graphics g) {
            super.paintComponent(g);

            Graphics2D g2d = (Graphics2D) g;
            g2d.setColor(Color.BLACK);
            g2d.drawLine(0, 0, getWidth(), getHeight());
//            for (Line l : game.mirrors) {
//                g.setColor(Color.BLACK);
//                g.drawLine(l.start.x, l.start.y, l.end.x, l.end.y);
//            }
        }
    }
}

Autres conseils

@MadProgrammer has already answered this question (+1 to him). In most overriden methods there are calls to their super do not forget to honor this or else these small hiccups begin to surface.

On another note:

  • Dont call setBounds(..) on JFrame ( i cannot see why you need it) rather call JFrame#pack() before setting the JFrame visible.

  • No need to do frame.getContentPane() as of Java 6. Simply use: frame.add() or frame.setLayout(..).

    As a conveniance add and its variants, remove and setLayout have been overridden to forward to the contentPane as necessary.

  • You also have this:

    graphic = new graphic(game);
    graphic.repaint();
    

    I cannnot see why the call to repaint() will be necessary repaint() will be called the first time the component is visible

  • Rather override getPreferredSize of JPanel than calling setPreferredSize()

  • Do not implement an ActionListener in a class unless it will be accessed via other classes. Rather use an anonymous Listener like so:

    refresh.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (e.getSource() == drawShoot) {
                    draw = !draw;
                    drawShoot.setText((draw) ? "Edit Mode" : "Shoot Mode");
                }
            }
    
    });
    
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top