1package com.example.graphics;
3import com.example.graphics.factory.ShapeFactory;
4import com.example.graphics.factory.SwingRendererFactory;
5import com.example.graphics.model.Line;
6import com.example.graphics.model.Shape;
7import com.example.graphics.observer.ConsoleLogger;
8import com.example.graphics.render.Renderer;
9import com.example.graphics.render.SwingRenderer;
10import com.example.graphics.singleton.RenderingConfig;
11import com.example.graphics.util.FileManager;
12import com.example.graphics.visitor.JsonExportVisitor;
13import com.example.graphics.visitor.XmlExportVisitor;
14import com.example.graphics.proxy.RemoteRendererProxy;
17import javax.swing.filechooser.FileNameExtensionFilter;
19import java.awt.event.*;
21import java.io.FileWriter;
22import java.io.IOException;
76 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
78 setLocationRelativeTo(
null);
83 JPanel mainPanel =
new JPanel(
new BorderLayout());
91 mainPanel.add(toolBar, BorderLayout.NORTH);
95 renderPanel.setBorder(BorderFactory.createLoweredBevelBorder());
99 JScrollPane scrollPane =
new JScrollPane(renderPanel);
100 mainPanel.add(scrollPane, BorderLayout.CENTER);
103 JPanel statusBar =
new JPanel(
new FlowLayout(FlowLayout.LEFT));
104 statusBar.setBorder(BorderFactory.createLoweredBevelBorder());
107 mainPanel.add(statusBar, BorderLayout.SOUTH);
109 setContentPane(mainPanel);
116 JMenuBar menuBar =
new JMenuBar();
119 JMenu fileMenu =
new JMenu(
"文件");
121 JMenuItem newItem =
new JMenuItem(
"新建");
123 fileMenu.add(newItem);
125 JMenuItem openItem =
new JMenuItem(
"打开...");
127 fileMenu.add(openItem);
129 fileMenu.addSeparator();
131 JMenuItem saveItem =
new JMenuItem(
"保存...");
133 fileMenu.add(saveItem);
135 JMenuItem saveJsonItem =
new JMenuItem(
"导出为JSON...");
137 fileMenu.add(saveJsonItem);
139 JMenuItem saveXmlItem =
new JMenuItem(
"导出为XML...");
141 fileMenu.add(saveXmlItem);
143 fileMenu.addSeparator();
145 JMenuItem exitItem =
new JMenuItem(
"退出");
146 exitItem.addActionListener(e -> System.exit(0));
147 fileMenu.add(exitItem);
149 menuBar.add(fileMenu);
152 JMenu editMenu =
new JMenu(
"编辑");
154 JMenuItem undoItem =
new JMenuItem(
"撤销");
155 undoItem.addActionListener(e -> {
163 editMenu.add(undoItem);
165 JMenuItem redoItem =
new JMenuItem(
"重做");
166 redoItem.addActionListener(e -> {
174 editMenu.add(redoItem);
176 editMenu.addSeparator();
178 JMenuItem clearItem =
new JMenuItem(
"清除所有");
179 clearItem.addActionListener(e -> {
182 editMenu.add(clearItem);
184 menuBar.add(editMenu);
187 JMenu renderMenu =
new JMenu(
"渲染");
189 JMenuItem localRenderItem =
new JMenuItem(
"本地渲染");
191 renderMenu.add(localRenderItem);
193 JMenuItem remoteRenderItem =
new JMenuItem(
"远程渲染");
195 renderMenu.add(remoteRenderItem);
197 menuBar.add(renderMenu);
200 JMenu helpMenu =
new JMenu(
"帮助");
202 JMenuItem aboutItem =
new JMenuItem(
"关于");
203 aboutItem.addActionListener(e -> {
204 JOptionPane.showMessageDialog(
this,
205 "图形渲染系统\n版本 1.0\n\n使用Java Swing开发的图形渲染应用\n支持多种设计模式",
206 "关于图形渲染系统\nsxizhuo.cn\nmengxizhuo@gmail.com",
207 JOptionPane.INFORMATION_MESSAGE);
209 helpMenu.add(aboutItem);
211 menuBar.add(helpMenu);
240 JToolBar toolBar =
new JToolBar();
241 toolBar.setFloatable(
false);
244 String[] shapeTypes = {
"Circle",
"Rectangle",
"Line",
"Triangle"};
245 ButtonGroup shapeGroup =
new ButtonGroup();
247 for (String type : shapeTypes) {
248 JToggleButton button =
new JToggleButton(type);
249 button.addActionListener(e -> {
258 shapeGroup.add(button);
262 if (
"Circle".equals(type)) {
263 button.setSelected(
true);
267 toolBar.addSeparator();
270 JButton clearButton =
new JButton(
"清除");
272 toolBar.add(clearButton);
274 toolBar.addSeparator();
330 JOptionPane.showMessageDialog(
this,
333 JOptionPane.ERROR_MESSAGE);
339 renderPanel.addMouseListener(
new MouseAdapter() {
341 public void mousePressed(MouseEvent e) {
402 public void mouseReleased(MouseEvent e) {
411 renderPanel.addMouseMotionListener(
new MouseMotionAdapter() {
413 public void mouseDragged(MouseEvent e) {
421 public void mouseMoved(MouseEvent e) {
423 statusLabel.setText(
"坐标: (" + e.getX() +
", " + e.getY() +
")");
429 if (shape instanceof com.example.graphics.model.Circle) {
431 }
else if (shape instanceof com.example.graphics.model.Rectangle) {
433 }
else if (shape instanceof com.example.graphics.model.Line) {
435 }
else if (shape instanceof com.example.graphics.model.Triangle) {
442 if (shape instanceof com.example.graphics.model.Circle) {
444 double distance = Math.sqrt(
445 Math.pow(point.x - circle.
getX(), 2) +
446 Math.pow(point.y - circle.
getY(), 2)
449 }
else if (shape instanceof com.example.graphics.model.Rectangle) {
451 return point.x >= rect.
getX() && point.x <= rect.
getX() + rect.
getWidth() &&
453 }
else if (shape instanceof com.example.graphics.model.Line) {
455 double lineLength = Math.sqrt(
460 double d1 = Math.sqrt(
461 Math.pow(point.x - line.
getX1(), 2) +
462 Math.pow(point.y - line.
getY1(), 2)
465 double d2 = Math.sqrt(
466 Math.pow(point.x - line.
getX2(), 2) +
467 Math.pow(point.y - line.
getY2(), 2)
471 return Math.abs(d1 + d2 - lineLength) <= 5;
472 }
else if (shape instanceof com.example.graphics.model.Triangle) {
480 int x3 = triangle.
getX3();
481 int y3 = triangle.
getY3();
483 double denominator = ((
y2 - y3) * (
x1 - x3) + (x3 -
x2) * (
y1 - y3));
484 double a = ((
y2 - y3) * (point.x - x3) + (x3 -
x2) * (point.y - y3)) / denominator;
485 double b = ((y3 -
y1) * (point.x - x3) + (
x1 - x3) * (point.y - y3)) / denominator;
486 double c = 1 - a - b;
489 return a >= 0 && a <= 1 && b >= 0 && b <= 1 && c >= 0 && c <= 1;
495 Shape newShape =
null;
499 newShape =
shapeFactory.createCircle(point.x, point.y, 50);
503 newShape =
shapeFactory.createRectangle(point.x, point.y, 100, 80);
509 if (newShape !=
null) {
525 if (!
drawing.getShapes().isEmpty()) {
526 int option = JOptionPane.showConfirmDialog(
this,
529 JOptionPane.YES_NO_CANCEL_OPTION);
531 if (option == JOptionPane.YES_OPTION) {
533 }
else if (option == JOptionPane.CANCEL_OPTION) {
542 JFileChooser fileChooser =
new JFileChooser();
543 fileChooser.setDialogTitle(
"打开图形文件");
546 FileNameExtensionFilter binFilter =
new FileNameExtensionFilter(
"二进制文件 (*.bin)",
"bin");
547 FileNameExtensionFilter jsonFilter =
new FileNameExtensionFilter(
"JSON文件 (*.json)",
"json");
548 fileChooser.addChoosableFileFilter(binFilter);
549 fileChooser.addChoosableFileFilter(jsonFilter);
550 fileChooser.setFileFilter(binFilter);
552 int result = fileChooser.showOpenDialog(
this);
554 if (result == JFileChooser.APPROVE_OPTION) {
555 File file = fileChooser.getSelectedFile();
556 String filePath = file.getAbsolutePath();
561 if (filePath.toLowerCase().endsWith(
".json")) {
572 for (
Shape shape : shapes) {
579 }
catch (Exception e) {
580 JOptionPane.showMessageDialog(
this,
581 "加载文件失败: " + e.getMessage(),
583 JOptionPane.ERROR_MESSAGE);
590 JFileChooser fileChooser =
new JFileChooser();
591 fileChooser.setDialogTitle(
"保存图形文件");
594 FileNameExtensionFilter binFilter =
new FileNameExtensionFilter(
"二进制文件 (*.bin)",
"bin");
595 fileChooser.addChoosableFileFilter(binFilter);
596 fileChooser.setFileFilter(binFilter);
598 int result = fileChooser.showSaveDialog(
this);
600 if (result == JFileChooser.APPROVE_OPTION) {
601 File file = fileChooser.getSelectedFile();
602 String filePath = file.getAbsolutePath();
605 if (!filePath.toLowerCase().endsWith(
".bin")) {
611 statusLabel.setText(
"已保存图形文件: " +
new File(filePath).getName());
612 }
catch (IOException e) {
613 JOptionPane.showMessageDialog(
this,
614 "保存文件失败: " + e.getMessage(),
616 JOptionPane.ERROR_MESSAGE);
635 JFileChooser fileChooser =
new JFileChooser();
636 fileChooser.setDialogTitle(
"保存为" + extension.toUpperCase() +
"文件");
638 int userSelection = fileChooser.showSaveDialog(
this);
640 if (userSelection == JFileChooser.APPROVE_OPTION) {
641 File fileToSave = fileChooser.getSelectedFile();
642 String filePath = fileToSave.getAbsolutePath();
645 if (!filePath.toLowerCase().endsWith(
"." + extension)) {
646 filePath +=
"." + extension;
650 if (extension.equals(
"json")) {
652 }
else if (extension.equals(
"xml")) {
655 try (FileWriter writer =
new FileWriter(filePath)) {
656 writer.write(content);
660 JOptionPane.showMessageDialog(
this,
661 "文件已保存至:" + filePath,
662 "保存成功", JOptionPane.INFORMATION_MESSAGE);
663 statusLabel.setText(
"已导出为" + extension.toUpperCase() +
"文件");
664 }
catch (IOException e) {
665 JOptionPane.showMessageDialog(
this,
666 "保存文件失败:" + e.getMessage(),
667 "错误", JOptionPane.ERROR_MESSAGE);
673 public static void main(String[] args) {
675 SwingUtilities.invokeLater(SwingGraphicsApp::new);
void switchToLocalRendering()
void setupRenderPanelListeners(JPanel renderPanel)
final ShapeFactory shapeFactory
boolean isPointOnShape(Shape shape, Point point)
void saveToFile(String content, String extension)
final SwingRenderer localRenderer
final RemoteRendererProxy remoteRenderer
final FileManager fileManager
JToggleButton remoteRenderingToggle
void createNewShape(Point point)
boolean isRemoteRenderingEnabled
static void main(String[] args)
boolean isDrawingTriangle
void switchToRemoteRendering()
String getShapeTypeName(Shape shape)
Renderer createRenderer(int width, int height)
static synchronized RenderingConfig getInstance()