我要画一个圆,用一条线将圆的上半部分和下半部分分开,然后使用GC填充上半部分和下半部分的颜色。
如果线条像这样越过圆心,我就能做到(要旋转线条,我只需更改fillArc()的startAngle)即可:
但是如果直线垂直向上或向下移动和/或旋转,则无法像这样填充上半部分和下半部分:
如果线向上或向下移动和/或旋转,是否有人知道如何填充上半部和下半部?
这是我的第一张图片代码:
// Fill top half with red color
gc.setBackground( event.display.getSystemColor( SWT.COLOR_RED ) );
gc.fillArc( xCoord - ( diameter / 2 ),
yCoord - ( diameter / 2 ),
diameter,
diameter,
0,
180 );
// Fill bottom half with blue color
gc.setBackground( event.display.getSystemColor( SWT.COLOR_BLUE ) );
gc.fillArc( xCoord - ( diameter/ 2 ),
yCoord - ( diameter/ 2 ),
diameter,
diameter,
180,
180 );
// Draw the line separating top half and bottom half
Transform transform = new Transform( event.display );
transform.translate( xCoord, yCoord );
transform .rotate( 0);
gc.setTransform( transform );
gc.drawLine( -diameter / 2, 0, diameter / 2, 0 );
transform.dispose();
答案 0 :(得分:1)
一种可能的方法是:
我创建了一个实现此解决方案的类和一个用于对其进行测试的小程序。
对于第2点,我发现使用Tranform
进行旋转非常麻烦,因为它将转换整个显示,并且我无法找到一种方法来将转换限制为有限的区域。
取而代之的是,我使用Eclipse GEF创建了一个Rectangle,将其旋转并将其转换为PathData
,可用于裁剪。
对于点4,我重用了点2的PathData
来绘制剪切矩形的底部,该矩形相当于两种颜色之间的分隔线。
为避免在圆外绘制线段的一部分,我用圆轮廓修剪了它。
这是结果:
这是测试程序,使用箭头键移动/旋转分隔线:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import static org.eclipse.swt.events.KeyListener.keyPressedAdapter;
public class SeparatedCircleTest {
public static void main(String[] args) {
Display display = new Display();
Shell shell = new Shell(display);
shell.setSize(600, 600);
shell.setLayout(new FillLayout());
// double buffering to avoid flickering while redrawing the circle
final SeparatedCircle separatedCircle = new SeparatedCircle(shell, SWT.DOUBLE_BUFFERED, 300, 300, 200, 0, 0.f);
// to move/rotate the separation
separatedCircle.addKeyListener(keyPressedAdapter(e -> {
if(e.keyCode == SWT.ARROW_UP) {
separatedCircle.setySeparationDelta(separatedCircle.getySeparationDelta() - 5);
} else if(e.keyCode == SWT.ARROW_DOWN) {
separatedCircle.setySeparationDelta(separatedCircle.getySeparationDelta() + 5);
} else if(e.keyCode == SWT.ARROW_LEFT) {
separatedCircle.setSeparationAngle(separatedCircle.getSeparationAngle() + 5.f);
} else if(e.keyCode == SWT.ARROW_RIGHT) {
separatedCircle.setSeparationAngle(separatedCircle.getSeparationAngle() - 5.f);
}
if(separatedCircle.needRedraw()) {
separatedCircle.redraw();
}
}));
shell.open();
while (!shell.isDisposed()) {
if (!display.readAndDispatch()) display.sleep();
}
display.dispose();
}
}
这是实现类:
import org.eclipse.gef.geometry.convert.swt.Geometry2SWT;
import org.eclipse.gef.geometry.euclidean.Angle;
import org.eclipse.gef.geometry.planar.Polygon;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.PaintEvent;
import org.eclipse.swt.events.PaintListener;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Path;
import org.eclipse.swt.graphics.PathData;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Canvas;
import org.eclipse.swt.widgets.Composite;
public class SeparatedCircle extends Canvas {
private int xCoord;
private int yCoord;
private int diameter;
private int ySeparationDelta;
private float separationAngle;
private boolean needRedraw;
private Rectangle circleBounds;
private PathData clippingData;
public SeparatedCircle(Composite parent, int style, int x, int y, int diameter, int ySeparationDelta, float separationAngle) {
super(parent, style);
xCoord = x;
yCoord = y;
this.diameter = diameter;
this.ySeparationDelta = ySeparationDelta;
this.separationAngle = separationAngle;
needRedraw = true;
addPaintListener(new PaintListener() {
public void paintControl(PaintEvent e) {
paint(e);
}
});
}
private void paint(PaintEvent event) {
// if some variable changed, we recalculate the bounds
if(needRedraw) {
calculateBounds();
needRedraw = false;
}
GC gc = event.gc;
// enable high quality drawing
gc.setAntialias(SWT.ON);
gc.setInterpolation(SWT.HIGH);
// draw the first circle, no clipping
gc.setBackground( event.display.getSystemColor( SWT.COLOR_BLUE ) );
gc.fillOval(circleBounds.x, circleBounds.y, circleBounds.width, circleBounds.height);
// clipping for the second circle
Path clipping = new Path(gc.getDevice(), clippingData);
gc.setClipping(clipping);
clipping.dispose();
// draw the second circle
gc.setBackground( event.display.getSystemColor( SWT.COLOR_RED ) );
gc.fillOval(circleBounds.x, circleBounds.y, circleBounds.width, circleBounds.height);
// remove the clipping
gc.setClipping((Rectangle) null);
// draw the circle outline
gc.setForeground(event.display.getSystemColor( SWT.COLOR_BLACK ));
gc.setLineWidth(4);
gc.drawOval(circleBounds.x, circleBounds.y, circleBounds.width, circleBounds.height);
// clipping for the separation line
Path circlePath = new Path(gc.getDevice());
circlePath.addArc(circleBounds.x, circleBounds.y, circleBounds.width, circleBounds.height, 0.f, 360.f);
gc.setClipping(circlePath);
circlePath.dispose();
// draw the separation line
// we want to draw the bottom segment of the clipping rectangle (the third segment), so we use its third and fourth point
gc.drawLine(
(int) clippingData.points[4], // third point x
(int) clippingData.points[5], // third point y
(int) clippingData.points[6], // fourth point x
(int) clippingData.points[7] // fourth point y
);
}
private void calculateBounds() {
circleBounds = calculateCircleBounds();
clippingData = calculateClipping();
}
private Rectangle calculateCircleBounds() {
return new Rectangle(calculateLeft(), calculateTop(), diameter, diameter);
}
private int calculateLeft() {
return xCoord - ( diameter / 2 );
}
private int calculateTop() {
return yCoord - ( diameter / 2 );
}
private PathData calculateClipping() {
// create the clipping rectangle
org.eclipse.gef.geometry.planar.Rectangle rectangle = new org.eclipse.gef.geometry.planar.Rectangle(
circleBounds.x, circleBounds.y, circleBounds.width, calculateClippingRectangleHeight());
// rotate it, using the center of our circle as its point of rotation
Polygon rotatedRectangle = rectangle.getRotatedCCW(Angle.fromDeg(separationAngle), xCoord, yCoord);
// convert the rotated rectangle to PathData
return Geometry2SWT.toSWTPathData(rotatedRectangle.toPath());
}
private int calculateClippingRectangleHeight() {
return circleBounds.height / 2 + ySeparationDelta;
}
public int getxCoord() {
return xCoord;
}
public void setxCoord(int xCoord) {
this.xCoord = xCoord;
needRedraw = true;
}
public int getyCoord() {
return yCoord;
}
public void setyCoord(int yCoord) {
this.yCoord = yCoord;
needRedraw = true;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int diameter) {
this.diameter = diameter;
needRedraw = true;
}
public int getySeparationDelta() {
return ySeparationDelta;
}
public void setySeparationDelta(int ySeparationDelta) {
this.ySeparationDelta = ySeparationDelta;
needRedraw = true;
}
public float getSeparationAngle() {
return separationAngle;
}
public void setSeparationAngle(float separationAngle) {
this.separationAngle = separationAngle;
needRedraw = true;
}
public boolean needRedraw() {
return needRedraw;
}
}
要使用GEF:
要使用GEF,您只需要包括以下jar:
org.eclipse.gef.geometry.convert.swt.Geometry2SWT<version>.jar
org.eclipse.gef.geometry<version>.jar
您可以从https://www.eclipse.org/gef/downloads/index.php此处的版本中的“插件”文件夹中检索它们。
选择最新版本,然后单击更新站点链接以下载完整的zip。