java swing 2d point_这是使用Java 2D Graphics API的正确方法吗?

如果您想以设定的时间间隔安排更新,javax.swing.Timer会为其提供Swing集成服务. Timer定期在EDT上运行其任务,没有显式循环. (显式循环会阻止EDT处理事件,这会冻结UI.我更深入地解释了这一点.)

最终在Swing中做任何一种绘画你仍然会做两件事:

>重写paintComponent来完成绘图.

>根据需要调用重绘以请求使您的绘图可见. (Swing通常只在需要时重新绘制,例如当某个其他程序的窗口经过Swing组件的顶部时.)

如果你正在做这两件事你可能做得对. Swing实际上没有动画的高级API.它主要是为绘制GUI组件而设计的.它当然可以做一些好东西,但你必须从头开始编写一个组件,就像你正在做的那样.

您可以查看JavaFX.我个人对此并不了解,但它应该更适合动画.

作为一种优化,可以做的一件事是在单独的图像上绘画,然后将图像绘制到paintComponent中的面板上.如果绘画很长,这个特别有用:系统可以安排重绘,以便在发生更多控制时保持重绘.

如果您没有绘制图像,那么您需要构建一个包含对象的模型,并且每次在paintComponent中绘制所有这些对象.

这是绘制图像的示例:

import javax.swing.*;

import java.awt.*;

import java.awt.image.*;

import java.awt.event.*;

/**

* Holding left-click draws, and

* right-clicking cycles the color.

*/

class PaintAnyTime {

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {

@Override

public void run() {

new PaintAnyTime();

}

});

}

Color[] colors = {Color.red, Color.blue, Color.black};

int currentColor = 0;

BufferedImage img = new BufferedImage(256, 256, BufferedImage.TYPE_INT_ARGB);

Graphics2D imgG2 = img.createGraphics();

JFrame frame = new JFrame("Paint Any Time");

JPanel panel = new JPanel() {

@Override

protected void paintComponent(Graphics g) {

super.paintComponent(g);

// Creating a copy of the Graphics

// so any reconfiguration we do on

// it doesn't interfere with what

// Swing is doing.

Graphics2D g2 = (Graphics2D) g.create();

// Drawing the image.

int w = img.getWidth();

int h = img.getHeight();

g2.drawImage(img, 0, 0, w, h, null);

// Drawing a swatch.

Color color = colors[currentColor];

g2.setColor(color);

g2.fillRect(0, 0, 16, 16);

g2.setColor(Color.black);

g2.drawRect(-1, -1, 17, 17);

// At the end, we dispose the

// Graphics copy we've created

g2.dispose();

}

@Override

public Dimension getPreferredSize() {

return new Dimension(img.getWidth(), img.getHeight());

}

};

MouseAdapter drawer = new MouseAdapter() {

boolean rButtonDown;

Point prev;

@Override

public void mousePressed(MouseEvent e) {

if (SwingUtilities.isLeftMouseButton(e)) {

prev = e.getPoint();

}

if (SwingUtilities.isRightMouseButton(e) && !rButtonDown) {

// (This just behaves a little better

// than using the mouseClicked event.)

rButtonDown = true;

currentColor = (currentColor + 1) % colors.length;

panel.repaint();

}

}

@Override

public void mouseDragged(MouseEvent e) {

if (prev != null) {

Point next = e.getPoint();

Color color = colors[currentColor];

// We can safely paint to the

// image any time we want to.

imgG2.setColor(color);

imgG2.drawLine(prev.x, prev.y, next.x, next.y);

// We just need to repaint the

// panel to make sure the

// changes are visible

// immediately.

panel.repaint();

prev = next;

}

}

@Override

public void mouseReleased(MouseEvent e) {

if (SwingUtilities.isLeftMouseButton(e)) {

prev = null;

}

if (SwingUtilities.isRightMouseButton(e)) {

rButtonDown = false;

}

}

};

PaintAnyTime() {

// RenderingHints let you specify

// options such as antialiasing.

imgG2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

imgG2.setStroke(new BasicStroke(3));

//

panel.setBackground(Color.white);

panel.addMouseListener(drawer);

panel.addMouseMotionListener(drawer);

Cursor cursor =

Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR);

panel.setCursor(cursor);

frame.setContentPane(panel);

frame.pack();

frame.setResizable(false);

frame.setLocationRelativeTo(null);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setVisible(true);

}

}

b7yYF.png

如果例程是长时间运行并且重新绘制可以同时发生,则也可以使用双缓冲.对与所示图像分开的图像进行绘制.然后,在完成绘图例程时,交换图像引用,以使更新无缝.

例如,您通常应该为游戏使用双缓冲.双缓冲可防止图像以部分状态显示.例如,如果您使用游戏循环的背景线程(而不是计时器)并且重复出现游戏正在进行绘画,则可能会发生这种情况.如果没有双缓冲,这种情况会导致闪烁或撕裂.

默认情况下,Swing组件是双缓冲的,因此如果您的所有绘图都在EDT上发生,则您不需要自己编写双缓冲逻辑. Swing已经做到了.

这是一个更复杂的示例,它显示了长时间运行的任务和缓冲区交换:

import java.awt.*;

import javax.swing.*;

import java.awt.image.*;

import java.awt.event.*;

import java.util.*;

/**

* Left-click to spawn a new background

* painting task.

*/

class DoubleBuffer {

public static void main(String[] args) {

SwingUtilities.invokeLater(new Runnable() {

@Override

public void run() {

new DoubleBuffer();

}

});

}

final int width = 640;

final int height = 480;

BufferedImage createCompatibleImage() {

GraphicsConfiguration gc =

GraphicsEnvironment

.getLocalGraphicsEnvironment()

.getDefaultScreenDevice()

.getDefaultConfiguration();

// createCompatibleImage creates an image that is

// optimized for the display device.

// See http://docs.oracle.com/javase/8/docs/api/java/awt/GraphicsConfiguration.html#createCompatibleImage-int-int-int-

return gc.createCompatibleImage(width, height, Transparency.TRANSLUCENT);

}

// The front image is the one which is

// displayed in the panel.

BufferedImage front = createCompatibleImage();

// The back image is the one that gets

// painted to.

BufferedImage back = createCompatibleImage();

boolean isPainting = false;

final JFrame frame = new JFrame("Double Buffer");

final JPanel panel = new JPanel() {

@Override

protected void paintComponent(Graphics g) {

super.paintComponent(g);

// Scaling the image to fit the panel.

Dimension actualSize = getSize();

int w = actualSize.width;

int h = actualSize.height;

g.drawImage(front, 0, 0, w, h, null);

}

};

final MouseAdapter onClick = new MouseAdapter() {

@Override

public void mousePressed(MouseEvent e) {

if (!isPainting) {

isPainting = true;

new PaintTask(e.getPoint()).execute();

}

}

};

DoubleBuffer() {

panel.setPreferredSize(new Dimension(width, height));

panel.setBackground(Color.WHITE);

panel.addMouseListener(onClick);

frame.setContentPane(panel);

frame.pack();

frame.setLocationRelativeTo(null);

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

frame.setVisible(true);

}

void swap() {

BufferedImage temp = front;

front = back;

back = temp;

}

class PaintTask extends SwingWorker {

final Point pt;

PaintTask(Point pt) {

this.pt = pt;

}

@Override

public Void doInBackground() {

Random rand = new Random();

synchronized(DoubleBuffer.this) {

Graphics2D g2 = back.createGraphics();

g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,

RenderingHints.VALUE_ANTIALIAS_ON);

g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,

RenderingHints.VALUE_STROKE_PURE);

g2.setBackground(new Color(0, true));

g2.clearRect(0, 0, width, height);

// (This computes pow(2, rand.nextInt(3) + 7).)

int depth = 1 << ( rand.nextInt(3) + 7 );

float hue = rand.nextInt(depth);

int radius = 1;

int c;

// This loop just draws concentric circles,

// starting from the inside and extending

// outwards until it hits the outside of

// the image.

do {

int rgb = Color.HSBtoRGB(hue / depth, 1, 1);

g2.setColor(new Color(rgb));

int x = pt.x - radius;

int y = pt.y - radius;

int d = radius * 2;

g2.drawOval(x, y, d, d);

++radius;

++hue;

c = (int) (radius * Math.cos(Math.PI / 4));

} while (

(0 <= pt.x - c) || (pt.x + c < width)

|| (0 <= pt.y - c) || (pt.y + c < height)

);

g2.dispose();

back.flush();

return (Void) null;

}

}

@Override

public void done() {

// done() is completed on the EDT,

// so for this small program, this

// is the only place where synchronization

// is necessary.

// paintComponent will see the swap

// happen the next time it is called.

synchronized(DoubleBuffer.this) {

swap();

}

isPainting = false;

panel.repaint();

}

}

}

绘画例程只是用于绘制垃圾,需要很长时间:

rUOf0.png

Java 画轨迹可以用 JavaGraphics2D 类来实现。以下是一种基本的实现方法: 1. 创建一个 JPanel 类,并重写其 paintComponent 方法。 2. 在 paintComponent 方法中,创建一个 Graphics2D 对象,并设置线条的颜色和粗细。 3. 使用 Graphics2D 对象的 drawLine 方法画出轨迹。 以下是示例代码: ```java import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.RenderingHints; import java.util.ArrayList; import javax.swing.JFrame; import javax.swing.JPanel; public class DrawPanel extends JPanel { private static final long serialVersionUID = 1L; private ArrayList<Point> points = new ArrayList<Point>(); public DrawPanel() { setPreferredSize(new Dimension(500, 500)); setBackground(Color.WHITE); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setStroke(new BasicStroke(3f)); g2d.setColor(Color.BLACK); for (int i = 0; i < points.size() - 1; i++) { Point p1 = points.get(i); Point p2 = points.get(i + 1); g2d.drawLine(p1.x, p1.y, p2.x, p2.y); } } public void addPoint(Point p) { points.add(p); repaint(); } public static void main(String[] args) { JFrame frame = new JFrame("Drawing Panel"); DrawPanel panel = new DrawPanel(); frame.add(panel); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setVisible(true); panel.addPoint(new Point(100, 100)); panel.addPoint(new Point(200, 200)); panel.addPoint(new Point(300, 150)); } } ``` 在这个例子中,我们创建了一个 DrawPanel 类,它继承了 JPanel 类,并重写了其 paintComponent 方法。我们在 paintComponent 方法使用 Graphics2D 对象画出了轨迹。我们还创建了一个 ArrayList 对象,用于存储轨迹上的点,然后通过 addPoint 方法将点添加到列表中。最后,在 main 方法中,我们创建了一个 JFrame 对象,并将 DrawPanel 对象添加到其中。然后,我们使用 addPoint 方法添加了三个点,这些点将被画成一条轨迹。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值