diff --git a/PaintingBoard.iml b/PaintingBoard.iml
index c90834f..615e3ef 100644
--- a/PaintingBoard.iml
+++ b/PaintingBoard.iml
@@ -7,5 +7,6 @@
+
\ No newline at end of file
diff --git a/src/Codes/shape/AbstractShape.java b/src/Codes/shape/AbstractShape.java
index 8fbfd3f..fea9f21 100644
--- a/src/Codes/shape/AbstractShape.java
+++ b/src/Codes/shape/AbstractShape.java
@@ -66,5 +66,4 @@ public abstract class AbstractShape implements Serializable {
*/
public abstract void draw(Graphics2D g);
-
}
\ No newline at end of file
diff --git a/src/Codes/shape/Brush.java b/src/Codes/shape/Brush.java
index a895dfd..596fb10 100644
--- a/src/Codes/shape/Brush.java
+++ b/src/Codes/shape/Brush.java
@@ -22,13 +22,11 @@ public Brush() {
@Override
public void draw(Graphics2D g) {
-
-
g.setPaint(color);
g.setStroke(new BasicStroke(0, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
for (int i = 0; i < 100; i++) {
- double d = (double) fx[i];
- double c = (double) fy[i];
+ double d = fx[i];
+ double c = fy[i];
g.drawLine((int) (x1 + d * Math.sin(d)), (int) (y1 + c * Math.sin(c)), (int) (x2 + d * Math.sin(d)),
(int) (y2 + c * Math.sin(c)));
}
diff --git a/src/Codes/shape/FillRect.java b/src/Codes/shape/FillRect.java
index 1f56087..f9de7de 100644
--- a/src/Codes/shape/FillRect.java
+++ b/src/Codes/shape/FillRect.java
@@ -2,11 +2,9 @@
import java.awt.*;
/**
- *
+ * 填充矩形
*/
public class FillRect extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/shape/FillRoundRect.java b/src/Codes/shape/FillRoundRect.java
index 3593f2a..015982b 100644
--- a/src/Codes/shape/FillRoundRect.java
+++ b/src/Codes/shape/FillRoundRect.java
@@ -3,10 +3,9 @@
import java.awt.*;
/**
+ * 填充圆角矩形
*/
public class FillRoundRect extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/shape/Hexagon.java b/src/Codes/shape/Hexagon.java
index 2e35b52..7a543ab 100644
--- a/src/Codes/shape/Hexagon.java
+++ b/src/Codes/shape/Hexagon.java
@@ -3,11 +3,9 @@
import java.awt.*;
/**
- *
+ * 六边形
*/
public class Hexagon extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/shape/Images.java b/src/Codes/shape/Images.java
index 3e346ad..9ee4845 100644
--- a/src/Codes/shape/Images.java
+++ b/src/Codes/shape/Images.java
@@ -3,15 +3,11 @@
import java.awt.*;
/**
- *
+ * 图片
*/
public class Images extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g) {
g.drawImage(image, 0, 0, board);
}
-
-
}
diff --git a/src/Codes/shape/Line.java b/src/Codes/shape/Line.java
index 6473538..7c1952d 100644
--- a/src/Codes/shape/Line.java
+++ b/src/Codes/shape/Line.java
@@ -3,12 +3,11 @@
import java.awt.*;
/**
- *
+ * 线段
*/
public class Line extends AbstractShape {
public Line() {
-
}
@Override
diff --git a/src/Codes/shape/Oval.java b/src/Codes/shape/Oval.java
index 7ac6e7f..231210d 100644
--- a/src/Codes/shape/Oval.java
+++ b/src/Codes/shape/Oval.java
@@ -3,11 +3,9 @@
import java.awt.*;
/**
- *
+ * 椭圆
*/
public class Oval extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/shape/Pencil.java b/src/Codes/shape/Pencil.java
index 4ac5322..88d4cb4 100644
--- a/src/Codes/shape/Pencil.java
+++ b/src/Codes/shape/Pencil.java
@@ -3,23 +3,16 @@
import java.awt.*;
/**
- *
+ * 铅笔
*/
public class Pencil extends AbstractShape {
-
-
public Pencil() {
-
}
-
@Override
public void draw(Graphics2D g) {
g.setPaint(color);
-
g.setStroke(new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
-
g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
g.drawLine(x1, y1, x2, y2);
}
}
diff --git a/src/Codes/shape/Pentagon.java b/src/Codes/shape/Pentagon.java
index d1d3c6a..14b852f 100644
--- a/src/Codes/shape/Pentagon.java
+++ b/src/Codes/shape/Pentagon.java
@@ -3,11 +3,9 @@
import java.awt.*;
/**
- *
+ * 五边形
*/
public class Pentagon extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/shape/Rectangle.java b/src/Codes/shape/Rectangle.java
index aabd895..e660d62 100644
--- a/src/Codes/shape/Rectangle.java
+++ b/src/Codes/shape/Rectangle.java
@@ -3,19 +3,14 @@
import java.awt.*;
/**
- *
+ * 矩形
*/
public class Rectangle extends AbstractShape {
-
-
public Rectangle() {
-
}
-
@Override
public void draw(Graphics2D g2d) {
-
g2d.setColor(color);
g2d.setStroke(new BasicStroke(width));
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
diff --git a/src/Codes/shape/RoundRect.java b/src/Codes/shape/RoundRect.java
index 3236527..624b5e9 100644
--- a/src/Codes/shape/RoundRect.java
+++ b/src/Codes/shape/RoundRect.java
@@ -3,13 +3,9 @@
import java.awt.*;
/**
- *
+ * 圆角矩形
*/
public class RoundRect extends AbstractShape {
- /**
- * 定义一个RoundRectangle类,继承Shape类,用于绘制一个圆角矩形
- */
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/shape/Select.java b/src/Codes/shape/Select.java
new file mode 100644
index 0000000..21e0a5a
--- /dev/null
+++ b/src/Codes/shape/Select.java
@@ -0,0 +1,73 @@
+package Codes.shape;
+
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import javax.swing.*;
+
+/**
+ * 可拖动矩形,边框为虚线,内部透明
+ */
+public class Select extends JPanel {
+ private int x, y, width, height;
+ private boolean dragging = false;
+ private int offsetX, offsetY;
+
+ public Select() {
+ setOpaque(false); // 透明背景
+ addMouseListener(new MouseAdapter() {
+ @Override
+ public void mousePressed(MouseEvent e) {
+ if (isInsideRectangle(e.getX(), e.getY())) {
+ dragging = true;
+ offsetX = e.getX() - x;
+ offsetY = e.getY() - y;
+ }
+ }
+
+ @Override
+ public void mouseReleased(MouseEvent e) {
+ dragging = false;
+ }
+ });
+
+ addMouseMotionListener(new MouseAdapter() {
+ @Override
+ public void mouseDragged(MouseEvent e) {
+ if (dragging) {
+ x = e.getX() - offsetX;
+ y = e.getY() - offsetY;
+ repaint();
+ }
+ }
+ });
+ }
+
+ public void setRectangle(int x, int y, int width, int height) {
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ repaint();
+ }
+
+ private boolean isInsideRectangle(int mouseX, int mouseY) {
+ return mouseX >= x && mouseX <= x + width && mouseY >= y && mouseY <= y + height;
+ }
+
+ @Override
+ protected void paintComponent(Graphics g) {
+ super.paintComponent(g);
+ Graphics2D g2d = (Graphics2D) g;
+
+ // 设置虚线边框
+ float[] dashPattern = {5, 5};
+ g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL, 0, dashPattern, 0));
+ g2d.setColor(Color.BLACK);
+ g2d.drawRect(x, y, width, height);
+
+ // 内部透明效果
+ g2d.setColor(new Color(255, 255, 255, 100));
+ g2d.fillRect(x, y, width, height);
+ }
+}
diff --git a/src/Codes/shape/Text.java b/src/Codes/shape/Text.java
index fff08e9..daaa02a 100644
--- a/src/Codes/shape/Text.java
+++ b/src/Codes/shape/Text.java
@@ -6,18 +6,12 @@
* 定义一个Text类,继承Shape类,用于文字输入
*/
public class Text extends AbstractShape {
-
-
-
@Override
public void draw(Graphics2D g) {
- //Font(String name, int style, int size)
g.setColor(color);
g.setFont(new Font(fontName, italic + boldType, fontSize));
if (s != null) {
-
g.drawString(s, x1, y1);
- //System.out.println(fontName+" "+s+" "+fontSize );
}
}
}
\ No newline at end of file
diff --git a/src/Codes/shape/Triangle.java b/src/Codes/shape/Triangle.java
index 344e71a..02063cf 100644
--- a/src/Codes/shape/Triangle.java
+++ b/src/Codes/shape/Triangle.java
@@ -6,8 +6,6 @@
* 定义一个Triangle类,继承Shape类,用于绘制一个三角形
*/
public class Triangle extends AbstractShape {
-
-
@Override
public void draw(Graphics2D g2d) {
g2d.setPaint(color);
diff --git a/src/Codes/start/Start.java b/src/Codes/start/Start.java
index 64ffd46..b5810dd 100644
--- a/src/Codes/start/Start.java
+++ b/src/Codes/start/Start.java
@@ -9,7 +9,7 @@ public class Start {
public static MyFrame wds;
public static void main(String[] args) {
-// try {
+// try
// //调用Windows的文件系统
// UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
// } catch (Exception e) {
diff --git a/src/Codes/tools/ColorPanel.java b/src/Codes/tools/ColorPanel.java
index 93d8b9f..68c5118 100644
--- a/src/Codes/tools/ColorPanel.java
+++ b/src/Codes/tools/ColorPanel.java
@@ -23,12 +23,12 @@ public class ColorPanel extends JPanel {
* 调色板
* 颜色数组,用来设置按钮的背景颜色
*/
- private final Color[] colors = {new Color(255, 255, 255), new Color(0, 0, 0), new Color(128, 128, 128),
- new Color(195, 195, 195), new Color(67, 0, 0, 255), new Color(185, 122, 87), new Color(255, 0, 0),
- new Color(255, 174, 201), new Color(255, 128, 0), new Color(0, 255, 0), new Color(255, 255, 0),
- new Color(34, 117, 76), new Color(128, 128, 0), new Color(0, 0, 255), new Color(0, 158, 158),
- new Color(255, 107, 39), new Color(56, 141, 246), new Color(163, 73, 164), new Color(200, 191, 231),
- new Color(87, 195, 169), new Color(8, 193, 194), new Color(24, 76, 64), new Color(168, 95, 223),
+ private final Color[] colors = {new Color(0, 0, 0), new Color(255, 255, 255), new Color(80, 79, 79),
+ new Color(128, 128, 128), new Color(67, 0, 0, 255), new Color(177, 96, 49), new Color(255, 0, 0),
+ new Color(255, 174, 201), new Color(255, 107, 39), new Color(255, 128, 0), new Color(255, 255, 0),
+ new Color(230, 218, 152), new Color(239, 233, 151), new Color(107, 251, 107), new Color(29, 29, 255),
+ new Color(0, 0, 255), new Color(26, 124, 232), new Color(104, 118, 198), new Color(163, 195, 241),
+ new Color(49, 75, 110), new Color(8, 193, 194), new Color(128, 44, 189), new Color(177, 121, 223),
new Color(199, 73, 4)};
public ColorPanel() {
@@ -39,7 +39,7 @@ private void addColorPanel() {
// 主面板添加左边面板
this.setPreferredSize(new Dimension(60, 60));
this.setLayout(null);
- this.setBackground(new Color(195, 195, 195));
+ this.setBackground(new Color(239, 238, 238));
// 左边面板添加子面板
JPanel panelDownChild = new JPanel();
@@ -76,7 +76,7 @@ private void addColorPanel() {
// 右面板
JPanel right = new JPanel();
- right.setBackground(new Color(195, 195, 195));
+ right.setBackground(new Color(239, 238, 238));
right.setLayout(new FlowLayout(FlowLayout.LEFT, 0, 0));
right.setPreferredSize(new Dimension(60, 240));
@@ -119,7 +119,7 @@ private void addColorPanel() {
JButton jbt = (JButton) e.getSource();
// 拿到被选中按钮的背景颜色
Color c = jbt.getBackground();
- // 把背景颜色复制给WIndowStart中的颜色属性
+ // 把背景颜色复制给WindowStart中的颜色属性
MyFrame.color = c;
MyFrame.itemList[MyFrame.index].color = c;
diff --git a/src/Codes/tools/DrawPanel.java b/src/Codes/tools/DrawPanel.java
index 6445fe6..3c21867 100644
--- a/src/Codes/tools/DrawPanel.java
+++ b/src/Codes/tools/DrawPanel.java
@@ -8,10 +8,13 @@
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionAdapter;
+import java.awt.geom.AffineTransform;
import java.io.Serial;
import java.util.Objects;
import static Codes.tools.MyFrame.*;
+import static java.lang.Math.abs;
+import static java.lang.Math.max;
/**
* 画图面板类,用来画图
@@ -20,6 +23,11 @@ public class DrawPanel extends JPanel {
@Serial
private static final long serialVersionUID = 1L;
+ private double zoomLevel = 1.0;
+ private double offsetX = 0, offsetY = 0;
+ private Image backgroundImage;
+ private int x1 = 0, x2 = 0, y1 = 0, y2 = 0;
+ private int currentX = 0, currentY = 0;
public DrawPanel() {
// 设置光标类型,为十字形
@@ -30,21 +38,51 @@ public DrawPanel() {
this.addMouseListener(new MouseAction());
this.addMouseMotionListener(new MouseMotion());
}
+ public void setBackgroundImage(Image image) {
+ this.backgroundImage = image;
+ repaint(); // 重新绘制面板
+ }
+
+ public void clearBackgroundImage() {
+ this.backgroundImage = null;
+ repaint(); // 重新绘制面板
+ }
+
+ public void setZoomAndOffset(double zoom, double offsetX, double offsetY) {
+ this.zoomLevel = zoom;
+ this.offsetX = offsetX;
+ this.offsetY = offsetY;
+ repaint();
+ }
// 重写paintComponent方法,使得画板每次刷新时可将之前的所有图形重新画出来。
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g; // 定义画板
- int j = 0;
- while (j <= index) {
- draw(g2d, itemList[j]);
- j++;
+ // 绘制背景图像
+ if (backgroundImage != null) {
+ g2d.drawImage(backgroundImage, 0, 0, getWidth(), getHeight(), this);
+ }
+
+ // 保存当前变换
+ AffineTransform originalTransform = g2d.getTransform();
+
+ // 应用缩放和平移
+ g2d.translate(offsetX, offsetY);
+ g2d.scale(zoomLevel, zoomLevel);
+ // 绘制所有图形
+ for (int j = 0; j <= index; j++) {
+ if (itemList[j] != null) {
+ draw(g2d, itemList[j]);
+ }
}
- }
+ // 恢复原始变换
+ g2d.setTransform(originalTransform);
+ }
void draw(Graphics2D g2d, AbstractShape abstractShape) {
// 将画笔传入到各个子类中,用来完成各自的绘图
abstractShape.draw(g2d);
@@ -57,7 +95,6 @@ public void undo() {
if (index > 0) { // 确保有图形可以撤销
index--; // 回退到上一个图形
// 如果当前选择的是铅笔、橡皮擦或刷子等工具(绘制多个点的图形)
-
if (itemList[index] != null) {
System.out.println(itemList[index].currentChoice);
if (itemList[index].currentChoice == 3 || itemList[index].currentChoice == 16
@@ -127,7 +164,7 @@ public void createNewGraphics() {
case 8 -> itemList[index] = new FillOval();
case 9 -> itemList[index] = new Circle();
case 10 -> itemList[index] = new FillCircle();
- case 11 -> itemList[index] = new RoundRect();
+ case 11 -> itemList[index] = new RoundRect();
case 12 -> itemList[index] = new FillRoundRect();
case 13 -> itemList[index] = new Triangle();
case 14 -> itemList[index] = new Pentagon();
@@ -148,7 +185,10 @@ public void createNewGraphics() {
itemList[index].color = color;
itemList[index].width = stroke;
itemList[index].currentChoice = currentChoice;
- //System.out.println(index);
+ itemList[index].x1 = -30;
+ itemList[index].y1 = -30;
+ itemList[index].x2 = -30;
+ itemList[index].y2 = -30;
}
// 鼠标事件mouseAction类,继承了MouseAdapter,用来完成鼠标相应事件操作
@@ -156,15 +196,18 @@ class MouseAction extends MouseAdapter {
@Override
public void mousePressed(MouseEvent e) {
// 设置状态提示
- statusBar.setText("坐标:[" + e.getX() + ", " + e.getY() + "]像素");
- itemList[index].x1 = itemList[index].x2 = e.getX();
- itemList[index].y1 = itemList[index].y2 = e.getY();
+ currentX = (int) (e.getX()/(zoomLevel/2+0.5));
+ currentY = (int) (e.getY()/(zoomLevel/2+0.5));
+ positionLabel.setText("坐标: [ " + currentX + ", " + currentY + " ]像素");
+ itemList[index].x1 = itemList[index].x2 = x1 = x2 = currentX;
+ itemList[index].y1 = itemList[index].y2 = y1 = y2 = currentY;
+ judgeSizeLabel();
// 如果当前选择的图形是画笔或者橡皮檫,则进行下面的操作
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
lengthCount = 0;
- itemList[index].x1 = itemList[index].x2 = e.getX();
- itemList[index].y1 = itemList[index].y2 = e.getY();
+ itemList[index].x1 = itemList[index].x2 = currentX ;
+ itemList[index].y1 = itemList[index].y2 = currentY;
index++;
lengthCount++;
createNewGraphics();
@@ -173,15 +216,21 @@ public void mousePressed(MouseEvent e) {
@Override
public void mouseReleased(MouseEvent e) {
- statusBar.setText("坐标:[" + e.getX() + ", " + e.getY() + "]像素");
+ currentX = (int) (e.getX()/(zoomLevel/2+0.5));
+ currentY = (int) (e.getY()/(zoomLevel/2+0.5));
+
+ positionLabel.setText("坐标: [ " + currentX + ", " + currentY + " ]像素");
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
- itemList[index].x1 = e.getX();
- itemList[index].y1 = e.getY();
+ itemList[index].x1 = currentX;
+ itemList[index].y1 = currentY;
itemList[index].length = lengthCount;
}
- itemList[index].x2 = e.getX();
- itemList[index].y2 = e.getY();
+ itemList[index].x2 = x2 = currentX;
+ itemList[index].y2 = y2 = currentY;
+
+ judgeSizeLabel();
+
repaint();
index++;
createNewGraphics();
@@ -189,12 +238,12 @@ public void mouseReleased(MouseEvent e) {
@Override
public void mouseEntered(MouseEvent e) {
- statusBar.setText("坐标:[" + e.getX() + ", " + e.getY() + "]像素");
+ positionLabel.setText("坐标: [ " + e.getX() + ", " + e.getY() + " ]像素");
}
@Override
public void mouseExited(MouseEvent e) {
- statusBar.setText("坐标:");
+ positionLabel.setText("坐标:");
}
}
@@ -204,25 +253,51 @@ public void mouseExited(MouseEvent e) {
class MouseMotion extends MouseMotionAdapter {
@Override
public void mouseDragged(MouseEvent e) {
- statusBar.setText("坐标:[" + e.getX() + "," + e.getY() + "]像素");
+ currentX = (int) (e.getX()/(zoomLevel/2+0.5));
+ currentY = (int) (e.getY()/(zoomLevel/2+0.5));
+
+ positionLabel.setText("坐标: [ " + currentX + ", " + currentY + " ]像素");
if (currentChoice == 3 || currentChoice == 16 || currentChoice == 17) {
- itemList[index - 1].x1 = itemList[index].x2 = itemList[index].x1 = e.getX();
- itemList[index - 1].y1 = itemList[index].y2 = itemList[index].y1 = e.getY();
+ itemList[index - 1].x1 = itemList[index].x2 = itemList[index].x1 = x2 = currentX;
+ itemList[index - 1].y1 = itemList[index].y2 = itemList[index].y1 = y2 = currentY;
index++;
lengthCount++;
createNewGraphics();
} else {
- itemList[index].x2 = e.getX();
- itemList[index].y2 = e.getY();
+ itemList[index].x2 = x2 = currentX;
+ itemList[index].y2 = y2 = currentY;
}
+
+ judgeSizeLabel();
repaint();
}
@Override
public void mouseMoved(MouseEvent e) {
- statusBar.setText("坐标:[" + e.getX() + "," + e.getY() + "]像素");
+ currentX = (int) (e.getX()/(zoomLevel/2+0.5));
+ currentY = (int) (e.getY()/(zoomLevel/2+0.5));
+
+ positionLabel.setText("坐标: [ " + currentX + ", " + currentY + " ]像素");
+ sizeLabel.setText("图形大小:");
}
}
+ public void setZoomLevel(double zoomLevel) {
+ this.zoomLevel = zoomLevel;
+ repaint(); // 重新绘制面板
+ }
+
+ private void judgeSizeLabel() {
+ if(currentChoice == 9|| currentChoice == 10){
+ int r = max(abs(x2-x1+1), abs(y2-y1+1));
+ sizeLabel.setText("图形大小: "+r+" × "+r+"像素");
+ }
+ else if(currentChoice != 3) {
+ sizeLabel.setText("图形大小: "+abs(x2-x1+1)+" × "+abs(y2-y1+1)+"像素");
+ }
+ else {
+ sizeLabel.setText("图形大小:");
+ }
+ }
}
diff --git a/src/Codes/tools/MyFrame.java b/src/Codes/tools/MyFrame.java
index 269d6d5..a85e482 100644
--- a/src/Codes/tools/MyFrame.java
+++ b/src/Codes/tools/MyFrame.java
@@ -3,8 +3,10 @@
import Codes.shape.*;
import javax.swing.*;
+import javax.swing.event.ChangeEvent;
import java.awt.*;
import java.awt.event.*;
+import java.awt.geom.AffineTransform;
import java.io.Serial;
import java.util.Objects;
@@ -17,8 +19,6 @@ public class MyFrame extends JFrame {
* 保存文件的标志
*/
public static int saved = 0;
-
-
/**
* 铅笔或橡皮擦图形的存储长度
*/
@@ -46,10 +46,31 @@ public class MyFrame extends JFrame {
* 画图区域
*/
public static DrawPanel drawingArea;
+ /**
+ * 画板大小
+ */
+ public static int width;
+ public static int height;
/**
* 底部状态栏
*/
- public static JLabel statusBar;
+ public static JPanel statusBar;
+ /**
+ * 页面布局管理器
+ */
+ public static GridBagConstraints gbc;
+ /**
+ * 位置信息
+ */
+ public static JLabel positionLabel;
+ /**
+ * 图形大小信息
+ */
+ public static JLabel sizeLabel;
+ /**
+ * 画布大小信息
+ */
+ public static JLabel canvasLabel;
/**
* 画笔粗细
*/
@@ -78,6 +99,11 @@ public class MyFrame extends JFrame {
*/
public static MySlide slider;
+ /**
+ * 缩放区域滑动条
+ */
+ public static MyZoom zoom;
+
public MyFrame() {
init();
}
@@ -87,25 +113,23 @@ private void init() {
// 设置标题
this.setTitle("画图");
// 设置窗口大小
- this.setSize(950, 600);
+ width = 1000;
+ height = 600;
+ this.setSize(width, height);
// 居中显示
this.setLocationRelativeTo(null);
setVisible(true);
+ this.setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
- /*
- 粗细调节滑动条
- */
+ //粗细调节滑动条
slider = new MySlide();
- this.add(slider, BorderLayout.EAST);
+ this.add(slider,BorderLayout.EAST);
// 添加菜单
menu = new MyMenu(this);
-
toolbar = new MyToolbar(this);
- /*
- 调色板
- */
+ //调色板
ColorPanel colorPanel = new ColorPanel();
add(colorPanel, BorderLayout.WEST);
@@ -120,16 +144,44 @@ private void init() {
// 创建各种基本图形的按钮
drawingArea = new DrawPanel();
this.add(drawingArea, BorderLayout.CENTER);
- statusBar = new JLabel();
- this.add(statusBar, BorderLayout.SOUTH);
- statusBar.setText("坐标");
+ zoom = new MyZoom(drawingArea);
+ //创建底部状态栏并设置布局
+ statusBar = new JPanel(new GridBagLayout());
+ gbc = new GridBagConstraints();
+ gbc.insets = new Insets(2, 5, 2, 5);
+ gbc.fill = GridBagConstraints.HORIZONTAL;
+
+ add(statusBar, BorderLayout.SOUTH);
+ gbc.gridx = 3;
+ gbc.weightx = 0.8;
+ statusBar.add(zoom,gbc);
+
+ //位置信息
+ positionLabel = new JLabel("坐标:");
+ positionLabel.setPreferredSize(new Dimension(100, 20));
+ gbc.gridx = 0;
+ gbc.weightx = 0.2;
+ statusBar.add(positionLabel, gbc);
+
+ //图形大小信息
+ sizeLabel = new JLabel("图形大小:");
+ sizeLabel.setPreferredSize(new Dimension(120, 20));
+ gbc.gridx = 1;
+ statusBar.add(sizeLabel, gbc);
+
+ //画布大小信息
+ canvasLabel = new JLabel("画布大小:");
+ canvasLabel.setPreferredSize(new Dimension(120, 20));
+ canvasLabel.setText("画布大小: "+width+" × "+height+"像素");
+ gbc.gridx = 2;
+ statusBar.add(canvasLabel, gbc);
/*
* 由于JLabel是透明的,当我们把JLabel控件加载到JPanel控件之上时, 会发现JLabel的背景色总是和JPanel的背景色保持一致,
*/
// 设置该组件为透明
statusBar.setOpaque(true);
- statusBar.setBackground(new Color(195, 195, 195));
+ statusBar.setBackground(new Color(239, 238, 238));
drawingArea.createNewGraphics();
this.addWindowListener(new WindowAdapter() {
@@ -146,8 +198,8 @@ public void windowClosing(WindowEvent e) {
}
}
});
-
+ this.revalidate(); // 重新验证组件布局
+ this.repaint(); // 强制刷新
}
-
}
diff --git a/src/Codes/tools/MyMenu.java b/src/Codes/tools/MyMenu.java
index 08e940d..d1cc998 100644
--- a/src/Codes/tools/MyMenu.java
+++ b/src/Codes/tools/MyMenu.java
@@ -4,6 +4,8 @@
import javax.imageio.ImageIO;
import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.InputEvent;
@@ -22,17 +24,15 @@ public class MyMenu {
private final String[] strokes = {"/image/stroke1.png", "/image/stroke2.png", "/image/stroke3.png",
"/image/stroke4.png"};
-
+ //private DrawPanel drawPanel;
public MyMenu(MyFrame frame) {
+
addMenu(frame);
}
void addMenu(MyFrame frame) {
- /*
- ** 顶部菜单条
- */
-
+ // 顶部菜单条
JMenuBar jMenuBar = new JMenuBar();
JMenuItem[] strokeItems = new JMenuItem[strokes.length];
// 实例化菜单对象
@@ -41,6 +41,7 @@ void addMenu(MyFrame frame) {
JMenu setMenu = new JMenu("设置");
JMenu helpMenu = new JMenu("帮助");
JMenu strokeMenu = new JMenu("粗细");
+ JMenu BGMenu =new JMenu("背景");
// 实例化菜单项,并通过ImageIcon对象添加图片 定义文件菜单的菜单项
JMenuItem fileItemNew = new JMenuItem("新建", new ImageIcon(getClass().getResource("/image/new.png")));
JMenuItem fileItemOpen = new JMenuItem("打开", new ImageIcon(getClass().getResource("/image/open.png")));
@@ -51,35 +52,89 @@ void addMenu(MyFrame frame) {
JMenuItem setItemUndo = new JMenuItem("撤销", new ImageIcon(getClass().getResource("/image/undo.png")));
JMenuItem helpItemUse = new JMenuItem("使用手册");
JMenuItem helpItemInfo = new JMenuItem("关于画图");
+
+ //背景选择
+ JMenuItem origin = new JMenuItem("原始模式");
+ origin.addActionListener(e -> {
+ drawingArea.clearBackgroundImage();
+ drawingArea.setBackground(Color.WHITE);
+ drawingArea.repaint(); // 刷新界面
+ });
+ JMenuItem black = new JMenuItem("黑夜模式");
+ black.addActionListener(e -> {
+ // 将画布背景设置为黑色
+ drawingArea.clearBackgroundImage();
+ drawingArea.setBackground(Color.BLACK); // 设置画布背景为黑色
+ drawingArea.repaint(); // 刷新界面
+ });
+ JMenuItem green = new JMenuItem("护眼模式");
+ green.addActionListener(e -> {
+ drawingArea.clearBackgroundImage();
+ // 将浮点数 RGB 值转换为整数
+ int r = (int) Math.round(199.00);
+ int g = (int) Math.round(237.00);
+ int b = (int) Math.round(204.00);
+
+ // 创建颜色对象
+ Color eyeProtectionColor = new Color(r, g, b);
+
+ // 设置背景颜色
+ drawingArea.setBackground(eyeProtectionColor);
+ drawingArea.repaint(); // 刷新界面
+ });
+ JMenuItem grid = new JMenuItem("网格纸");
+ grid.addActionListener(e -> {
+ // 加载图片
+ ImageIcon gridIcon = new ImageIcon(getClass().getResource("/image/grid.png"));
+ Image gridImage = gridIcon.getImage();
+
+ // 设置自定义背景面板
+ drawingArea.setBackgroundImage(gridImage); // 假设 DrawPanel 中有 setBackgroundImage 方法
+ drawingArea.repaint();
+ });
+ JMenuItem graph = new JMenuItem("坐标纸");
+ graph.addActionListener(e -> {
+ // 加载图片
+ ImageIcon gridIcon = new ImageIcon(getClass().getResource("/image/graph.png"));
+ Image gridImage = gridIcon.getImage();
+
+ // 设置自定义背景面板
+ drawingArea.setBackgroundImage(gridImage); // 假设 DrawPanel 中有 setBackgroundImage 方法
+ drawingArea.repaint();
+ });
+
+ BGMenu.add(origin);
+ BGMenu.add(black);
+ BGMenu.add(green);
+ BGMenu.add(grid);
+ BGMenu.add(graph);
for (int i = 0; i < 4; i++) {
strokeItems[i] = new JMenuItem("", new ImageIcon(getClass().getResource(strokes[i])));
strokeMenu.add(strokeItems[i]);
}
helpItemInfo.addActionListener(e -> JOptionPane.showMessageDialog(null,
"""
- 关于画图
- ****该软件由***开发完成****
- ****班级:计算机1602班 *****
- ****学号:00000000 *****
- ****邮箱:1111111@qq.com
+ ****该软件由软件学院2023级tjj,zyj,lyt开发完成****
+ ****项目地址:https://github.com/janeyujie/PaintingBoard
""",
"关于画图", JOptionPane.PLAIN_MESSAGE));
helpItemUse.addActionListener(e -> JOptionPane.showMessageDialog(null, """
- ##################\r
- #画图软件使用说明书#\r
- ####################\r
+ ********************\r
+ 画图软件使用说明书\r
+ ********************\r
1.本软件可以实现以下功能:\r
- (1)在画布上绘制直线、矩形、椭圆等图形\r
+ (1)依据鼠标轨迹绘制曲线\r
(2)设置画笔的颜色和粗细\r
- (3)绘制填充图形\r
- (4)依据鼠标轨迹绘制曲线\r
- (5)橡皮擦、保存图片\r
- 2.本软件主要分为四个模块:菜单、工具栏、调色板、和画布\r
+ (3)在画布上绘制直线、矩形、椭圆等图形\r
+ (4)绘制填充图形,橡皮擦擦去图形\r
+ (5)保存绘制结果为图片、导入图片\r
+ 2.本软件主要分为六个模块:菜单、工具栏、调色板、滑动条、状态栏和画布\r
(1)菜单栏的文件子菜单包括打开、新建、保存图片以及退出程序,设置有快捷键,方便操作,\r
- 菜单栏的设置子菜单包括设置画笔的粗细和颜色;\r
+ 菜单栏的设置子菜单包括设置画笔的粗细和颜色;背景子菜单可以选择画布的背景;\r
(2)工具栏主要包括保存文件、清空画板、撤回操作、图形绘制和文字的绘制;\r
(3)调色板位于界面的左侧,用于设置画笔的颜色,可以使用已设定的颜色,也可以自己选择系统提供的颜色;\r
- (4)画布用于图形绘制,使用鼠标选中要绘制的图形即可进行绘制。""", "使用说明", JOptionPane.PLAIN_MESSAGE));
+ (4)画布用于图形绘制,使用鼠标选中要绘制的图形即可进行绘制。
+ (5)滑动条用于调节画笔粗细,状态栏用于显示当前坐标以及绘制的图形大小。""", "使用说明", JOptionPane.PLAIN_MESSAGE));
helpMenu.add(helpItemUse);
helpMenu.add(helpItemInfo);
// 设置快捷键
@@ -96,12 +151,13 @@ void addMenu(MyFrame frame) {
fileMenu.add(fileItemSave);
fileMenu.add(fileItemExit);
setMenu.add(setItemColor);
- setMenu.add(setItemUndo);
setMenu.add(strokeMenu);
+ setMenu.add(setItemUndo);
// 添加菜单到菜单条
jMenuBar.add(fileMenu);
jMenuBar.add(setMenu);
+ jMenuBar.add(BGMenu);
jMenuBar.add(helpMenu);
// 添加菜单条
frame.setJMenuBar(jMenuBar);
@@ -220,59 +276,39 @@ void openFile() {
JOptionPane.showMessageDialog(fileChooser, "无效的文件名", "无效的文件名", JOptionPane.ERROR_MESSAGE);
}
- /*
- BufferedImage image;
-try {
- image = ImageIO.read(fileName);
- if (image == null) {
- JOptionPane.showMessageDialog(MyFrame.this, "无法读取图片!");
- return;
- }
-
- // 获取图片原始尺寸
- int imgWidth = image.getWidth();
- int imgHeight = image.getHeight();
-
- // 设置画布大小为图片大小
- drawingArea.setPreferredSize(new Dimension(imgWidth, imgHeight));
- drawingArea.revalidate();
- drawingArea.repaint();
-
- // 如果需要缩放图片适应画布(可选)
- int canvasWidth = drawingArea.getWidth();
- int canvasHeight = drawingArea.getHeight();
- if (canvasWidth > 0 && canvasHeight > 0) {
- // 按比例缩放图片
- Image scaledImage = image.getScaledInstance(canvasWidth, canvasHeight, Image.SCALE_SMOOTH);
- BufferedImage resizedImage = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB);
- Graphics2D g2d = resizedImage.createGraphics();
- g2d.drawImage(scaledImage, 0, 0, null);
- g2d.dispose();
- image = resizedImage;
- }
-
- // 更新画布显示图片
- index = 0;
- currentChoice = 0;
- drawingArea.createNewGraphics();
- itemList[index].image = image;
- itemList[index].board = drawingArea;
- drawingArea.repaint();
- index++;
- currentChoice = 3;
- drawingArea.createNewGraphics();
- ColorChanger colorChanger=new ColorChanger(drawingArea);
- colorChanger.processImage(image);
-} catch (IOException e) {
- e.printStackTrace();
-}
- * */
- BufferedImage image;
-
try {
index = 0;
currentChoice = 0;
- image = ImageIO.read(fileName);
+ BufferedImage image = ImageIO.read(fileName);
+
+ if (image == null) {
+ JOptionPane.showMessageDialog(Start.wds, "无法读取图片!");
+ return;
+ }
+
+ // 获取图片原始尺寸
+ int imgWidth = image.getWidth();
+ int imgHeight = image.getHeight();
+
+ // 设置画布大小为图片大小
+ drawingArea.setPreferredSize(new Dimension(imgWidth, imgHeight));
+ drawingArea.revalidate();
+ drawingArea.repaint();
+
+ // 如果需要缩放图片适应画布(可选)
+ int canvasWidth = drawingArea.getWidth();
+ int canvasHeight = drawingArea.getHeight();
+ if (canvasWidth > 0 && canvasHeight > 0) {
+ // 按比例缩放图片
+ Image scaledImage = image.getScaledInstance(canvasWidth, canvasHeight, Image.SCALE_SMOOTH);
+ BufferedImage resizedImage = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D g2d = resizedImage.createGraphics();
+ g2d.drawImage(scaledImage, 0, 0, null);
+ g2d.dispose();
+ image = resizedImage;
+ }
+
+ // 更新画布显示图片
drawingArea.createNewGraphics();
itemList[index].image = image;
itemList[index].board = drawingArea;
diff --git a/src/Codes/tools/MySlide.java b/src/Codes/tools/MySlide.java
index e735597..615e900 100644
--- a/src/Codes/tools/MySlide.java
+++ b/src/Codes/tools/MySlide.java
@@ -13,8 +13,7 @@ public class MySlide extends JPanel {
public JSlider slider;
public MySlide() {
- setBounds(450, 300, 50, 200);
-
+ setBounds(450, 300, 25, 150);
// 设置面板布局
setLayout(new BorderLayout());
@@ -28,17 +27,16 @@ public MySlide() {
slider.setUI(customUI);
// 显示当前值的标签
- JLabel label = new JLabel(": 1px", JLabel.CENTER);
+ JLabel label = new JLabel("1px", JLabel.CENTER);
label.setFont(new Font("Arial", Font.BOLD, 12));
// 添加滑动条监听器
slider.addChangeListener(_ -> {
-
// 动态更新画笔粗细
MyFrame.stroke = slider.getValue();
itemList[index].width = stroke;
- label.setText(": " + MyFrame.stroke + "px");
+ label.setText(MyFrame.stroke + "px");
});
// 鼠标移动事件监听,检测鼠标是否悬停在滑轮上
@@ -53,14 +51,14 @@ public void mouseMoved(MouseEvent e) {
});
// 限制滑动条高度
- slider.setPreferredSize(new Dimension(50, 150));
+ slider.setPreferredSize(new Dimension(35, 150));
// 添加组件到面板
add(slider, BorderLayout.CENTER);
add(label, BorderLayout.SOUTH);
// 设置外边距
- setBorder(BorderFactory.createEmptyBorder(50, 10, 50, 10));
+ setBorder(BorderFactory.createEmptyBorder(25, 10, 25, 10));
}
//重写BasicSliderUI类,更换滑轮的UI样式
private static class RoundThumbSliderUI extends BasicSliderUI {
diff --git a/src/Codes/tools/MyToolbar.java b/src/Codes/tools/MyToolbar.java
index 793087e..3a2dee1 100644
--- a/src/Codes/tools/MyToolbar.java
+++ b/src/Codes/tools/MyToolbar.java
@@ -12,7 +12,7 @@
*/
public class MyToolbar {
/**
- * 定义各种绘图的按钮
+ * 定义绘图按钮
*/
private JButton[] btnPaint;
private JComboBox jFont;
@@ -20,17 +20,15 @@ public class MyToolbar {
/**
* 将图片资源的相对路径存放于数组中,方便使用
*/
- private final String[] images = { "/image/save.png", "/image/refresh.png", "/image/undo.png", "/image/pencil.png",
+ private final String[] images = { "/image/save.png", "/image/refresh.png", "/image/undo.png","/image/pencil.png",
"/image/line.png", "/image/rectangle.png", "/image/rectangle3.png", "/image/oval.png",
"/image/oval2.png", "/image/circle.png", "/image/fillcircle.png", "/image/rectangle2.png",
"/image/rectangle4.png", "/image/triangle.png", "/image/pentagon.png", "/image/hexagon.png",
"/image/eraser.png", "/image/brush.png", "/image/font.png", };
- private final String[] tipText = { "保存", "清空", "撤销", "铅笔", "直线", "空心矩形", "填充矩形", "空心椭圆", "填充椭圆", "空心圆形", "填充圆形",
- "空心圆角矩形", "填充圆角矩形", "三角形", "五边形", "六边形", "橡皮擦", "填充", "文本", "粗细" };
+ private final String[] tipText = { "保存", "清空", "撤销", "铅笔", "直线", "矩形", "填充矩形", "椭圆", "填充椭圆", "圆形", "填充圆形",
+ "圆角矩形", "填充圆角矩形", "三角形", "五边形", "六边形", "橡皮擦", "刷子", "文本", "粗细" };
private final String[] font = { "宋体", "隶书", "华文彩云", "仿宋_GB2312", "华文行楷", "方正舒体" };
- private final String[] fontSize = { "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28",
- "36",
- "48", "72" };
+ private final String[] fontSize = { "8", "9", "10", "11", "12", "14", "16", "18", "20", "22", "24", "26", "28", "36", "48", "72" };
public MyToolbar(MyFrame myFrame) {
addToolbar(myFrame);
@@ -43,7 +41,7 @@ void addToolbar(MyFrame myFrame) {
toolbar.setLayout(new FlowLayout(FlowLayout.LEFT));
toolbar.setBackground(new Color(195, 195, 195));
- // 中文会乱码
+
// 粗体
Checkbox btnBold = new Checkbox("bold");
// 斜体
@@ -63,7 +61,7 @@ void addToolbar(MyFrame myFrame) {
// 设置按钮图标以及图片
for (int i = 0; i < images.length; i++) {
- // System.out.println(images[i]);//测试
+ //System.out.println(images[i]);//测试
btnPaint[i] = new JButton();
icon[i] = new ImageIcon(Objects.requireNonNull(getClass().getResource(images[i])));
btnPaint[i].setIcon(icon[i]);
@@ -113,8 +111,23 @@ void addToolbar(MyFrame myFrame) {
btnPaint[2].addActionListener(e -> drawingArea.undo());
// 添加监听
- btnItalic.addItemListener(e -> MyFrame.italic = Font.ITALIC);
- btnBold.addItemListener(e -> MyFrame.boldType = Font.BOLD);
+ // 添加监听
+ // 添加监听
+ btnItalic.addItemListener(e -> {
+ if (btnItalic.getState()) { // 判断是否选中
+ MyFrame.italic = Font.ITALIC; // 设置斜体
+ } else {
+ MyFrame.italic = Font.PLAIN; // 恢复普通字体
+ }
+ });
+
+ btnBold.addItemListener(e -> {
+ if (btnBold.getState()) { // 判断是否选中
+ MyFrame.boldType = Font.BOLD; // 设置粗体
+ } else {
+ MyFrame.boldType = Font.PLAIN; // 恢复普通字体
+ }
+ });
// 设置字体大小
toolbar.add(jFontSize);
diff --git a/src/Codes/tools/MyZoom.java b/src/Codes/tools/MyZoom.java
new file mode 100644
index 0000000..5b725ff
--- /dev/null
+++ b/src/Codes/tools/MyZoom.java
@@ -0,0 +1,220 @@
+package Codes.tools;
+
+import Codes.tools.DrawPanel;
+
+import javax.swing.*;
+import javax.swing.event.ChangeEvent;
+import javax.swing.event.ChangeListener;
+import javax.swing.plaf.basic.BasicSliderUI;
+import java.awt.*;
+import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
+import java.util.Hashtable;
+
+import static Codes.tools.MyFrame.*;
+
+public class MyZoom extends JPanel {
+
+ private double zoomLevel = 1.0; // 当前缩放比例
+ private DrawPanel drawingArea; // 绘图区域
+ private JSlider zoomSlider; // 缩放滑动条
+ private JLabel zoomValueLabel; // 显示缩放值的标签
+
+ public MyZoom(DrawPanel drawingArea) {
+ this.drawingArea = drawingArea;
+ initComponents();
+ }
+
+ private void initComponents() {
+ // 设置布局
+ //setLayout(new FlowLayout(FlowLayout.CENTER, 10, 5));
+
+ // 创建缩放滑动条
+ zoomSlider = new JSlider(JSlider.HORIZONTAL, 10, 40, 10); // 最小值 10,最大值 40,初始值 10
+ zoomSlider.setMajorTickSpacing(10); // 大刻度间隔
+ zoomSlider.setMinorTickSpacing(1); // 小刻度间隔
+ zoomSlider.setPaintTicks(false); // 显示刻度
+ zoomSlider.setPaintLabels(false); // 显示刻度标签
+ zoomSlider.setPreferredSize(new Dimension(200, 20)); // 设置滑动条大小
+ zoomSlider.setBorder(BorderFactory.createEmptyBorder(3,0,0,0));
+ // 应用自定义的滑轮UI
+ zoomSlider.setUI(new CustomSliderUI(zoomSlider));
+
+ //滑轮悬停效果
+ zoomSlider.addMouseListener(new MouseAdapter() {
+ @Override
+ public void mouseEntered(MouseEvent e) {
+ ((CustomSliderUI) zoomSlider.getUI()).setHover(true); // 鼠标悬停时设置滑轮为悬停状态
+ zoomSlider.repaint();
+ }
+
+ @Override
+ public void mouseExited(MouseEvent e) {
+ ((CustomSliderUI) zoomSlider.getUI()).setHover(false); // 鼠标移出时取消悬停状态
+ zoomSlider.repaint();
+ }
+ });
+
+
+ // 自定义刻度标签
+ Hashtable labelTable = new Hashtable<>();
+ for (int i = 10; i <= 40; i += 1) {
+ labelTable.put(i, new JLabel(String.format("%.1f", i / 10.0)));
+ }
+ zoomSlider.setLabelTable(labelTable);
+
+ // 创建缩放值标签
+ zoomValueLabel = new JLabel("1.0");
+ zoomValueLabel.setFont(new Font("宋体", Font.PLAIN, 14));
+
+ // 添加滑动条和标签到面板
+ add(new JLabel("缩放程度:"));
+ add(zoomSlider);
+ add(zoomValueLabel);
+
+ // 添加滑动条值变化监听器
+ zoomSlider.addChangeListener(new ChangeListener() {
+ @Override
+ public void stateChanged(ChangeEvent e) {
+ // 获取滑动条的值
+ int sliderValue = zoomSlider.getValue();
+ zoomLevel = sliderValue / 10.0; // 将整数值转换为小数值
+
+ // 更新缩放值标签
+ zoomValueLabel.setText(String.format("%.1f", zoomLevel));
+ canvasLabel.setText("画布大小: "+(int)(width/(zoomLevel/2+0.5))+" × "+(int)(height/(zoomLevel/2+0.5))+"像素");
+
+ // 更新绘图区域的缩放比例
+ updateZoom();
+ }
+ });
+ }
+
+
+ private static class CustomSliderUI extends BasicSliderUI {
+ private boolean isHover = false; // 标记鼠标是否悬停在滑轮上
+
+ public CustomSliderUI(JSlider slider) {
+ super(slider);
+ }
+
+ // 设置悬停状态
+ public void setHover(boolean hover) {
+ isHover = hover;
+ }
+
+ // 获取滑轮的区域
+ public Rectangle getThumbBounds() {
+ return thumbRect;
+ }
+
+ @Override
+ public void paint(Graphics g, JComponent c) {
+ // 调用父类的 paint 方法以清除背景
+ super.paint(g, c);
+
+ // 强制仅重绘滑轮和轨迹区域,避免残影
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ // 绘制滑动条轨迹
+ paintTrack(g2);
+
+ // 绘制滑轮
+ paintThumb(g2);
+
+ g2.dispose();
+ }
+
+ @Override
+ public void paintThumb(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ // 滑轮白色部分(固定大小)
+ int whiteSize = 18; // 白色圆大小
+ int whiteX = thumbRect.x + (thumbRect.width - whiteSize) / 2;
+ int whiteY = thumbRect.y + (thumbRect.height - whiteSize) / 2;
+
+ g2.setColor(new Color(255, 255, 255));
+ g2.fillOval(whiteX, whiteY, whiteSize, whiteSize);
+
+ // 滑轮蓝色部分(根据悬停状态调整大小)
+ int blueSize = isHover ? 14 : 10; // 悬停时增大蓝色圆
+ int blueX = thumbRect.x + (thumbRect.width - blueSize) / 2;
+ int blueY = thumbRect.y + (thumbRect.height - blueSize) / 2;
+
+ g2.setColor(new Color(0, 120, 250));
+ g2.fillOval(blueX, blueY, blueSize, blueSize);
+
+ g2.dispose();
+ }
+
+ @Override
+ public void paintTrack(Graphics g) {
+ Graphics2D g2 = (Graphics2D) g.create();
+ g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+
+ int trackHeight = 4; // 轨迹高度
+ int trackWidth = trackRect.width; // 轨迹宽度(水平滑动条时是宽度)
+
+ // 绘制完整轨迹(底层)
+ g2.setColor(new Color(200, 200, 200)); // 灰色轨迹线
+ g2.fillRoundRect(trackRect.x, trackRect.y + (trackRect.height - trackHeight) / 2, trackWidth, trackHeight, 3, 3);
+
+ // 绘制动态轨迹(覆盖)
+ int thumbCenterX = thumbRect.x + thumbRect.width / 2; // 计算滑轮中心X坐标
+ int dynamicTrackWidth = thumbCenterX - trackRect.x; // 蓝色轨迹宽度(从滑块位置到轨迹起点)
+
+ // 绘制动态轨迹(蓝色部分)
+ g2.setColor(new Color(0, 120, 250)); // 蓝色动态轨迹
+ g2.fillRoundRect(trackRect.x, trackRect.y + (trackRect.height - trackHeight) / 2, dynamicTrackWidth, trackHeight, 3, 3);
+
+ g2.dispose();
+ }
+
+ @Override
+ protected Dimension getThumbSize() {
+ // 设置滑轮的尺寸
+ return new Dimension(16, 16);
+ }
+
+ @Override
+ public void setThumbLocation(int x, int y) {
+ // 调用父类方法设置滑轮位置
+ super.setThumbLocation(x, y);
+
+ // 强制仅重绘滑轮和动态轨迹区域
+ slider.repaint(trackRect.x, trackRect.y, trackRect.width, trackRect.height);
+ }
+ }
+
+
+ private void updateZoom() {
+ // 获取绘图区域的大小
+ int width = drawingArea.getWidth();
+ int height = drawingArea.getHeight();
+
+ // 计算缩放后的偏移量
+ double offSetX = width / 2;
+ double offSetY = height / 2;
+
+ // 调整偏移量以保持缩放中心
+ if (offSetX < (width / zoomLevel) / 2) {
+ offSetX = (width / zoomLevel) / 2;
+ }
+ if (offSetX > width - ((width / zoomLevel) / 2)) {
+ offSetX = width - ((width / zoomLevel) / 2);
+ }
+ if (offSetY < (height / zoomLevel) / 2) {
+ offSetY = (height / zoomLevel) / 2;
+ }
+ if (offSetY > height - ((height / zoomLevel) / 2)) {
+ offSetY = height - ((height / zoomLevel) / 2);
+ }
+
+ // 更新绘图区域的缩放比例
+ drawingArea.setZoomLevel(zoomLevel);
+ drawingArea.repaint(); // 重新绘制绘图区域
+ }
+}
diff --git a/src/image/graph.png b/src/image/graph.png
new file mode 100644
index 0000000..ceb0032
Binary files /dev/null and b/src/image/graph.png differ
diff --git a/src/image/grid.png b/src/image/grid.png
new file mode 100644
index 0000000..e4d9106
Binary files /dev/null and b/src/image/grid.png differ
diff --git a/src/image/select.png b/src/image/select.png
new file mode 100644
index 0000000..d1af11d
Binary files /dev/null and b/src/image/select.png differ