问题描述
作为一个更大项目的一部分,我正在尝试创建一个基本的 UI,它允许用户单击 JButton 以选择所需的颜色,然后允许该用户单击另一个 JButton 以指定要显示、填充的形状根据之前选择的颜色.我明白我必须利用动作事件.
请注意,我引用了这个类似的问题:
As part of a larger project I'm trying to create a basic UI that will allow a user to click a JButton to select a desired color and then allow that user to click another JButton to designate a shape to be displayed, filled in according to the previously selected color. I understand that I must make use of action events.
Please note I am referencing this similar question:
GUI Application that allows the user to choose the shape and color of a drawing
My code thus far is:
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import java.awt.*;
import java.awt.event.*;
public class GUI extends JFrame implements ActionListener, WindowListener
{
private final JButton circleButton, rectangleButton, redButton;
private final JButton greenButton, blueButton, exitButton;
private final JTextArea textArea;
private final JLabel label1;
private final JPanel colorPane;
private String shapeColor = "black";
private String actualShape = "rectangle";
private static final int ROWS = 2, COLS = 3;
public GUI (String title)
{
super(title);
//setResizable(false);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
colorPane = new JPanel();
label1 = new JLabel("current date here");
label1.setVerticalAlignment(SwingConstants.BOTTOM);
label1.setHorizontalAlignment(SwingConstants.LEFT);
label1.setPreferredSize(new Dimension(200,0));
getContentPane().add(label1, BorderLayout.WEST);
colorPane.setLayout(new GridLayout(ROWS,COLS));
getContentPane().add(colorPane, BorderLayout.CENTER);
redButton = makeButton("Red");
colorPane.add(redButton);
greenButton = makeButton("Green");
colorPane.add(greenButton);
blueButton = makeButton("Blue");
colorPane.add(blueButton);
rectangleButton = makeButton("Rectangle");
colorPane.add(rectangleButton);
circleButton = makeButton("Circle");
colorPane.add(circleButton);
exitButton = makeButton("Exit");
colorPane.add(exitButton);
textArea = new JTextArea(0,20);
getContentPane().add(textArea, BorderLayout.EAST);
pack();
}
public void paint(Graphics g, String color)
{
if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.BLUE);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.GREEN);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.RED);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.GREEN);
g.fillRect(50,90,100,50);
}
else if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.BLUE);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.RED);
g.fillOval(50, 180, 55, 55);
}
}
//method designed to create new JButtons while avoiding code duplication
private JButton makeButton(String text)
{
JButton b = new JButton(text);
b.setHorizontalAlignment(SwingConstants.LEFT);
b.addActionListener(this);
b.setPreferredSize(new Dimension(125,55));
return b;
}
@Override
public void windowOpened(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
@Override
public void windowClosed(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowIconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeiconified(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowActivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void windowDeactivated(WindowEvent e) {
// TODO Auto-generated method stub
}
@Override
public void actionPerformed(ActionEvent e)
{
System.out.println( ( (JButton)e.getSource() ).getText() + " button pressed ");
if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Red")) )
{
setShapeColor("Red");
System.out.println("selected color is: " + shapeColor + " selected shape is: " + actualShape);
//paint(this.getGraphics());
}
else if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Blue")) )
{
setShapeColor("Blue");
System.out.println("selected color is: " + shapeColor + " selected shape is: " + actualShape);
//paint(this.getGraphics());
}
else if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Green")) )
{
setShapeColor("Green");
System.out.println("selected color is: " + shapeColor + " selected shape is: " + actualShape);
//paint(this.getGraphics());
}
if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Rectangle")) )
{
setActualShape("rectangle");
System.out.println("selected shape is: " + actualShape + " selected color is: " + shapeColor);
paint(this.getGraphics(), shapeColor);
}
else if ( ( ((JButton) e.getSource()).getText().equalsIgnoreCase("Circle")) )
{
setActualShape("circle");
System.out.println("selected shape is: " + actualShape + " selected color is: " + shapeColor);
paint(this.getGraphics(), shapeColor);
}
}
public String getShapeColor() {
return shapeColor;
}
public void setShapeColor(String shapeColor) {
this.shapeColor = shapeColor;
}
public String getActualShape() {
return actualShape;
}
public void setActualShape(String actualShape) {
this.actualShape = actualShape;
}
public static void main(String[] args)
{
new GUI("My Gui").setVisible(true);
}
}
What I've thus far achieved is an output that shows both the selected color as well as the selected shape to be rendered in the selected color.
Furthermore, I've been successful in outputting a shape whose position is hard-coded but whose type (either circle or square) and whose color (red, blue or green), is correctly output as a result of the user clicks.
The final phase, upon which I am struggling, is the implementation of the shape's output so that the user's sequence of clicks determines the location and dimensions of the shape output to the screen.
The goal is to achieve the functionality demonstrated here:
I'm relatively certain that the correct solution is similar to the following code:
import java.util.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* Note: Normally the ButtonPanel and DrawingArea would not be static
classes.
* This was done for the convenience of posting the code in one class and
to
* highlight the differences between the two approaches. All the
differences
* are found in the DrawingArea class.
*/
public class DrawOnComponent
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
private static void createAndShowGUI()
{
DrawingArea drawingArea = new DrawingArea();
ButtonPanel buttonPanel = new ButtonPanel( drawingArea );
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("Draw On Component");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.getContentPane().add(drawingArea);
frame.getContentPane().add(buttonPanel, BorderLayout.SOUTH);
frame.setSize(400, 400);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
static class ButtonPanel extends JPanel implements ActionListener
{
private DrawingArea drawingArea;
public ButtonPanel(DrawingArea drawingArea)
{
this.drawingArea = drawingArea;
add( createButton(" ", Color.BLACK) );
add( createButton(" ", Color.RED) );
add( createButton(" ", Color.GREEN) );
add( createButton(" ", Color.BLUE) );
add( createButton(" ", Color.ORANGE) );
add( createButton(" ", Color.YELLOW) );
add( createButton("Clear Drawing", null) );
}
private JButton createButton(String text, Color background)
{
JButton button = new JButton( text );
button.setBackground( background );
button.addActionListener( this );
return button;
}
public void actionPerformed(ActionEvent e)
{
JButton button = (JButton)e.getSource();
if ("Clear Drawing".equals(e.getActionCommand()))
drawingArea.clear();
else
drawingArea.setForeground( button.getBackground() );
}
}
static class DrawingArea extends JPanel
{
private final static int AREA_SIZE = 400;
private ArrayList<ColoredRectangle> coloredRectangles = new ArrayList<ColoredRectangle>();
private Rectangle shape;
public DrawingArea()
{
setBackground(Color.WHITE);
MyMouseListener ml = new MyMouseListener();
addMouseListener(ml);
addMouseMotionListener(ml);
}
@Override
public Dimension getPreferredSize()
{
return isPreferredSizeSet() ?
super.getPreferredSize() : new Dimension(AREA_SIZE, AREA_SIZE);
}
@Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
// Custom code to paint all the Rectangles from the List
Color foreground = g.getColor();
g.setColor( Color.BLACK );
g.drawString("Add a rectangle by doing mouse press, drag and release!", 40, 15);
for (DrawingArea.ColoredRectangle cr : coloredRectangles)
{
g.setColor( cr.getForeground() );
Rectangle r = cr.getRectangle();
g.drawRect(r.x, r.y, r.width, r.height);
}
// Paint the Rectangle as the mouse is being dragged
if (shape != null)
{
Graphics2D g2d = (Graphics2D)g;
g2d.setColor( foreground );
g2d.draw( shape );
}
}
public void addRectangle(Rectangle rectangle, Color color)
{
// Add the Rectangle to the List so it can be repainted
ColoredRectangle cr = new ColoredRectangle(color, rectangle);
coloredRectangles.add( cr );
repaint();
}
public void clear()
{
coloredRectangles.clear();
repaint();
}
class MyMouseListener extends MouseInputAdapter
{
private Point startPoint;
public void mousePressed(MouseEvent e)
{
startPoint = e.getPoint();
shape = new Rectangle();
}
public void mouseDragged(MouseEvent e)
{
int x = Math.min(startPoint.x, e.getX());
int y = Math.min(startPoint.y, e.getY());
int width = Math.abs(startPoint.x - e.getX());
int height = Math.abs(startPoint.y - e.getY());
shape.setBounds(x, y, width, height);
repaint();
}
public void mouseReleased(MouseEvent e)
{
if (shape.width != 0 || shape.height != 0)
{
addRectangle(shape, e.getComponent().getForeground());
}
shape = null;
}
}
class ColoredRectangle
{
private Color foreground;
private Rectangle rectangle;
public ColoredRectangle(Color foreground, Rectangle rectangle)
{
this.foreground = foreground;
this.rectangle = rectangle;
}
public Color getForeground()
{
return foreground;
}
public void setForeground(Color foreground)
{
this.foreground = foreground;
}
public Rectangle getRectangle()
{
return rectangle;
}
}
}
}
and as a hard-coded exercise I have included the following in my code:
public void paint(Graphics g, String color)
{
if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.BLUE);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.GREEN);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.RED);
g.fillRect(50, 90, 100, 50);
}
else if (shapeColor.equalsIgnoreCase("green") && actualShape.equalsIgnoreCase("rectangle"))
{
g.setColor(Color.GREEN);
g.fillRect(50,90,100,50);
}
else if (shapeColor.equalsIgnoreCase("blue") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.BLUE);
g.fillOval(50, 180, 55, 55);
}
else if (shapeColor.equalsIgnoreCase("red") && actualShape.equalsIgnoreCase("circle"))
{
g.setColor(Color.RED);
g.fillOval(50, 180, 55, 55);
}
}
}
The following is a suggested implementation, also incorporating the good guidance you got from Frakcool:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.Point;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Rectangle2D;
import java.util.HashMap;
import java.util.Map;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.JToggleButton;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
public class GUI
{
private final ButtonGroup colorGroup; //group buttons
private final ButtonGroup shapeGroup; //so only one can be selected at any given time
private final Map<String, Color> colors; //map colors to it names.
private Color color; // color for painting
private Shape shape; //shape to paint
private JFrame frame;
private JPanel buttonsPane;
private JTextArea textArea;
private static final int ROWS = 2, COLS = 3;
private static final String[] BUTTONS_LABELS = {"Rectangle", "Circle", "Exit"};
public GUI()
{
shapeGroup = new ButtonGroup(); colorGroup = new ButtonGroup();
colors = new HashMap<>();
colors.put("Red", Color.RED); colors.put("Green", Color.GREEN); colors.put("Blue", Color.BLUE);
}
private void createAndShowGUI(String title) {
frame = new JFrame(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//use a GridLayout for the buttons pane
buttonsPane = new JPanel();
buttonsPane.setLayout(new GridLayout(ROWS, COLS));
frame.getContentPane().add(buttonsPane, BorderLayout.CENTER);//each BorderLayout position can hold ONE component
for(String colorName : colors.keySet()){
JToggleButton button = makeButton(colorName);
buttonsPane.add(button);
colorGroup.add(button);
button.addActionListener(changeColorAction());
}
for(String text : BUTTONS_LABELS){
JToggleButton button = makeButton(text);
buttonsPane.add(button);
shapeGroup.add(button);
button.addActionListener(changeShapeAction());
}
setDefaults();
frame.getContentPane().add(new Draw(), BorderLayout.WEST);
textArea = new JTextArea(0,20);
frame.getContentPane().add(textArea, BorderLayout.EAST);
frame.pack();
frame.setVisible(true);
}
private JToggleButton makeButton(String text) {
JToggleButton b = new JToggleButton(text); //use toggle buttons
b.setHorizontalAlignment(SwingConstants.LEFT);
b.setPreferredSize(new Dimension(100, 80)); //set preferred and let Layout manager do its work
return b;
}
private ActionListener changeColorAction() {
return e->{
color = colors.get(((JToggleButton)e.getSource()).getText());
frame.repaint();
};
}
private ActionListener changeShapeAction() {
return e->{
switch (((JToggleButton)e.getSource()).getText()){
case "Circle":
shape = Shape.CIRCLE;
break;
case "Rectangle":
shape = Shape.RECTANGLE;
break;
default: System.exit(0);
}
frame.repaint();
};
}
private void setDefaults() {
colorGroup.getElements().nextElement().setSelected(true);
color = colors.get(colorGroup.getElements().nextElement().getText());
shapeGroup.getElements().nextElement().setSelected(true);
shape = Shape.RECTANGLE;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new GUI().createAndShowGUI("My Gui"));
}
class Draw extends JPanel{
private final Point[] points; // an array to hold clicked points
private int mouseClicks = 0;
private static final int POINT_SIZE = 2;
Draw(){
setLayout(new BorderLayout());
setBackground(Color.WHITE);
setPreferredSize(new Dimension(200, 200));
JLabel help = new JLabel("Click 2 points to draw");
help.setHorizontalAlignment(SwingConstants.CENTER);
add(help, BorderLayout.PAGE_START);
JLabel timeLabel = new JLabel("current time here");
timeLabel.setHorizontalAlignment(SwingConstants.LEFT);
add(timeLabel, BorderLayout.PAGE_END);
points = new Point[2];
addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e) {
addPoint(e.getX(), +e.getY() );
}
});
}
@Override
public void paintComponent(Graphics g){
super.paintComponent(g);
g.setColor(color);
for(Point point : points)
if(point != null){
g.drawOval(point.x, point.y, POINT_SIZE, POINT_SIZE);
}
drawShape((Graphics2D)g);
}
private void addPoint(int x, int y) {
if(mouseClicks ==2){
mouseClicks = 0;
points[1] = null;
}
points[mouseClicks++] = new Point(x, y);
repaint();
}
private void drawShape(Graphics2D g2d) {
if(points[0] == null || points[1] == null) return;
if(shape == Shape.RECTANGLE) {
drawRectangle(g2d);
}else{
drawCircle(g2d);
}
}
private void drawRectangle(Graphics2D g2D) {
int minX = Math.min(points[0].x, points[1].x);
int minY = Math.min(points[0].y, points[1].y);
int maxX = Math.max(points[0].x, points[1].x);
int maxY = Math.max(points[0].y, points[1].y);
int width = maxX - minX;
int height = maxY - minY;
Rectangle2D.Double rectangle = new Rectangle2D.Double(minX, minY, width, height);
g2D.draw(rectangle);
}
private void drawCircle(Graphics2D g2D) {
int minX = Math.min(points[0].x, points[1].x);
int minY = Math.min(points[0].y, points[1].y);
int maxX = Math.max(points[0].x, points[1].x);
int maxY = Math.max(points[0].y, points[1].y);
double dx = maxX - minX;
double dy = maxY - minY;
double radius = Math.sqrt(dx*dx + dy*dy)/2;
double centerX = minX + dx/2;
double centerY = minY + dy/2;
g2D.draw(new Ellipse2D.Double(centerX - radius , centerY - radius, 2* radius, 2* radius));
}
}
enum Shape {
RECTANGLE, CIRCLE
}
}
这篇关于如何输出用户选择的形状 &颜色,其位置和尺寸取决于用户点击的坐标位置的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!