📄 view.java
字号:
package draw;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.InetSocketAddress;
import java.util.Vector;
import javax.swing.AbstractAction;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.UIManager;
import javax.swing.WindowConstants;
import javax.swing.border.Border;
import javax.swing.filechooser.FileFilter;
import svg.SVGGen;
import app.Application;
import app.action.DelAction;
import app.action.MoveAction;
import app.action.RotateAction;
import app.pane.ChatFrame;
import app.pane.EdgedBorder;
import net.NetMessage;
import net.PaintClient;
import net.PaintServer;
import draw.figuare.AbstractFiguare;
/**
* 画布 <br/> 为绘图的主体
*
* @author Thihy
*
*/
public class View {
protected Draw draw;// 所在的主框架
protected JInternalFrame viewPort; // 附着体
private PaintCanvas canvas;// 画布实体
protected JPanel chatPane;// 聊天面板
protected ChatFrame chatFrame;// 聊天框架
// 一些常量,用于属性更改监听器
public static final String VIEW_KIND_PROPERTY = "view.kind";
public static final String CANVAS_CHANGED_PROPERTY = "view.canvas.changed";
public static final String HAS_SAVED = "view.saved";
// 唯一指定的ID
public int viewId;
// 用于聊天的服务端和客户端,一次只能使用一个
protected PaintServer server;
protected PaintClient client;
// 记录是否需要保存文档
private boolean needSave;
// 属性更改监听器
protected ViewPropertyListener propertyListener = new ViewPropertyListener();
// 当前文件保存的位置。
protected File viewFile;
/**
* 画布的名称。<br/> 显示在内部窗口JInternalFrame的标题栏上。 初始时如果未指定显示“untitled - ”+标号(从1开始)。
* 这是由此类自身维护的,不提供setName接口。 修改只能通过保存操作或者初始时设定(如打开文档,新建文档时)。
* 为了方便,初始时可能会要求获得文件的存储地址。 目前可能提供的文件存储格式为:svg。
*/
private String name;
/**
* 样式,分为服务器和客户端两种
*/
private String viewKind;
public View(String name, Draw controlDraw, int id) {
this.name = name;
this.viewId = id;
this.draw = controlDraw;
this.viewPort = createViewPort();
this.server = null;
this.client = null;
this.needSave = false;
this.viewFile = null;
viewKind = "";
}
/**
* 创建内部框架
*
* @return 内部框架
*/
protected JInternalFrame createViewPort() {
viewPort = new InnerFrame(draw);
regKeyAction(viewPort);
// 获取标题文本,也即View的名称
String title = this.name;
if (title == null) {
title = ""; // 如果为null时,什么也不显示。
}
viewPort.setTitle(title);
viewPort.addInternalFrameListener(this.draw);
viewPort.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
viewPort.putClientProperty("ID", viewId);// 用来唯一表示这个IFRAME
viewPort.putClientProperty(VIEW_KIND_PROPERTY, "");
viewPort.addPropertyChangeListener(propertyListener);
// 出示时不指定显示位置,而是由控制器Draw来控制显示位置。
/*
* 用户可以直接关闭这个面板。 但是会调用一些处理程序, 如判断当前文档是否已经经过更改, 若如此,会询问是否保存文档。
*/
viewPort.setClosable(true);
viewPort.setResizable(true); // 可以调整大小
viewPort.setMaximizable(true); // 可以最大化
viewPort.setIconifiable(true); // 可以最小化
viewPort.setVisible(true);
// 绘出画板
drawPaintPad(viewPort);
viewPort.setSize(400, 400);
return viewPort;
}
/**
* 绘制内部框架
*
* @param iframe
* 内部框架
*/
private void drawPaintPad(JInternalFrame iframe) {
iframe.setBackground(Color.lightGray);// TEMP View内部面板采用BorderLayout
JPanel p = (JPanel) iframe.getContentPane();
p.setLayout(new BorderLayout());
canvas = new PaintCanvas(this);
p.add(canvas);
canvas.setPreferredSize(new Dimension(450, 500));
canvas.addPropertyChangeListener(propertyListener);
Border bd = new EdgedBorder(UIManager.getColor("control"));
canvas.setBackground(Color.white);
canvas.setBorder(bd);
canvas.setVisible(true);
chatFrame = new ChatFrame(this, true);
chatPane = chatFrame.getChatPane();
chatPane.setVisible(false);
p.add(chatPane, BorderLayout.EAST);
}
/**
* 注册键盘
*
* @param comp
* 待注册组件
*/
private void regKeyAction(JComponent comp) {
comp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),
MoveAction.East.ID);
comp.getActionMap().put(MoveAction.East.ID, new MoveAction.East(this));
comp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),
MoveAction.North.ID);
comp.getActionMap()
.put(MoveAction.North.ID, new MoveAction.North(this));
comp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),
MoveAction.South.ID);
comp.getActionMap()
.put(MoveAction.South.ID, new MoveAction.South(this));
comp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),
MoveAction.West.ID);
comp.getActionMap().put(MoveAction.West.ID, new MoveAction.West(this));
comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0), DelAction.ID);
comp.getActionMap().put(DelAction.ID, new DelAction(this));
comp.getInputMap().put(KeyStroke.getKeyStroke(KeyEvent.VK_R, 0),
RotateAction.Right.ID);
comp.getActionMap().put(RotateAction.Right.ID,
new RotateAction.Right(this));
comp
.getInputMap()
.put(
KeyStroke.getKeyStroke(KeyEvent.VK_R,
InputEvent.SHIFT_DOWN_MASK), RotateAction.Left.ID);
comp.getActionMap().put(RotateAction.Left.ID,
new RotateAction.Left(this));
}
/**
* 获取聊天面板
*/
public JPanel getChatPane() {
return chatPane;
}
/**
* 获取聊天框架
*/
public ChatFrame getChatFrame() {
return chatFrame;
}
/**
* 获取当前窗口的视窗。<br/> 不应该向里面添加任何组件,因为它 是有程序Draw来布置View画布的一个 容器。 <br/>
* 只运行同一个包或其子类访问。
*
* @return 当前窗口的视窗
*/
public JInternalFrame getViewPort() {
return viewPort;
}
/**
* 设置当前画布所在的画板
*
* @param newDraw
* 画板
*/
public void setDraw(Draw newDraw) {
this.draw = newDraw;
}
/**
* 获取当前画布的名称
*
* @return 画布的名称
*/
public String getName() {
return this.name;
}
/**
* 获取网络名称,如果是客户端,由服务器指定
*
* @return 网络名称
*/
public String getNetName() {
if (client != null) {
return client.getNetName() + "-";
}
return "Server-";
}
/**
* 设置工具,由工具的唯一ID来指定
*
* @param figuareID
* 工具的唯一ID
*/
protected void setPaintTool(int figuareID) {
getCanvas().setShape(figuareID);
}
/**
* 设置线形颜色
*
* @param color
* 线形颜色
*/
public void setStrokeColor(Color color) {
getCanvas().setStrokeColor(color);
}
/**
* 设置填充颜色
*
* @param color
* 填充颜色
*/
public void setFillColor(Color color) {
getCanvas().setFillColor(color);
}
/**
* 获取所有的图形
*
* @return 所有的图形
*/
public Vector<AbstractFiguare> getFiguares() {
return getCanvas().getFiguares();
}
/**
* 获取Canvas
*
* @return Canvas
*/
public PaintCanvas getCanvas() {
return canvas;
}
/**
* 关闭窗口
*
* @return 成功关闭返回真
*/
public boolean close() {
if (IsConnected()) {
int ans = JOptionPane.showOptionDialog(null,
name + "文件连接到网络,确定关闭?", "警告", JOptionPane.YES_NO_OPTION,
JOptionPane.WARNING_MESSAGE, null, new String[] { "关闭",
"不关闭" }, "关闭");
switch (ans) {
case JOptionPane.YES_OPTION:// 关闭
unConnectServer();
break;
case JOptionPane.NO_OPTION:// 不关闭
return false;
default:
return false;
}
}
if (needSave) {
int ans = JOptionPane.showOptionDialog(null, name + "文件已经更改,是否保存?",
"警告", JOptionPane.YES_NO_CANCEL_OPTION,
JOptionPane.WARNING_MESSAGE, null, new String[] { "保存",
"不保存", "取消关闭" }, "保存");
switch (ans) {
case JOptionPane.YES_OPTION:// 保存
save();
break;
case JOptionPane.NO_OPTION:// 不保存
break;
case JOptionPane.CANCEL_OPTION:// 取消关闭
return false;
default:
return false;
}
}
viewPort.dispose();
canvas.setVisible(false);
canvas = null;
return true;
}
protected void save() {
if (viewFile == null || !(viewFile.isFile() && viewFile.canWrite())) {
saveAs();
return;
}
savingView();
}
protected void saveAs() {
JFileChooser filechooser = draw.getFileChooser();
int ans = filechooser.showSaveDialog(draw.app);
if (ans == JFileChooser.APPROVE_OPTION) {
viewFile = filechooser.getSelectedFile();
String name = viewFile.getName();
String path = viewFile.getAbsolutePath();
path = path.substring(0, path.lastIndexOf(File.separatorChar));
name = name.trim();
if (name.matches("\".+\"")) { // 文件名两边有“”, 则不指定后缀
name = name.replaceFirst("\"(.+)\"", "$1");
viewFile = new File(path + File.separatorChar + name);
} else if (!name.matches(".+\\.{1}[A-Za-z0-9]*")) {// 没有指定后缀时指定后缀
name = name + "." + Application.viewfileSuffix;
viewFile = new File(path + File.separatorChar + name);
}
try {
viewFile.createNewFile();
} catch (IOException e) {
if (Application.DEBUG > 0)
e.printStackTrace();
return;
}
savingView();
}
}
public void saveAsSvg() {
SVGGen svg = new SVGGen();
File file;
JFileChooser filechooser = new JFileChooser();
filechooser.setAcceptAllFileFilterUsed(true);
// 文件过滤器
FileFilter filter = new FileFilter() {
@Override
public String getDescription() {
return "Svg 文件 (*.svg)";
}
@Override
public boolean accept(File f) {
String fileName = f.getName();
if (f.isDirectory())
return true;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -