📄 shapepane.java
字号:
package com.zcsoft.graphics.line;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.event.MouseInputListener;
import com.zcsoft.graphics.*;
/*
* Title: 示例程序
* Description: 为使用公司开发工具软件的用户提供软件实现示例代码
* Copyright: Copyright (c) 2001
* Company: 苏州至诚软件
* @author 蒋智湘
* @version 2.0
*/
/**
* 图形绘制面板。
* 当前实现的功能有:
* <ol>
* <li>图形控制点信息捕捉</li>
* <li>图形选择</li>
* <li>图形控制点移动</li>
* <li>图形移动</li>
* </ol>
*/
public class ShapePane extends JComponent implements MouseInputListener
{
/** 要绘制的图形列表 */
private Vector shapeMakers = new Vector();
/**
* 当前选中的图形
*/
private transient int currentShape=-1;
// /**
// * 当前选中的图形的各个节点中选中的节点
// */
// private transient int currentPoint=-1;
/**
* 鼠标拖动时,上一次拖动事件发生时所到的点
*/
private transient Point last=null;
/**
* 判断鼠标是否在里面
*/
//private transient boolean in=false;
/** 是否支持鼠标移动事件的处理 */
private boolean mouseMotionEnabled;
/**
* 构造一个没有任何图形的面板
*/
public ShapePane()
{
enableEvents(AWTEvent.KEY_EVENT_MASK | AWTEvent.FOCUS_EVENT_MASK);
setBackground(java.awt.Color.black);
setForeground(java.awt.Color.yellow);
this.addMouseListener(this);
setMouseMotionEnabled(true);
ToolTipManager ttm = ToolTipManager.sharedInstance();
ttm.registerComponent(this);
ttm.setDismissDelay(3000);
ttm.setInitialDelay(100);
}
/**
* 设定绘制面板支持对鼠标移动事件的处理
* @param yes
*/
public void setMouseMotionEnabled(boolean yes)
{
if (mouseMotionEnabled == yes)
{
return;
}
mouseMotionEnabled = yes;
if (yes)
{
this.addMouseMotionListener(this);
}
else
{
this.removeMouseMotionListener(this);
}
}
/**
* 判断是否允许了该绘制面板对鼠标移动事件的处理
* @return
*/
public boolean isMouseMotionEnabled()
{
return this.mouseMotionEnabled;
}
/**
* 处理键盘事件
* 当敲击回车键且无修饰键时,相当于单击鼠标左键
* 当敲击回车键且修饰键为ALT时,相当于双击鼠标左键
*
* @since 2.0
*/
protected void processKeyEvent(KeyEvent e)
{
if(currentShape !=-1 && e.getKeyCode()==KeyEvent.VK_ENTER && e.getID() == KeyEvent.KEY_PRESSED )
{
ShapeMaker sm = (ShapeMaker)this.shapeMakers.get(currentShape);
if( e.getModifiers() == 0 )
sm.click(sm.getRange().getLocation());
else if( e.getModifiers() == KeyEvent.ALT_MASK )
sm.doubleClick(sm.getRange().getLocation());
}
else if(e.getID() == KeyEvent.KEY_PRESSED
&& e.isAltDown() == false
&& e.getKeyCode()==KeyEvent.VK_TAB)
{
if (e.isControlDown())
{
this.transferFocus();
}
else if(this.getShapeMakerCnt() > 0)
{
int newShape = currentShape;
if( e.isShiftDown() )
{
newShape = newShape > 0?(newShape - 1):(this.getShapeMakerCnt() - 1);
}
else
{
newShape = newShape < (this.getShapeMakerCnt() - 1)?(newShape + 1):0;
}
this.setSelectedShape(newShape, -1);
}
e.consume();
}
}
/**
* 使得可以处理键盘事件
*
* @since 2.0
*/
public boolean isFocusTraversable()
{
return isEnabled();
}
/**
* 添加图形构造器
* @exception NullPointerException 添加图形绘制器为null
*/
public synchronized void addShapeMaker(ShapeMaker sm)
{
if(sm==null)
throw new NullPointerException("sm is null");
shapeMakers.add(sm);
}
/**
* 获得指定的图形构造器
*/
public ShapeMaker getShapeMaker(int indx)
{
return (ShapeMaker)shapeMakers.get(indx);
}
/**
* 获得已有的图形构造器的数目
*/
public int getShapeMakerCnt()
{
return shapeMakers.size();
}
/**
* 删除指定图形构造器
*/
public synchronized void removeShapeMaker(ShapeMaker sm)
{
int index = this.shapeMakers.indexOf(sm);
if (index != -1)
{
this.removeShapeMaker(index);
}
}
/**
* 删除指定图形构造器
*/
public synchronized void removeShapeMaker(int indx)
{
shapeMakers.remove(indx);
if (indx == this.currentShape)
{
this.currentShape = -1;
// this.currentPoint = -1;
}
}
/**
* 删除所有图形构造器
*/
public synchronized void removeAllShapeMakers()
{
shapeMakers.removeAllElements();
this.currentShape = -1;
// this.currentPoint = -1;
}
public void paint(java.awt.Graphics g)
{
if (this.getWidth() == 0 || this.getHeight() == 0 || this.isShowing() == false)
{
return;
}
g.setColor(this.getBackground());
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(this.getForeground());
this.paintComponent(g);
}
/**
* 绘制图形
*/
protected void paintComponent(java.awt.Graphics g)
{
Rectangle bounds = g.getClipBounds();
for (int i = shapeMakers.size() - 1; i >= 0; i--)
{
ShapeMaker sm = this.getShapeMaker(i);
if (sm.isVisible() && sm.intersects(bounds))
{
if(sm.getShapeColor() == null)
sm.setShapeColor(this.getForeground());
if( sm.getOwner() == null)
sm.setOwner(this);
sm.paint((Graphics2D)g.create());
}
}
}
/**
* 处理鼠标点击事件。
*
* @since 2.0
*/
public void mouseClicked(MouseEvent e)
{
if (this.currentShape!=-1)
{
if (SwingUtilities.isLeftMouseButton(e))
{
ShapeMaker sm = (ShapeMaker)this.shapeMakers.get(currentShape);
if(e.getClickCount() > 1 )
{
sm.doubleClick(e.getPoint());
}
else
{
sm.click(e.getPoint());
}
}
}
}
/**
* 处理鼠标按钮按下时的事件
*/
public void mousePressed(MouseEvent e)
{
if ( !this.hasFocus() )
{
this.requestFocus();
}
if(SwingUtilities.isMiddleMouseButton(e))
return;
Point p = e.getPoint();
last = p;
int currentPoint = -1;
int currentShape = findMakerAt(p);
if (currentShape != -1)
{
currentPoint = this.getShapeMaker(currentShape).findControlPointUnder(p);
}
this.setSelectedShape(currentShape, currentPoint);
}
/**
* 找到指定点下的绘制器。
* 如果该点下存在多个重叠的绘制器,则找最小区域的那个。
* 查找时,不遍历不可见的绘制器。
* @param p
* @return
*/
protected int findMakerAt(Point p)
{
Rectangle bounds, minimumBounds = null;
ShapeMaker sm;
int index = -1;
for (int i = shapeMakers.size() - 1; i >= 0 ; i--)
{
sm = (ShapeMaker)this.shapeMakers.get(i);
if (sm.isVisible() && sm.contains(p))
{
bounds = sm.getRange();
if (minimumBounds == null
|| minimumBounds.contains(bounds))
{
index = i;
minimumBounds = bounds;
}
}
}
return index;
}
/** @todo 设置选中的图形
*
* @param cs 当前选中图形
* @param cp 当前选中的控制点
*
* @return 是否改变选择图形或控制点
*
* @since 2.0
*/
protected boolean setSelectedShape(int cs, int cp)
{
int oldShape = this.currentShape;
this.currentShape = cs;
ShapeMaker sm = null;
if(cs != oldShape)
{
if(cs != -1 )
{
sm = getShapeMaker(cs);
sm.setSelectedPoint(cp);
sm.setSelected(true);
}
if(oldShape != -1)
{
getShapeMaker(oldShape).setSelected(false);
}
}
else if( cs != -1 )
{
sm = (ShapeMaker)shapeMakers.get(cs);
sm.setSelectedPoint(cp);
sm.setSelected(true);
}
return sm != null;
}
/**
* 处理鼠标按钮弹起时的事件
*/
public void mouseReleased(MouseEvent e)
{
last = null;
if(e.isPopupTrigger())
{
if (this.currentShape == -1)
{
this.mousePressed(e);
}
if (this.currentShape == -1)
{
return ;
}
ShapeMaker sm = this.getShapeMaker(currentShape);
Point p = e.getPoint();
if (sm.contains(p))
{
JPopupMenu pop = sm.getContextMenu(p);
if (pop != null)
{
ShapePane.getLocationRelativeTo(pop, this, p);
pop.show(this, p.x, p.y);
}
}
}
}
/**
* 已知组件invoker上的某点p,求得组件me在屏幕上的正确位置,即如果组件
* 所求得点上显示,则尽可能保证组件me全部在屏幕的可是范围内。
* <BR>
* 同时更改点p的位置为所求得位置相对于组件invoker的新位置。
*
* @param me 想在屏幕正确位置上显示的组件
* @param invoker
* @param p 组件invoker上的某个点。其坐标原点在invoker所在矩形区域的
* 左上角
* @return 待求的组件位置
*/
public static Point getLocationRelativeTo(Component me
, Component invoker
, Point p)
{
Point loc = invoker.getLocationOnScreen();
int x = loc.x + p.x,
y = loc.y + p.y;
Dimension size = me.getPreferredSize(),
ss = JOptionPane.getRootFrame().getSize();
int offset = (x + size.width) - ss.width;
if (offset > 0)
{
x -= offset;//size.width;
}
offset = (y + size.height) - ss.height;
if (offset>0)
{
if (y>size.height)
y -= size.height;
else
y -= offset;
}
p.setLocation(x-loc.x, y-loc.y);
return new Point(x, y);
}
/**
* 处理鼠标进入面板事件
*/
public void mouseEntered(MouseEvent e)
{
//in=true;
}
/**
* 处理鼠标移出面板事件
*/
public void mouseExited(MouseEvent e)
{
//in=false;
}
/**
* 鼠标拖动事件侦听实现
* 如果选择了图形上的某个控制点,该方法就完成移动该控制点的功能,
* 否则,如果当前选中了图形,则方法就完成移动该控制点的功能。
*/
public void mouseDragged(MouseEvent e)
{
Point p = e.getPoint();
if(currentShape == -1
|| last == null
|| !this.getVisibleRect().contains(p))
{
return;
}
ShapeMaker sm = (ShapeMaker)shapeMakers.get(currentShape);
Rectangle oldBounds = sm.getRange();
boolean b;
if( sm.isMovable() && sm.getSelectedPoint() < 0) //移动整个图形
{
b = sm.translate(p.getX()-last.getX(),p.getY()-last.getY());
if(b)
{
last = p;
repaint(oldBounds.union(sm.getRange()));
}
}
else //移动一个点
{
b = ((ShapeMaker)shapeMakers.get(currentShape)).refreshPoint(sm.getSelectedPoint()
, new DoublePoint(p.getX(), p.getY()) );
if(b)
{
this.setCursor(sm.getCuror(sm.getSelectedPoint()));
repaint(oldBounds.union(sm.getRange()));
}
}
}
/**
* 鼠标移动事件侦听实现
*
* 实现设置工具提示和设置光标功能
*
*/
public void mouseMoved(MouseEvent e)
{
ShapeMaker sm;
Point p = e.getPoint();
this.setCursor(Cursor.getDefaultCursor());
int shapeIndx = this.findMakerAt(p);
if(shapeIndx != -1)
{
sm = this.getShapeMaker(shapeIndx);
int indexControlPoint = sm.findControlPointUnder(p);
if (indexControlPoint != -1)
{
//更新工具提示内容为控制点信息
this.setCursor(sm.getCuror(indexControlPoint));
Object pointInfo = sm.getPointInfo(indexControlPoint);
this.setToolTipText(pointInfo==null?null:pointInfo.toString());
return ;
}
}
//没有找到点但找到图形,如果选中的图形可以被移动,则设置选中的图形的光标为移动光标
if ( shapeIndx == currentShape && shapeIndx != -1)
{
sm = (ShapeMaker)this.shapeMakers.get(shapeIndx);
if(sm.isMovable())
this.setCursor( sm.getMovingCursor());
}
if( shapeIndx != -1 )
this.setToolTipText(((ShapeMaker)this.shapeMakers.get(shapeIndx)).getToolTipText(p));
else
this.setToolTipText(null);//取消工具提示
}
/**
* 设置工具提示内容
*
* @param txt 工具提示内容,支持HTML格式,
* 但不包含<code><html></code>和<code></html></code>标记。
*/
public void setToolTipText(String txt)
{
super.putClientProperty(super.TOOL_TIP_TEXT_KEY,txt!=null?("<html>".concat(txt).concat("</html>")):null);
}
/**
* 获取选中的图形绘制器
* @return 选中的图形绘制器。如果没有选中的图形,则为null
*/
public ShapeMaker getSelectedShape()
{
return this.currentShape != -1?this.getShapeMaker(this.currentShape):null;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -