Java 绘制应用程序:使用仿射变换拖动自由形式线(路径)
如何使用仿射变换拖动自由形式的线(路径) 我正在用Java制作一个类似于绘画的应用程序,其中一个要求是能够将绘制的自由形式形状拖动到用于绘制的JPanel上的一个新位置。我已经试着让AffineTransform这样做了一天了,现在它所做的是在选中并拖动所需的行(存储为Path2D)时移动。但是,一旦不再选择线,该线将返回其原始位置。另外,当我再次选择它时,它会立即显示在新位置(如果有意义的话);这可能是要转换的坐标系,但我不确定。。。 任何帮助都将不胜感激!也许有一种更简单的方法可以做到这一点。 PS我还注意到,当移动任何绘制的线时,除了最后绘制的线外,在移动的线之前绘制的所有线都会随之移动。 代码如下:Java 绘制应用程序:使用仿射变换拖动自由形式线(路径),java,swing,graphics2d,translate,affinetransform,Java,Swing,Graphics2d,Translate,Affinetransform,如何使用仿射变换拖动自由形式的线(路径) 我正在用Java制作一个类似于绘画的应用程序,其中一个要求是能够将绘制的自由形式形状拖动到用于绘制的JPanel上的一个新位置。我已经试着让AffineTransform这样做了一天了,现在它所做的是在选中并拖动所需的行(存储为Path2D)时移动。但是,一旦不再选择线,该线将返回其原始位置。另外,当我再次选择它时,它会立即显示在新位置(如果有意义的话);这可能是要转换的坐标系,但我不确定。。。 任何帮助都将不胜感激!也许有一种更简单的方法可以做到这一点
public class DrawPanel extends JPanel {
public double translateX=0;
public double translateY=0;
public int lastOffsetX;
public int lastOffsetY;
class Line {
public Point start;
public Point end;
public Color color;
public Path2D path;
}
ArrayList<Line> lines = new ArrayList<Line>();
ArrayList<Path2D> paths = new ArrayList<Path2D>();
boolean moveMode = false;
Path2D selectedLine;
int xDistance;
int yDistance;
public DrawPanel() {
setBackground(Color.WHITE);
setFocusable(true);
requestFocusInWindow();
this.addMouseMotionListener(new MouseMotionAdapter() {
@Override
public void mouseDragged(MouseEvent e) {
//System.out.println(resizeMode);
if (moveMode) {
if (selectedLine!=null) {
int newX = e.getX() - lastOffsetX;
int newY = e.getY() - lastOffsetY;
lastOffsetX += newX;
lastOffsetY += newY;
translateX += newX;
translateY += newY;
repaint();
}
} else {
Path2D p = paths.get(paths.size() - 1);
p.lineTo(e.getX(), e.getY());
repaint();
}
}
@Override
public void mouseMoved(MouseEvent e) {
super.mouseMoved(e);
if (resizeMode) {
selectedLine = null;
for (Path2D l : paths) {
if (l.contains(e.getPoint())) {
selectedLine = l;
}
}
repaint();
}
}
});
this.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent e) {
super.mousePressed(e);
if (!moveMode) {
Line l = new Line(e.getPoint());
l.path = new Path2D.Double();
l.path.moveTo(e.getX(), e.getY());
lines.add(l);
paths.add(l.path);
} else {
lastOffsetX = e.getX();
lastOffsetY = e.getY();
}
}
}
@Override
public void mouseReleased(MouseEvent e) {
super.mouseReleased(e);
if (!resizeMode) {
if (selectedLine == null) {
Line l = lines.get(lines.size() - 1);
l.end = e.getPoint();
l.path.lineTo(e.getX(), e.getY());
Path2D p = paths.get(paths.size() - 1);
p.lineTo(e.getX(), e.getY());
repaint();
}
} else {
for (int j=0; j<paths.size();j++) {
if (selectedLine!=null && selectedLine.equals(paths.get(j))) {
paths.set(j, selectedLine);
}
}
repaint();
}
}
});
}
private void setKeyBindings() {
ActionMap actionMap = getActionMap();
int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
InputMap inputMap = getInputMap(condition );
String ctrl = "VK_CONTROL";
String ctrl_rel = "control_released";
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_CONTROL, KeyEvent.CTRL_DOWN_MASK, false), ctrl);
inputMap.put(KeyStroke.getKeyStroke(("released CONTROL")), ctrl_rel);
actionMap.put(ctrl, new KeyAction(ctrl));
actionMap.put(ctrl_rel, new KeyAction(ctrl_rel));
}
private class KeyAction extends AbstractAction {
public KeyAction(String actionCommand) {
putValue(ACTION_COMMAND_KEY, actionCommand);
}
@Override
public void actionPerformed(ActionEvent actionEvt) {
if(actionEvt.getActionCommand() == "VK_CONTROL") {
moveMode = true;
}
else if(actionEvt.getActionCommand() == "control_released") {
moveMode = false;
repaint();
}
}
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D)g;
g2d.setColor(Color.BLACK);
g2d.setStroke(new BasicStroke(10.0f));
g2d.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
if (moveMode) {
for (int j=0; j<paths.size();j++) {
Path2D path = paths.get(j);
if (selectedLine!=null && selectedLine.equals(path)) {
AffineTransform at = new AffineTransform();
at.translate(translateX, translateY);
g2d.transform(at);
g2d.setColor(Color.RED);
g2d.draw(path);
g2d.setColor(Color.BLACK);
continue;
}
g2d.draw(path);
g2d.setColor(Color.BLACK);
}
} else {
for (int i =0; i < paths.size();i++) {
Path2D path = paths.get(i);
g2d.draw(path); // outline
}
}
}
公共类DrawPanel扩展了JPanel{
公共双translateX=0;
公共双translateY=0;
公共金融机构;
公共部门;
班级线{
公共点启动;
公共点终端;
公共色彩;
公共路径;
}
ArrayList行=新的ArrayList();
ArrayList路径=新的ArrayList();
布尔moveMode=false;
路径2D选择线;
距离;
内距离;
公共事务委员会(){
挫折地面(颜色:白色);
设置聚焦(真);
requestFocusInWindow();
this.addMouseMotionListener(新的MouseMotionAdapter(){
@凌驾
公共无效鼠标标记(鼠标事件e){
//System.out.println(resizeMode);
如果(移动模式){
如果(selectedLine!=null){
int newX=e.getX()-lastOffsetX;
int newY=e.getY()-lastOffsetY;
lastOffsetX+=newX;
lastOffsetY+=newY;
translateX+=newX;
translateY+=newY;
重新油漆();
}
}否则{
path2dp=path.get(path.size()-1);
p、 lineTo(e.getX(),e.getY());
重新油漆();
}
}
@凌驾
public void mouseMoved(MouseEvent e){
超级鼠标移动(e);
if(resizeMode){
selectedLine=null;
用于(路径2D l:路径){
if(l.contains(如getPoint())){
selectedLine=l;
}
}
重新油漆();
}
}
});
this.addMouseListener(新的MouseAdapter(){
@凌驾
公共无效鼠标按下(MouseEvent e){
超级鼠标按下(e);
如果(!移动模式){
第l行=新行(如getPoint());
l、 路径=新路径2d.Double();
l、 moveTo(e.getX(),e.getY());
行。添加(l);
路径。添加(l.path);
}否则{
lastfoffsetx=e.getX();
lastOffsetY=e.getY();
}
}
}
@凌驾
公共无效MouseEvent(MouseEvent e){
超级鼠标(e);
如果(!resizeMode){
如果(selectedLine==null){
第l行=lines.get(lines.size()-1);
l、 end=e.getPoint();
l、 lineTo(e.getX(),e.getY());
path2dp=path.get(path.size()-1);
p、 lineTo(e.getX(),e.getY());
重新油漆();
}
}否则{
对于(int j=0;j,您的AffineTransform
会为所有后续图形更改图形上下文的坐标系
在引用的示例中,每个形状都是类节点
的实例。每个节点
都包含一个selected
属性,该属性允许独立选择形状。该值确定从mouseDragged()调用时updatePosition()
的效果
。updatePosition()
的实现只需更新每个选定节点的坐标,但您也可以使用CreateTransform()
的CreateTransform()
的AffineTransform
更改所有后续图形的图形上下文坐标系
在引用的示例中,每个形状都是类节点
的实例。每个节点
都包含一个selected
属性,该属性允许独立选择形状。该值确定从mouseDragged()调用时updatePosition()
的效果
。updatePosition()
的实现只需更新每个选定节点的坐标,但您也可以使用AffineTransform
的createTransformedShape()
,谢谢您的回答!但是,由于我是一个新手,我不知道如何在我的代码中实现您的建议