Java Swing 自定义形状(二维图形)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2483533/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Swing custom shapes (2D Graphics)
提问by juFo
I need to draw custom shapes. Now when a user clicks on several points on the panel I create a shape using a polygon.
我需要绘制自定义形状。现在,当用户单击面板上的几个点时,我会使用多边形创建一个形状。
public void mouseClicked(MouseEvent e) {
polygon.addPoint(e.getX(), e.getY());
repaint();
}
But I don't know if this is the best way to draw custom shapes.
但我不知道这是否是绘制自定义形状的最佳方式。
It should be possible to edit a drawn shape:
它应该可以编辑绘制形状:
- resize
- change its fill color
- change the stroke color
- copy/paste it
- move a single point of the polygon
- ...
- 调整大小
- 改变它的填充颜色
- 改变描边颜色
- 复制/粘贴
- 移动多边形的一个点
- ...
I have seen people creating an own class implementing the Shape class and using a GeneralPath. But again I have no idea if this is a good way.
我见过有人创建自己的类来实现 Shape 类并使用 GeneralPath。但我不知道这是否是一个好方法。
Now I can create my own shape with a polygon (or with a GeneralPath) but I have no clue how to attach all the edit functions to my own shape (the edit functions I mean the resize, move, etc from above).
现在我可以用多边形(或 GeneralPath)创建我自己的形状,但我不知道如何将所有编辑功能附加到我自己的形状(编辑功能我的意思是从上面调整大小、移动等)。
I hope somebody could show me a way to do this or maybe write a little bit of code to demonstrate this.
我希望有人可以向我展示一种方法来做到这一点,或者编写一些代码来演示这一点。
Thanks in advance!!
提前致谢!!
回答by Wintermut3
In answer to your question, I would definitely do what you describe as an AWT solution--that way you can track the objects created and be able to allow the user to reload them onto an edit Canvas and more than likely each of the shapes the user creates would be a "layer" not the Layer Swing Container, but an object that would store and track what shapes are drawn and be able to redraw them--the main thing to keep in mind is "Draw order". Basically you can do this by assigning each object or group of object that are your "shapes" to have a Z=[0-100] etc. (100, can be any number) which determine what order each of the object/shapes are drawn in and thus how they over lay each other.
在回答您的问题时,我肯定会做您所描述的 AWT 解决方案——这样您就可以跟踪创建的对象并能够允许用户将它们重新加载到编辑画布上,并且很可能每个形状用户创建的将是一个“图层”,而不是图层 Swing 容器,而是一个可以存储和跟踪绘制的形状并能够重绘它们的对象——要记住的主要事情是“绘制顺序”。基本上,您可以通过将作为您的“形状”的每个对象或一组对象分配给 Z=[0-100] 等(100,可以是任意数字)来确定每个对象/形状的顺序被吸引,因此他们是如何相互重叠的。
Basically you are going to need a shape class that stores the
基本上你需要一个形状类来存储
It should be possible to edit a drawn shape:
resize change its fill color change the stroke color copy/paste it move a single point of the polygon ...
应该可以编辑绘制的形状:
调整大小更改其填充颜色更改笔触颜色复制/粘贴它移动多边形的单个点...
you outlined and a storage object/manager that will enumerate the shape class objects/instances that are created. This classes will more or less be contained by a java.awt.Canvas container that will actually handle all the graphics.
您概述了一个存储对象/管理器,它将枚举创建的形状类对象/实例。这些类或多或少会包含在实际处理所有图形的 java.awt.Canvas 容器中。
Mostly you want to use awt over Swing due to the fact Swing is not Thread safe--that way you do not "paint yourself in the corner" early on in your design. Another reason is this is an implementation that needs to respond and interact in a way that a user is used to. Swing is built over the AWT and adds a great deal of complexity that an application like this doesn't need. Over all you are going to be creating a class Custom component that is exactly what the Canvas object was mean to provide and if Sun would have kept this tact earlier on they would not have gotten into the mess that Swing turned out to be... The Developer community--myself included--were well on the way to creating a lot of what Swing offered in "slickness" and component based design, but what we were building was totally AWT based. When Swing entered the scene, Java as a GUI platform was greatly complicated and started Sun and Java down a slippery path...
大多数情况下,您希望在 Swing 上使用 awt,因为 Swing 不是线程安全的——这样您就不会在设计的早期“把自己画在角落里”。另一个原因是这是一个需要以用户习惯的方式响应和交互的实现。Swing 是在 AWT 之上构建的,并增加了大量的复杂性,而这样的应用程序不需要。总之,您将创建一个类 Custom 组件,这正是 Canvas 对象所要提供的内容,如果 Sun 早点保持这种策略,他们就不会陷入 Swing 变成的烂摊子……开发人员社区——包括我自己——正在很好地创建 Swing 提供的许多“流畅”和基于组件的设计,但我们正在构建的内容完全基于 AWT。
Also you have to decide what you ultimately want as far as control over what you are creating here. If you need it fast and do not really care about modifying it in the future, then there are lots of open-source examples that can do this--most for free. If you want to do it yourself, then hopefully what I have talked about above and the rubber band code below will be enough to get you there and have a deeper understanding of Java as a GUI. I personally hope you take it on yourself--this language desperately needs more "core" people that truly understand the Language and its design and not just how to "work" frameworks like Hibernate and Spring among others...
此外,您必须决定您最终想要什么,只要能控制您在这里创建的内容。如果您快速需要它并且并不真正关心将来修改它,那么有很多开源示例可以做到这一点——大多数是免费的。如果你想自己做,那么希望我上面讨论的内容和下面的橡皮筋代码足以让你到达那里并更深入地了解 Java 作为 GUI。我个人希望你自己承担 - 这种语言迫切需要更多真正理解语言及其设计的“核心”人员,而不仅仅是如何“工作”像 Hibernate 和 Spring 等框架......
Good luck hope this helps,
祝你好运,希望这会有帮助,
WM
西马
As far as "Rubber-band" select code goes, this is mine I have used in the past, just consider it GLP and use it as you need to...
就“橡皮筋”选择代码而言,这是我过去使用过的,只需考虑它 GLP 并根据需要使用它......
First is the Listener interface:
首先是监听器接口:
/*
* RubberBandListener.java
*
* Created on August 18, 2005, 3:27 PM
*
* To change this template, choose Tools | Options and locate the template under
* the Source Creation and Management node. Right-click the template and choose
* Open. You can then make changes to the template in the Source Editor.
*/
package com.ges.util;
import java.util.EventListener;
import java.awt.Rectangle;
/**
*
* @author mstemen
*/
public interface RubberBandListener extends EventListener {
public abstract void notifyBounds(Rectangle boundingBox);
}
Here is the class which is a custom AWT component--it should be fine in either Swing/AWT probably even SWT
这是一个自定义 AWT 组件的类——它在 Swing/AWT 甚至 SWT 中都应该没问题
/*
* RubberBandSelect.java
*
* Created on August 18, 2005, 9:11 AM
* By Matthew Stemen/Wintermute Studios for util like use
*
*/
package com.ges.util;
import javax.swing.*;
import java.awt.*;
import java.util.*;
import java.awt.event.*;
/**
*
* @author mstemen
*/
public class RubberBandSelect extends Component {
/** Creates a new instance of RubberBandSelect */
private Point startPoint = null;
private Point endPoint = null;
private Graphics hostGraphics = null;
private Component hostComponent = null;
private Color bandColor = Color.ORANGE.darker().darker();
private boolean started = false;
private boolean eraseSomething = false;
private int startX, endX, startY, endY = 0;
private Rectangle boundingBox;
private StringBuilder QuadrantMessage = null;
private HashSet<RubberBandListener> listeners =
new HashSet<RubberBandListener>();
private int width = 0;
private int height = 0;
public RubberBandSelect(Component c) {
hostComponent = c;
hostGraphics = c.getGraphics();
}
public void addListener(RubberBandListener l) {
listeners.add(l);
}
public void paint(Graphics g) {
draw();
}
public void erase() {
if (eraseSomething) {
// hostComponent.repaint();
draw();
eraseSomething = false;
}
}
private void draw() {
hostGraphics = hostComponent.getGraphics();
if (hostGraphics != null) {
try {
/// hostGraphics.setXORMode( hostComponent.getBackground() );
erase();
drawRubberBand();
eraseSomething = false;
} finally {
// hostGraphics.dispose();
}
}
}
private void drawRubberBand() {
if (!started) {
return;
}
hostGraphics = hostComponent.getGraphics();
if (hostGraphics == null) {
return;
}
if (startPoint == null || endPoint == null) {
return;
}
hostGraphics.setColor(bandColor);
if (endX > startX && endY > startY) {
boundingBox = new Rectangle(startX, startY, endX - startX, endY - startY);
hostGraphics.drawRect(startX, startY, endX - startX, endY - startY);
QuadrantMessage = new StringBuilder("Drawing in Q - IV X1=");
width = endX - startX;
height = endY - startY;
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
} else if (endX < startX && endY < startY) {
boundingBox = new Rectangle(endX, endY, startX - endX, startY - endY);
hostGraphics.drawRect(endX, endY, startX - endX, startY - endY);
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
QuadrantMessage = new StringBuilder("Drawing in Q - II X1=");
width = startX - endX;
height = startY - endY;
} else if (endX > startX && endY < startY) {
boundingBox = new Rectangle(startX, endY, endX - startX, startY - endY);
hostGraphics.drawRect(startX, endY, endX - startX, startY - endY);
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
QuadrantMessage = new StringBuilder("Drawing in Q - I X1=");
width = endX - startX;
height = startY - endY;
} else if (endX < startX && endY > startY) {
boundingBox = new Rectangle(endX, startY, startX - endX, endY - startY);
hostGraphics.drawRect(endX, startY, startX - endX, endY - startY);
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
QuadrantMessage = new StringBuilder("Drawing in Q - III X1=");
width = startX - endX;
height = endY - startY;
}
}
public void assignToCompoent(Component c) {
this.hostComponent = c;
hostGraphics = c.getGraphics();
}
public void update(Graphics g) {
drawRubberBand();
}
public Point getStartPoint() {
return startPoint;
}
public void setStartPoint(Point startPoint) {
this.startPoint = startPoint;
startX = (int) startPoint.getX();
startY = (int) startPoint.getY();
QuadrantMessage = new StringBuilder();
// UDTMgr.getMgr().sendStatusMessage( "RubberBandSelect--Started: point is: X=" + startX + " Y=" + startY );
// drawRubberBand();
// started = true;
}
public Point getEndPoint() {
return endPoint;
}
public void setEndPoint(Point endPoint) {
this.endPoint = endPoint;
clear();
endX = (int) endPoint.getX();
endY = (int) endPoint.getY();
// UDTMgr.getMgr().sendStatusMessage( "RubberBandSelect--Streching: points are: X=" + startX + " Y=" + startY + " Ending Point is: X=" + endX + " Y="+ endY );
draw();
notifyListeners();
started = true;
}
public Color getBandColor() {
return bandColor;
}
public void setBandColor(Color bandColor) {
this.bandColor = bandColor;
}
public void setForeground(Color color) {
this.bandColor = color;
}
private void clear() {
hostGraphics = hostComponent.getGraphics();
if (hostGraphics == null) {
return;
}
// hostGraphics.setXORMode( hostComponent.getBackground() );
try {
// hostGraphics.setXORMode( hostComponent.getBackground() );
drawRubberBand();
} finally {
// hostGraphics.dispose();
}
}
public void breakBand() {
startPoint = null;
endPoint = null;
started = false;
boundingBox = new Rectangle(0, 0, 0, 0);
if (hostGraphics != null) {
hostGraphics.dispose();
}
clear();
hostComponent.repaint();
// UDTMgr.getMgr().sendStatusMessage( "RubberBandSelect-- Broke band, click to restart" );
}
public boolean isStarted() {
return started;
}
public void notifyListeners() {
Iterator<RubberBandListener> it = listeners.iterator();
while (it.hasNext()) {
it.next().notifyBounds(boundingBox);
}
}
public void redraw(Graphics g) {
if (startPoint == null || endPoint == null) {
return;
}
g.setColor(bandColor);
// hostGraphics.setPaintMode();
// hostComponent.repaint();
// four way case state to determine what quadrant to draw in
if (endX > startX && endY > startY) {
boundingBox = new Rectangle(startX, startY, endX - startX, endY - startY);
g.drawRect(startX, startY, endX - startX, endY - startY);
QuadrantMessage = new StringBuilder("Drawing in Q - IV X1=");
width = endX - startX;
height = endY - startY;
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
} else if (endX < startX && endY < startY) {
boundingBox = new Rectangle(endX, endY, startX - endX, startY - endY);
g.drawRect(endX, endY, startX - endX, startY - endY);
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
QuadrantMessage = new StringBuilder("Drawing in Q - II X1=");
width = startX - endX;
height = startY - endY;
} else if (endX > startX && endY < startY) {
boundingBox = new Rectangle(startX, endY, endX - startX, startY - endY);
g.drawRect(startX, endY, endX - startX, startY - endY);
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
QuadrantMessage = new StringBuilder("Drawing in Q - I X1=");
width = endX - startX;
height = startY - endY;
} else if (endX < startX && endY > startY) {
boundingBox = new Rectangle(endX, startY, startX - endX, endY - startY);
g.drawRect(endX, startY, startX - endX, endY - startY);
//UDTMgr.getMgr().sendStatusMessage( "Drawing Rect: " + "(X1=" + startX + ",Y1=" + startY + ") (X2=" + endX + ",Y2=" + endY + ")" );
QuadrantMessage = new StringBuilder("Drawing in Q - III X1=");
width = startX - endX;
height = endY - startY;
}
}
public Rectangle getBoundingBox() {
return boundingBox;
}
}
回答by trashgod
回答by John Kane
Have you looked at the Graphics class in java (there is also a Polygon class)? There are draw and fill polygon methods, and each can take in an array of x-coordinates and y-coordinates. By using these arrays, you should be able to change the positions of the points fairly easily. Like you could change all of them equally for a re-size, or copy and paste by just moving all points equally. Changing the color is as easy as filling it with a new color and repainting.
你有没有看过java中的Graphics类(还有一个Polygon类)?有绘制和填充多边形方法,每个方法都可以接收一组 x 坐标和 y 坐标。通过使用这些数组,您应该能够相当轻松地更改点的位置。就像您可以平等地更改所有这些以重新调整大小,或者通过平均移动所有点来复制和粘贴。更改颜色就像填充新颜色并重新粉刷一样简单。


