5

I'm learning Swing GUI design. One thing I haven't quite sorted out is how to add an add a Canvas to a specific location in a container.

More specifically: I create a Canvas class that uses Paint method. Object of this class is added to a Panel. What I do not quite understand, is how and where it is added to a Panel. In Tkinter Canvas is a widget that contains only an image, but in Swing there is no similar widget (probably not the best word) added to the Frame that contains only Canvas object and nothing else.

Sorry if it is too vague, I'm adding a self-contained code. Please ignore text fields and labels.

import java.awt.BorderLayout;
import java.awt.Canvas;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSeparator;
import javax.swing.JTextField;

//frame class
class frame_class2 extends JFrame implements ActionListener{
  //declare buttons
  JButton draw_button = new JButton("Draw");
  JButton quit_button= new JButton("Quit");
  JButton info_button = new JButton("Info");
  //declare labels
  JLabel x_loc = new JLabel("X:");
  JLabel y_loc = new JLabel("Y:");
  JLabel w_label= new JLabel("Width:");
  JLabel h_label = new JLabel("Height:");
  //Layout
  FlowLayout layout_frame1 = new FlowLayout();
  //Text boxes
  JTextField x_loc_box = new JTextField("0");
  JTextField y_loc_box = new JTextField("0");
  JTextField w_loc_box = new JTextField("100");
  JTextField h_loc_box = new JTextField("100");
  //Info 
  JOptionPane info1 = new JOptionPane();
  //Canvas
  //Canvas area1 = new Canvas();
  //Containers
  JPanel panel1 = new JPanel();
  JPanel panel2= new JPanel();
  //Container container3 = new Container();
  Container con = getContentPane();


  public frame_class2(){    
    //panel1 = getContentPane();
    //add(area1);
    //add labels to the first panel
    panel1.setLayout(layout_frame1);
    panel2.setLayout(layout_frame1);
    panel1.add(x_loc);
    panel1.add(x_loc_box);
    panel1.add(y_loc);
    panel1.add(y_loc_box);
    panel1.add(w_label);
    panel1.add(w_loc_box);
    panel1.add(h_label);
    panel1.add(h_loc_box);
    //add buttons to the second panel
    draw_button.addActionListener(this);
    quit_button.addActionListener(this);
    info_button.addActionListener(this);
    panel2.add(draw_button);
    panel2.add(quit_button);
    panel2.add(info_button);

    con.add(panel1, BorderLayout.NORTH);
    //con.add(new JSeparator(), BorderLayout.CENTER);

    con.add(panel2, BorderLayout.SOUTH);
    setDefaultCloseOperation(super.EXIT_ON_CLOSE);
    setTitle("Graphics Toolbox v2");
     //Set up the content pane.
      //this.getContentPane();
    pack();
    //setSize(500, 500);
    setLocationRelativeTo(null);
    //setBackground(Color.BLUE);
    setVisible(true);
  }

  @Override
  public void actionPerformed(ActionEvent e) {
    // TODO Auto-generated method stub
    if (e.getSource()==info_button){
        info1.showMessageDialog(this, "hahahahahaha"); 
    }
    else if (e.getSource()==quit_button){
        System.exit(0);
    }
    else if (e.getSource()==draw_button){

        graphics_class2 input1 = new graphics_class2();
        con.add(input1);        
        //info1.showMessageDialog(this, "Not yet!");

    }


  }



}

//graphics class
class graphics_class2 extends Canvas{

  public graphics_class2(){
    //frame_class1 inst1 = new frame_class1();
    //Canvas img1 = inst1.area1;
    setSize(50,50);
    //setBackground(Color.BLUE);
  }

  public void paint(Graphics g){
    super.paint(g); 
    g.setColor(Color.GREEN);
    g.fillArc(0, 0, 50, 50, 50, 50);

  }



}



public class main_code {

    public static void main(String args[]){
    frame_class2 inst1 = new frame_class2();
    }



}
Alex
  • 944
  • 4
  • 15
  • 28

2 Answers2

4

"Swing programs should override paintComponent() instead of overriding paint()."—Painting in AWT and Swing: The Paint Methods. JPanel or JComponent are common choices, as suggested here. You can control placement using a suitable layout.

Addendum: How does this relate to Canvas?

The class java.awt.Canvas is an AWT component; instead use the Swing component javax.swing.JPanel. Here's a variation of your program that merely selects a random color, but it might give you an idea how to address your other properties. There's a related example here.

image

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class MainCode {

    public static void main(String args[]) {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                MainView fc = new MainView();
            }
        });
    }

    private static class MainView implements ActionListener {

        private JFrame f = new JFrame();
        private JButton colorButton = new JButton("Color");
        private JButton quitButton = new JButton("Quit");
        private JButton infoButton = new JButton("Info");
        private JLabel x_loc = new JLabel("X:");
        private JLabel y_loc = new JLabel("Y:");
        private JLabel w_label = new JLabel("Width:");
        private JLabel h_label = new JLabel("Height:");
        private JTextField x_loc_box = new JTextField("0");
        private JTextField y_loc_box = new JTextField("0");
        private JTextField w_loc_box = new JTextField("100");
        private JTextField h_loc_box = new JTextField("100");
        private JOptionPane info1 = new JOptionPane();
        private JPanel panel1 = new JPanel();
        private JPanel panel2 = new JPanel();
        private GraphicsClass graphicsClass = new GraphicsClass();

        public MainView() {
            panel1.add(x_loc);
            panel1.add(x_loc_box);
            panel1.add(y_loc);
            panel1.add(y_loc_box);
            panel1.add(w_label);
            panel1.add(w_loc_box);
            panel1.add(h_label);
            panel1.add(h_loc_box);
            colorButton.addActionListener(this);
            quitButton.addActionListener(this);
            infoButton.addActionListener(this);
            panel2.add(colorButton);
            panel2.add(quitButton);
            panel2.add(infoButton);
            f.add(panel1, BorderLayout.NORTH);
            f.add(graphicsClass, BorderLayout.CENTER);
            f.add(panel2, BorderLayout.SOUTH);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.setTitle("Graphics Toolbox v2");
            f.pack();
            f.setLocationRelativeTo(null);
            f.setVisible(true);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == infoButton) {
                JOptionPane.showMessageDialog(f, "hahahahahaha");
            } else if (e.getSource() == quitButton) {
                System.exit(0);
            } else if (e.getSource() == colorButton) {
                graphicsClass.randomColor();
                graphicsClass.repaint();
            }
        }
    }

    private static class GraphicsClass extends JPanel {

        private static final int SIZE = 128;
        private static final Random r = new Random();
        private Color color = Color.green;

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

        public void randomColor() {
            this.color = new Color(r.nextInt());
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(color);
            int w = getWidth();
            int h = getHeight();
            g.fillArc(0, h / 4, w, h, 45, 90);
        }
    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
  • Does this mean I have to call a separate `JPanel` object for the image? – Alex Aug 24 '12 at 23:50
  • Yes, I would override `paintComponent()` in a `JPanel` subclass. Alternatively, see this [example](http://stackoverflow.com/a/7343420/230513) using `BufferedImage` – trashgod Aug 25 '12 at 00:49
  • Could you explain please how this relate to the Canvas? – Roman C Aug 26 '12 at 00:00
  • @RomanC: I've elaborated above, although I (incorrectly) thought I was responding to Alex. I would avoid mixing AWT and Swing components unnecessarily. – trashgod Aug 26 '12 at 06:24
  • 1
    Canvas is an AWT component. It's a "heavyweight" meaning it's peered with a native window - one provided by the OS. JPanel is a "lightweight" component. It's entirely a Swing abstraction. Heavyweight components like Canvas have quirks and are difficult to work with. Examples are resizing failures and vanishing pulldown menus. Just use the JPanel unless you have an absolutly terrific reason for using the Canvas (such as it's a JOGL GLCanvas and you need the speed). – Gene Aug 26 '12 at 06:25
  • @trashgod Do you understand that not using `Canvas` in the answer is off-topic and doesn't relate to the question until the question is edited so my response became obsolete. This is unhonest to unaccept solution without evidence. – Roman C Aug 26 '12 at 10:44
  • @trashgod I think that my answer was locked once accepted and after some time about a day it has been unaccepted. I don't understand such people. Or this a moderation activities accept than unaccept. – Roman C Aug 26 '12 at 11:43
  • @trashgod "A question with an accepted answer isn't as likely to receive further attention". "another comes in, uncovering the fact that previous one was in fact a bad hack". How came in, did you came in? Is my answer is a hack? – Roman C Aug 26 '12 at 11:51
  • @RomanC: Votes are locked, unless the post is edited, but un-accept can happen anytime; [26-May-2012](http://stackoverflow.com/users/230513/trashgod?tab=reputation&sort=time&StartDate=2012-08-26%2011:52:20Z&page=4) comes to mind, but I harbor no ill will. I value your participation; I rarely down-vote, and I'll try to remember to comment when I up-vote your answers going forward. – trashgod Aug 26 '12 at 11:58
  • @trashgod: thanks for the addendum. I'm experimenting with both `Canvas` and `Jpanel`, both seem to work fine. I guess the difference becomes obvious in large applications only. – Alex Aug 27 '12 at 06:46
  • @RomanC: I'm sorry for removing the acceptance for your answer. I would have accepted both if it were allowed. The thing is, it turned out that `validate()` does not update the component, `repaint()` does. – Alex Aug 27 '12 at 06:48
  • @Alex: Glad you got it sorted. See also [*Mixing heavy and light components*](http://java.sun.com/products/jfc/tsc/articles/mixing/) for some of the perils. – trashgod Aug 27 '12 at 10:22
  • @Alex I've just tried to answer to your question about `Canvas`. So, if the theme is no longer discussed I wash my hands. Thanks for your support. – Roman C Aug 27 '12 at 10:45
1

Appends the canvas to the end of this panel. A component has been added to a container that has been displayed, validate must be called on that container to display the new component.

Roman C
  • 49,761
  • 33
  • 66
  • 176