简体   繁体   中英

Clicking a button within a JFrame passes an data to a JPanel

I have a Jframe with two buttons: '1' and '2'. Clicking the button '1' should display the capital letter A in the JPanel.

Code fore my JFrame:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class DrawFrame extends JFrame{
    private final int WIDTH = 500;
    private final int HEIGHT = 300;

    private JButton number1;
    private JButton number2;

    private JPanel numberPanel;
    private DrawPanel graphicsPanel;

    public DrawFrame()
    {
        createSelectionPanel();
        createGraphicsPanel();

        this.setSize(WIDTH, HEIGHT);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

    private void createSelectionPanel()
    {
        numberPanel = new JPanel();

        number1 = new JButton("1");
        number2 = new JButton("2");   

        numberPanel.setLayout(new GridLayout(2,2));
        numberPanel.add(number1);
        numberPanel.add(number2);

        this.add(numberPanel, BorderLayout.WEST);
    }

    private void createGraphicsPanel()
    {
        //instantiate drawing panel
        graphicsPanel = new DrawPanel();
        //add drawing panel to right
        add(graphicsPanel);
    }

    private class Number1ButtonListener implements ActionListener {
        public void actionPerformed (ActionEvent event) {
            Number number = new Number();
            number.setNumber('A');
        }
    }

    //creates a drawing frame
    public static void main(String[] args)
    {
        DrawFrame draw = new DrawFrame();
    }   
}

Code for my JPanel

import javax.swing.JPanel;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;

public class DrawPanel extends JPanel{
    public Coordinates current;

    public DrawPanel(){
        //nothing drawn initially
        current = null;

        //set white background for drawing panel
        setBackground(Color.WHITE);

        //add mouse listeners
        MouseHandler mouseHandler = new MouseHandler();
        this.addMouseListener(mouseHandler);
        this.addMouseMotionListener(mouseHandler);
    }

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

        if(current!=null){

I want to replace "A" with number.getNumber()

            g.drawString("A", current.getX(), current.getY());
        }
    }

    //class to handle all mouse events
    private class MouseHandler extends MouseAdapter implements MouseMotionListener
    {
        public void mousePressed(MouseEvent event)
        {
           current = new Coordinates(event.getX(), event.getY());
        }

        public void mouseReleased(MouseEvent event)
        {
            repaint();
        }
    }
}

I'm not sure if this is possible. So sorry if I am mistaken in my logic. Please provide an alternate way for me to approach this problem. Appreciate any guidance.

Thanks!

The Coordinates and Number classes weren't included, so I had to modify the code somewhat.

Here's the GUI I created.

开封信

The first thing I did was create a model class for the GUI. By creating a model class, I could make the display string and the drawing coordinate available to the view and the controller classes. This is a simple example of the model / view / controller pattern .

package com.ggl.drawing;

import java.awt.Point;

public class GUIModel {

    private String displayString;

    private Point coordinate;

    public GUIModel(String displayString) {
        this.displayString = displayString;
    }

    public Point getCoordinate() {
        return coordinate;
    }

    public void setCoordinate(int x, int y) {
        this.coordinate = new Point(x, y);
    }

    public void setCoordinate(Point coordinate) {
        this.coordinate = coordinate;
    }

    public void setDisplayString(String displayString) {
        this.displayString = displayString;
    }

    public String getDisplayString() {
        return displayString;
    }

}

Now that we have a model, lets look at the DrawFrame class.

package com.ggl.drawing;

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class DrawFrame implements Runnable {
    private final int WIDTH = 500;
    private final int HEIGHT = 300;

    private JFrame frame;

    private GUIModel model;

    public DrawFrame() {
        this.model = new GUIModel("A");
    }

    @Override
    public void run() {
        frame = new JFrame("Draw Letters");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        frame.add(createSelectionPanel(), BorderLayout.WEST);
        frame.add(new DrawPanel(WIDTH, HEIGHT, model), BorderLayout.CENTER);

        frame.pack();
        frame.setVisible(true);
    }

    private JPanel createSelectionPanel() {
        JPanel numberPanel = new JPanel();
        ButtonListener listener = new ButtonListener();

        JButton number1 = new JButton("A");
        number1.addActionListener(listener);

        JButton number2 = new JButton("B");
        number2.addActionListener(listener);

        numberPanel.setLayout(new GridLayout(0, 2));
        numberPanel.add(number1);
        numberPanel.add(number2);

        return numberPanel;
    }

    private class ButtonListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent event) {
            model.setDisplayString(event.getActionCommand());
        }
    }

    // creates a drawing frame
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new DrawFrame());
    }
}

I started the Java Swing application on the Event Dispatch thread with the call to the SwingUtilities invokeLater method.

I separated the JFrame construction from the 2 JPanels construction. I used a JFrame, rather than extend a JFrame. The only time you should extend any Java class is if you want to override one or more of the class methods.

I used the same ButtonListener for both JButtons. I'm guessing what you want, but I drew either an "A" or a "B", depending on which button you left clicked.

Let's look at the DrawPanel class.

package com.ggl.drawing;

import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

import javax.swing.JPanel;

public class DrawPanel extends JPanel {

    private static final long serialVersionUID = 3443814601865936618L;

    private GUIModel model;

    public DrawPanel(int width, int height, GUIModel model) {
        this.setPreferredSize(new Dimension(width, height));
        this.model = model;
        // add mouse listeners
        MouseHandler mouseHandler = new MouseHandler();
        this.addMouseListener(mouseHandler);
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        if (model.getCoordinate() != null) {
            Point p = model.getCoordinate();
            Font font = g.getFont().deriveFont(48F);
            g.setFont(font);
            g.drawString(model.getDisplayString(), p.x, p.y);
        }
    }

    // class to handle all mouse events
    private class MouseHandler extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent event) {
            model.setCoordinate(event.getPoint());
        }

        @Override
        public void mouseReleased(MouseEvent event) {
            DrawPanel.this.repaint();
        }

    }
}

The major change I made in this class was to use the paintComponent method, rather than the paint method. The paintComponent method is the correct method to override.

I set the size of the drawing panel in the DrawPanel constructor. It's much better to let Swing figure out the size of the JFrame. That's what the pack method in the DrawFrame run method does.

I increased the font size so you can see the drawn letter better.

I removed the mouse motion listener code, as it wasn't needed.

I hope this was helpful to you.

OK, all I know so far is that you want the text displayed in a JPanel to change if a button is pressed. If so, then your code looks to be way too complex for the job. Suggestions include:

  • Give the DrawingPanel a setter method, say, setText(String text) , that allows outside classes to change the text that it displays.
  • Within that method, set a field of DrawingPanel, say called text , and call repaint() .
  • Override DrawingPanel's paintComponent not its paint method, and call the super's method within your override.
  • Within the paintComponent method, call drawString to draw the String held by the text field, if the field is not null.
  • Give your buttons ActionListeners or AbstractActions that call the DrawingPanel's setText(...) method, setting the text to be displayed.

For example:

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;

import javax.swing.*;

public class DrawAorB extends JPanel {
    private DrawingPanel drawingPanel = new DrawingPanel(); 

    public DrawAorB() {
        JPanel btnPanel = new JPanel(new GridLayout(1, 0, 5, 5));
        btnPanel.add(new JButton(new ButtonAction("A")));
        btnPanel.add(new JButton(new ButtonAction("B")));

        setLayout(new BorderLayout());
        add(drawingPanel, BorderLayout.CENTER);
        add(btnPanel, BorderLayout.PAGE_END);
    }

    private class ButtonAction extends AbstractAction {
        public ButtonAction(String name) {
            super(name);
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String text = e.getActionCommand();
            drawingPanel.setText(text);
        }
    }

    private static void createAndShowGui() {
        JFrame frame = new JFrame("DrawAorB");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(new DrawAorB());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createAndShowGui();
            }
        });
    }
}

class DrawingPanel extends JPanel {
    private static final int PREF_W = 200;
    private static final int PREF_H = PREF_W;
    private String text = null;

    public void setText(String text) {
        this.text = text;  // set the JPanel's text
        repaint();  // and draw it
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (text != null) {
            int x = getWidth() / 2;
            int y = getHeight() / 2;
            // use FontMetrics if you want to center text better
            g.drawString(text, x, y);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        if (isPreferredSizeSet()) {
            return super.getPreferredSize();
        }
        return new Dimension(PREF_W, PREF_H);
    }
}

Even simpler, easier, and probably better would be to display the text within a JLabel as it's much easier to center this text.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM