如何在JavaSwing中绘制大小也不同的平滑连续线?
我正在使用swing和JPen用Java编写一个2D传统动画程序。该应用程序运行良好。然而,我不满意我画线时得到的结果 使用JPen API,swing面板侦听手写笔输入,其代码为:如何在JavaSwing中绘制大小也不同的平滑连续线?,java,swing,drawing,line,smooth,Java,Swing,Drawing,Line,Smooth,我正在使用swing和JPen用Java编写一个2D传统动画程序。该应用程序运行良好。然而,我不满意我画线时得到的结果 使用JPen API,swing面板侦听手写笔输入,其代码为: /** * This method is called whenever the stylus makes contact with the tablet while inside of the JPanel functioning * as the Drawing Canvas. * @param
/**
* This method is called whenever the stylus makes contact with the tablet while inside of the JPanel functioning
* as the Drawing Canvas.
* @param evt
*/
public void penLevelEvent(PLevelEvent evt) {
// Get kind of event: does it come from mouse (CURSOR), STYLUS or ERASER?
PKind kind = evt.pen.getKind();
// Discard events from mouse
if (kind == PKind.valueOf(PKind.Type.CURSOR)){
//System.out.println("returning since this is only a mouse cursor");
return;
}
// Get the current cursor location
// position value is in with respect to entire application window
// Get the tilt values (not with a Bamboo... so untested!)
float curX = evt.pen.getLevelValue(PLevel.Type.X);
float curY = evt.pen.getLevelValue(PLevel.Type.Y);
float pressure = evt.pen.getLevelValue(PLevel.Type.PRESSURE);// 0.0 - 1.0
float xTilt = evt.pen.getLevelValue(PLevel.Type.TILT_X);
float yTilt = evt.pen.getLevelValue(PLevel.Type.TILT_Y);
// Set the brush's size, and darkness relative to the pressure
float darkness = 255 * pressure;
// Transform them to azimuthX and altitude, two angles with the projection of the pen against the X-Y plane
// azimuthX is the angle (clockwise direction) between this projection and the X axis. Range: -pi/2 to 3*pi/2.
// altitude is the angle between this projection and the pen itself. Range: 0 to pi/2.
// Might be more pratical to use than raw x/y tilt values.
double[] aa = { 0.0, 0.0 };
PLevel.Type.evalAzimuthXAndAltitude(aa, xTilt, yTilt);
// or just PLevel.Type.evalAzimuthXAndAltitude(aa, evt.pen);
double azimuthX = aa[0];
double altitude = aa[1];
//-------------------------------------------------------------------------------------
// If the stylus is being pressed down, we want to draw a black
// line onto the screen. If it's the eraser, we want to create
// a white line, effectively "erasing" the black line
//-------------------------------------------------------------------------------------
if (kind == PKind.valueOf(PKind.Type.STYLUS)) {
//System.out.println("Darkness "+darkness);
int alpha = 255 - (int)darkness;
color = new Color(0,0,255, 255 - alpha);
}
else if (kind == PKind.valueOf(PKind.Type.ERASER)) {
System.out.println("Handle eraser");
}
else {
return; // IGNORE or CUSTOM...
}
//If movement of the stylus is occuring
if (evt.isMovement()) {
//and the buttonIsDown(boolean)
if(buttonIsDown) {
//drawingCanvas:JPanel -> instruct the jpanel to draw at the following coordinate using the specified pressure
drawingCanvas.stylusMovementInput( prevXPos,prevYPos, curX,curY, pressure);
}
prevXPos = curX;
prevYPos = curY;
}
prevXPos = curX;
prevYPos = curY;
}
因此,调用上述方法后,jpaneldrawingCanvas通过获取图像的图形2D开始在BuffereImage上绘制。以下是代码stylusMovementInput->calls->performDrawOnBufferImageGraphic2D:
/**
* Draw on the active frame that is selected. Then call channel refresh, to refresh the the composite image derived
* from call changes related to the current frame
* @param cX current
* @param cY current
* @param oX previous
* @param oY previous
* @param pressure pressure 0 - 1f
*/
private void performDrawOnBufferImageGraphic2D(float oX, float oY, float cX, float cY, float pressure){
//Obtain the current layer that user wants to draw one
//MyImageData is encapsulating a BufferedImage
MyImageData $activeData = getActiveLayer();
//Exit if one is not valid
if( $activeData == null) return;
//if valid layer, get the, get the bufferedImage.getGraphics
Graphics2D $activeDataGFX = $activeData.getImageGraphics();
// Customize the drawing brush (create a BasicStroke)
Stroke thickness = Sys.makeStroke(getPencilSize(pressure), null);
// Determine the tranparency with respect to the pressure
int alpha = (int)(255 * pressure * getPencilOpacityPercentage());
// Get the current color found in the color wheel
Color cwVal = Sys.getColorFromColorWheel();
Color drawingColor ;
if(cwVal != null){
// add alpha value to it
drawingColor = new Color(cwVal.getRed(), cwVal.getGreen(), cwVal.getBlue(), alpha);
}else throw new RuntimeException("ColorWheel is null drawing stylus draw");
//set the brush and drawingColor
$activeDataGFX.setStroke(thickness);
// Save reference to the current bufferedImage graphic component
Composite originalComposite =$activeDataGFX.getComposite();
if(getCurrentTool() == DrawingCanvasTool.ERASER){
//If eraser, set new composite information, to allow erasing to transparency
$activeDataGFX.setPaint( new Color(255,255,255, 0));
$activeDataGFX.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, 0.0f));
}else {
//set the drawing color
$activeDataGFX.setPaint(drawingColor);
}
//---------------------------------------------------------------
// Rotate, Translate, Zoom the image according to the panning, zoom, and rotate
// set by the user
//---------------------------------------------------------------
//Figure out the canvas center, as it is used for rotating
float theta = (float)Math.toRadians(canvasRotation);
Dimension drawingAreaComponentSize = getSize();
float centerX = drawingAreaComponentSize.width/2;
float centerY = drawingAreaComponentSize.height/2;
AffineTransform transform = new AffineTransform();
transform.rotate(-theta, centerX, centerY);
transform.scale(1.0f / canvasZoom, 1.0f / canvasZoom);//erase
transform.translate(-canvasPan.x, -canvasPan.y);//erase
$activeDataGFX.setTransform(transform);
//Now Draw inside of the active data graphics object
Shape line = new Line2D.Float(cX,cY, oX, oY);
Path2D.Float t = new Path2D.Float(line);
$activeDataGFX.draw(t);
//drawing is complete
if(getCurrentTool() ==DrawingCanvasTool.ERASER){
//Restore the old composite object
$activeDataGFX.setComposite(originalComposite);
}
//Refresh basically merges frames along a frame column into a single preview buffered image
//which will later be used to view the tool animation when user clicks "play" button
channelPannel.refreshFrameOut( channelPannel.getCurrentFrame() );
}
我对许多代码进行了注释,并提供了与问题相关的关键点。非常感谢您的帮助。同样,问题是如何绘制一条与下降绘图程序相当的平滑线。任何绘图程序只能在响应鼠标事件时绘制。问题是,鼠标移动时不会为每个像素生成MouseEvents,因此在图形中会出现间隙。您需要跟踪当前/以前的点,并在两者之间绘制直线,以获得完整的实线。我一直在跟踪当前和以前的点。例如,我将上一点输出到控制台的当前点,对于一个冲程,得到以下读数:行259.0 416.0 258.0 416.0行258.0 416.0 259.0 416.0行259.0 416.0 260.0 417.0行260.0 417.0 262.0 417.0行267.0 417.0行267.0 417.0 276.0行276.0 415.0行290.0 413.0行290.0 413.0308.0 410.0行308.0 410.0 330.0 407.0