库文件解释
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
import java.util.List;
本实验作业使用了图形化界面进行交互,包括使用了窗口,面板,按钮和标签等元素所以文件首先导入了javax.swing.*
。
但是不满足绘图的需求,故而紧接着导入了java.awt.*
,同时该窗口有图形拖动以及点击按钮等需要监听鼠标事件的功能,awt
同时满足需求(java.awt.event.MouseAdapterhe
和java.awt.event.MouseEvent
)。
紧接着的java.util.List
接口和java.util.ArrayList
类,Arraylist
类对List
接口进行了实现,可以进行调用,仅仅在实现绘画三角形的时候需要用到,用于存储三角形的顶点
Shape.java——图形类
我们在绘图时,首先会想到要画什么,从画板的哪个位置下笔,画什么颜色,故而图形类应该包含:
String type; //用于存储图形种类
int x, y; //用于存储绘画起始坐标
Color color; //用于存储图形颜色(Color类定义于awt库中)
int width, height, radius, x1, x2, x3, y1, y2, y3; //用于存储输入的信息
double square, length;//用于存储面积和周长
同时,我们将拖动的状态的方法move(int x,int y)
也放在这里,用于获取拖动过后的图形的位置信息,具体实现如下:
class Shape {
private String type;
private int x, y;
private Color color;
private int width, height, radius, x1, x2, x3, y1, y2, y3;
public double square, length;
public Shape(String type, int x, int y, Color color, int width, int height) {
this.type = type;
this.x = x;
this.y = y;
this.color = color;
this.width = width;
this.height = height;
this.square = width * height;
this.length = (width + height) * 2;
}
public Shape(String type, int x, int y, Color color, int radius) {
this.type = type;
this.x = x;
this.y = y;
this.color = color;
this.radius = radius;
this.square = Math.PI * radius * radius;
this.length = 2 * Math.PI * radius;
}
public Shape(String type, int x, int y, Color color, Point[] points, double length) {
this.type = type;
this.color = color;
this.x1 = points[0].x + x;
this.y1 = points[0].y + y;
this.x2 = points[1].x + x;
this.y2 = points[1].y + y;
this.x3 = points[2].x + x;
this.y3 = points[2].y + y;
this.square = 0.5 * Math.abs(x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2));
this.length = length;
}
public String getType() {
return type;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Color getColor() {
return color;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
public int getRadius() {
return radius;
}
public int getX1() {
return x1;
}
public int getX2() {
return x2;
}
public int getX3() {
return x3;
}
public int getY1() {
return y1;
}
public int getY2() {
return y2;
}
public int getY3() {
return y3;
}
public void move(int dx, int dy) {
x += dx;
y += dy;
x1 += dx;
y1 += dy;
x2 += dx;
y2 += dy;
x3 += dx;
y3 += dy;
}
}
DrawingPanel.java——画板类
该类用于实现图形的绘画和鼠标事件的监听,因为鼠标拖动图形实质上是清除上一个位置的图形在下一个位置重新绘制,所以鼠标时间的监听方法也都在此类中实现:
大体思路:定义一个List
列表List<Shape> shapes
,用于存储图形,保证画板上的历史图形信息存在,每需要创建一个图形就调用add
方法加入shape
类的对象。
图形的绘画就直接通过java.awt.Graphics
类的setColor()
和各种绘图方法(三角形就用fillPolygon()
方法绘制三个顶点的多边形,圆形就用fillOval()
方法绘制高度和宽度相同的椭圆,矩形就用fillRect()
方法进行绘制)进行绘画。
对于鼠标事件的监听就通过重写MouseAdapter
类的mousePressed,mouseDragged,mouseReleased
等方法对需求的功能进行实现,同时自定义isMouseOverShape
方法判断鼠标是否在图形上
具体实现:
class DrawingPanel extends JPanel {
private List<Shape> shapes = new ArrayList<>();
private boolean dragging = false;
private Point dragStartPoint;
private Shape selectedShape;
public void addShape(Shape shape) {
shapes.add(shape);
}
protected void paintComponent(Graphics g) {
super.paintComponent(g);
for (Shape shape : shapes) {
g.setColor(shape.getColor());
switch (shape.getType()) {
case "Triangle":
int[] xPoints = {shape.getX1(), shape.getX2(), shape.getX3()};
int[] yPoints = {shape.getY1(), shape.getY2(), shape.getY3()};
g.fillPolygon(xPoints, yPoints, 3);
break;
case "Circle":
g.fillOval(shape.getX(), shape.getY(), shape.getRadius() * 2, shape.getRadius() * 2);
break;
case "Rectangle":
g.fillRect(shape.getX(), shape.getY(), shape.getWidth(), shape.getHeight());
break;
}
}
}
public DrawingPanel() {
MouseAdapter mouseHandler = new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
dragStartPoint = e.getPoint();
shows infos=new shows();
if (SwingUtilities.isRightMouseButton(e)) {
for (Shape shape : shapes) {
if (isMouseOverShape(shape, dragStartPoint.x, dragStartPoint.y)) {
infos.showShapeInfo(shape);
break;
}
}
} else {
for (Shape shape : shapes) {
if (isMouseOverShape(shape, dragStartPoint.x, dragStartPoint.y)) {
dragging = true;
selectedShape = shape;
break;
}
}
}
}
@Override
public void mouseDragged(MouseEvent e) {
if (dragging && selectedShape != null) {
Point currentPoint = e.getPoint();
int dx = currentPoint.x - dragStartPoint.x;
int dy = currentPoint.y - dragStartPoint.y;
selectedShape.move(dx, dy);
dragStartPoint = currentPoint;
repaint();
}
}
@Override
public void mouseReleased(MouseEvent e) {
dragging = false;
selectedShape = null;
}
};
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
private boolean isMouseOverShape(Shape shape, int mouseX, int mouseY) {
switch (shape.getType()) {
case "Triangle":
int[] xPoints = {shape.getX1()+getX(), shape.getX2()+getX(), shape.getX3()+getX()};
int[] yPoints = {shape.getY1()+getY(), shape.getY2()+getY(), shape.getY3()+getY()};
return new Polygon(xPoints, yPoints, 3).contains(mouseX, mouseY);
case "Circle":
return Math.sqrt(Math.pow(mouseX - (shape.getX() + shape.getRadius()), 2) + Math.pow(mouseY - (shape.getY() + shape.getRadius()), 2)) <= shape.getRadius();
case "Rectangle":
return mouseX >= shape.getX() && mouseX <= (shape.getX() + shape.getWidth()) && mouseY >= shape.getY() && mouseY <= (shape.getY() + shape.getHeight());
default:
return false;
}
}
}
Demo.java——程序入口文件
public class Demo extends JFrame {
public static DrawingPanel drawingPanel;
public Demo(){
setTitle("Shape Drawer");
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setSize((int) (screenSize.width * 0.7), (int) (screenSize.height * 0.7));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
setLayout(new BorderLayout());
shows draws=new shows();
drawingPanel = new DrawingPanel();
add(drawingPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
JButton triangleButton = new JButton("绘制三角形");
JButton circleButton = new JButton("绘制圆形");
JButton rectangleButton = new JButton("绘制矩形");
triangleButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
circleButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
rectangleButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
triangleButton.setPreferredSize(new Dimension(200, 75));
circleButton.setPreferredSize(new Dimension(200, 75));
rectangleButton.setPreferredSize(new Dimension(200, 75));
triangleButton.addActionListener(e -> draws.showTriangleDialog());
circleButton.addActionListener(e -> draws.showCircleDialog());
rectangleButton.addActionListener(e -> draws.showRectangleDialog());
buttonPanel.add(triangleButton);
buttonPanel.add(circleButton);
buttonPanel.add(rectangleButton);
add(buttonPanel, BorderLayout.SOUTH);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
Demo drawer = new Demo();
drawer.setVisible(true);
});
}
}
通过继承JFrame
类进行窗口创建,同时创建画板public static DrawingPanel drawingPanel
,以供后续的按钮点击,绘画图形事件进行调用.
在窗口创建时通过Toolkit.getDefaultToolkit().getScreenSize()
方法获取屏幕大小,自动创建适当大小的窗口,并通过JPanel,JButton
类创建按钮,并通过setFont()方法自定义部件上的字体,通过setPreferredSize()
方法自定义按钮大小方便与用户进行交互,通过add()
方法将各元素添加到窗口中。
同时通过addActionListener()
方法添加鼠标监听,点击不同的按钮进入到不同的方法。
infa.java——接口类定义
public interface infa {
public void showRectangleDialog();
public void showCircleDialog();
public void showTriangleDialog();
public void showShapeInfo(Shape shape);
}
定义四个show方法,分别用于实现点击不同按钮过后的事件。
shows.java——接口的具体实现
分别实现了infa.java中的四个接口,分别是在点击绘制三角形
,绘制圆形
,绘制矩形
和右键图形
过后的事件。
绘制三角形的时候会要求输入三条边,所以自定义了一个calculateTrianglePoints
方法通过三条边计算出三个点的坐标,点击确定创建按钮后会调用Demo的Demo.drawingPanel.addShape
方法进行图形的绘制,其他两种图形的接口方法实现几乎相同,但是对于三角形,如果用户输入的三条边无法构成一个三角形就会抛出异常IllegalArgumentException("输入的边长不能构成三角形");
右键显示图形信息则会直接调出shape类的length和square参数并add到弹窗上进行显示。
public class shows implements infa {
private Point[] calculateTrianglePoints(int sideA, int sideB, int sideC) {
int x1 = 50;
int y1 = 100;
int x2 = x1 + sideA;
int y2 = y1;
double angleB = Math.acos((sideA * sideA + sideC * sideC - sideB * sideB) / (2.0 * sideA * sideC));
int x3 = x1 + (int) (sideC * Math.cos(angleB));
int y3 = y1 - (int) (sideC * Math.sin(angleB));
return new Point[]{new Point(x1, y1), new Point(x2, y2), new Point(x3, y3)};
}
@Override
public void showCircleDialog() {
JDialog dialog = new JDialog();
dialog.setSize((int) (Toolkit.getDefaultToolkit().getScreenSize().width * 0.2), (int) (Toolkit.getDefaultToolkit().getScreenSize().height * 0.2));
dialog.setLayout(new GridLayout(3, 2));
dialog.setLocationRelativeTo(null);
JTextField colorField = new JTextField("#0000FF");
JTextField radiusField = new JTextField("50");
JLabel colorLabel = new JLabel("颜色 (十六进制码):");
JLabel radiusLabel = new JLabel("圆形半径:");
colorField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
radiusField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
radiusLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
colorLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
colorLabel.setHorizontalAlignment(JLabel.CENTER);
radiusLabel.setHorizontalAlignment(JLabel.CENTER);
dialog.add(colorLabel);
dialog.add(colorField);
dialog.add(radiusLabel);
dialog.add(radiusField);
JButton createButton = new JButton("创建圆形");
createButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
createButton.addActionListener(e -> {
String colorHex = colorField.getText();
int radius = Integer.parseInt(radiusField.getText());
Color color = Color.decode(colorHex);
Demo.drawingPanel.addShape(new Shape("Circle", 100, 50, color, radius));
dialog.dispose();
Demo.drawingPanel.repaint();
});
dialog.add(createButton);
dialog.setVisible(true);
}
@Override
public void showRectangleDialog() {
JDialog dialog = new JDialog();
dialog.setSize((int) (Toolkit.getDefaultToolkit().getScreenSize().width * 0.2), (int) (Toolkit.getDefaultToolkit().getScreenSize().height * 0.2));
dialog.setLayout(new GridLayout(4, 2));
dialog.setLocationRelativeTo(null);
JTextField colorField = new JTextField("#FF0000");
JTextField widthField = new JTextField("150");
JTextField heightField = new JTextField("100");
JLabel colorLabel = new JLabel("颜色 (十六进制码):");
JLabel widthLabel = new JLabel("矩形宽度:");
JLabel heightLabel = new JLabel("矩形高度:");
colorField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
widthField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
heightField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
widthLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
heightLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
colorLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
colorLabel.setHorizontalAlignment(JLabel.CENTER);
widthLabel.setHorizontalAlignment(JLabel.CENTER);
heightLabel.setHorizontalAlignment(JLabel.CENTER);
dialog.add(colorLabel);
dialog.add(colorField);
dialog.add(widthLabel);
dialog.add(widthField);
dialog.add(heightLabel);
dialog.add(heightField);
JButton createButton = new JButton("创建矩形");
createButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
createButton.addActionListener(e -> {
String colorHex = colorField.getText();
int width = Integer.parseInt(widthField.getText());
int height = Integer.parseInt(heightField.getText());
Color color = Color.decode(colorHex);
Demo.drawingPanel.addShape(new Shape("Rectangle", 100, 50, color, width, height));
dialog.dispose();
Demo.drawingPanel.repaint();
});
dialog.add(createButton);
dialog.setVisible(true);
}
@Override
public void showTriangleDialog() {
JDialog dialog = new JDialog();
dialog.setSize((int) (Toolkit.getDefaultToolkit().getScreenSize().width * 0.2), (int) (Toolkit.getDefaultToolkit().getScreenSize().height * 0.3));
dialog.setLayout(new GridLayout(5, 2));
dialog.setLocationRelativeTo(null);
JTextField colorField = new JTextField("#808080");
JTextField sideAField = new JTextField("100");
JTextField sideBField = new JTextField("100");
JTextField sideCField = new JTextField("100");
JLabel colorLabel = new JLabel("颜色 (十六进制码):");
JLabel sideALabel = new JLabel("边A:");
JLabel sideBLabel = new JLabel("边B:");
JLabel sideCLabel = new JLabel("边C:");
colorLabel.setHorizontalAlignment(JLabel.CENTER);
sideALabel.setHorizontalAlignment(JLabel.CENTER);
sideBLabel.setHorizontalAlignment(JLabel.CENTER);
sideCLabel.setHorizontalAlignment(JLabel.CENTER);
dialog.add(colorLabel);
dialog.add(colorField);
dialog.add(sideALabel);
dialog.add(sideAField);
dialog.add(sideBLabel);
dialog.add(sideBField);
dialog.add(sideCLabel);
dialog.add(sideCField);
JButton createButton = new JButton("创建三角形");
colorField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
colorLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
sideAField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
sideBField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
sideCField.setFont(new Font("微软雅黑", Font.PLAIN, 25));
sideALabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
sideBLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
sideCLabel.setFont(new Font("微软雅黑", Font.PLAIN, 25));
createButton.setFont(new Font("微软雅黑", Font.PLAIN, 25));
createButton.addActionListener(e -> {
try {
String colorHex = colorField.getText();
int sideA = Integer.parseInt(sideAField.getText());
int sideB = Integer.parseInt(sideBField.getText());
int sideC = Integer.parseInt(sideCField.getText());
if (sideA + sideB <= sideC || sideA + sideC <= sideB || sideB + sideC <= sideA) {
throw new IllegalArgumentException("输入的边长不能构成三角形");
}
Color color = Color.decode(colorHex);
Point[] trianglePoints = calculateTrianglePoints(sideA, sideB, sideC);
Demo.drawingPanel.addShape(new Shape("Triangle",500, 500, color, trianglePoints,sideA+sideB+sideC));
dialog.dispose();
Demo.drawingPanel.repaint();
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(dialog, "请输入有效的数字", "输入错误", JOptionPane.ERROR_MESSAGE);
} catch (IllegalArgumentException ex) {
JOptionPane.showMessageDialog(dialog, ex.getMessage(), "输入错误", JOptionPane.ERROR_MESSAGE);
}
});
dialog.add(createButton);
dialog.setVisible(true);
}
@Override
public void showShapeInfo(Shape shape) {
StringBuilder info = new StringBuilder();
info.append("图形类型: ").append(shape.getType()).append("\n");
if (shape.getType().equals("Triangle")) {
double area = shape.square;
double length = shape.length;
info.append("面积: ").append(area).append("\n");
info.append("周长: ").append(length).append("\n");
}
if (shape.getType().equals("Circle")) {
double area = shape.square;
double length = shape.length;
info.append("面积: ").append(area).append("\n");
info.append("周长: ").append(length).append("\n");
}if (shape.getType().equals("Rectangle")) {
double area = shape.square;
double length = shape.length;
info.append("面积: ").append(area).append("\n");
info.append("周长: ").append(length).append("\n");
}
Font font = new Font("微软雅黑", Font.PLAIN, 28);
JTextArea textArea = new JTextArea(info.toString());
textArea.setFont(font);
textArea.setEditable(false);
JScrollPane scrollPane = new JScrollPane(textArea);
scrollPane.setPreferredSize(new Dimension(300, 200));
JOptionPane.showMessageDialog(null, scrollPane, "图形信息", JOptionPane.PLAIN_MESSAGE);
}
}
易传承——灌水.cpp
一般一般,继续加油!