在这里,我尝试使用drawOval方法绘制一个圆,我想以特定的速度在屏幕上移动它。但是我有一个关于速度的双变量的问题。例如,当vx = 0.25和vy = 0时,圆刚好卡在其位置上。 抱歉,我的英语不好。
这是我正在使用的Java代码
int x=0 , y=0;
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
move();
g.drawOval(x, y, 10, 10);
repaint();
}
public void move() {
x+=0.25;
y+=0.25;
}
答案 0 :(得分:3)
move
方法调用paintComponent
!您永远都不知道何时调用此方法,因此无法正确控制移动速度。repaint
方法调用paintComponent
! 从不。这将使绘画系统进入无休止的重画操作周期!关于这个问题:
有一种方法可以根据double
坐标绘制任意形状。 2D Graphics Tutorial中也对此进行了详细介绍和解释。关键是使用Shape
界面。对于您的特定示例,代码的相关部分是这样的:
private double x = 0;
private double y = 0;
@Override
public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D)gr;
double radius = 5;
g.draw(new Ellipse2D.Double(
x - radius, y - radius, radius * 2, radius * 2));
}
也就是说,您创建一个Ellipse2D
实例,然后将其绘制。
这是MVCE,显示您可能要完成的工作:
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class PaintWithDouble
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
PaintWithDoublePanel p = new PaintWithDoublePanel();
f.getContentPane().add(p);
startMoveThread(p);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static void startMoveThread(PaintWithDoublePanel p)
{
Thread t = new Thread(() -> {
while (true)
{
p.move();
p.repaint();
try
{
Thread.sleep(20);
}
catch (InterruptedException e)
{
Thread.currentThread().interrupt();
return;
}
}
});
t.setDaemon(true);
t.start();
}
}
class PaintWithDoublePanel extends JPanel
{
private double x = 0;
private double y = 0;
@Override
public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
double radius = 5;
g.draw(new Ellipse2D.Double(
x - radius, y - radius, radius * 2, radius * 2));
g.drawString("At " + x + ", " + y, 10, 30);
}
public void move()
{
x += 0.05;
y += 0.05;
}
}
根据评论进行了编辑(并澄清了其他答案中已经提到的一些内容):
虽然说“只有整个像素”而没有“坐标(0.3,1.8)的像素”在技术上是正确的,但这并不意味着分数坐标不会影响渲染的最终外观输出。您学习足够长的时间后,每个主题都会变成一门科学。特别地,很多研究涉及到如何改善渲染输出的视觉外观的问题,这超出了用平凡的Bresenham所能达到的范围。进一步研究的切入点可以是关于subpixel rendering的文章。
在许多情况下,与往常一样,外观和绘图性能之间需要权衡取舍。对于Java及其2D绘图功能,这些权衡主要是通过RenderingHints
类控制的。例如,有RenderingHints#VALUE_STROKE_PURE
用于启用子像素渲染。该效果如下图所示:
滑块用于将水平线最右边点的y偏移更改为-3到+3像素。在左上方,您会看到一条按原样呈现的线。在中间,您会看到线条被放大了8倍,以更好地显示效果:像素充满了不同的不透明度,具体取决于理想化的1像素宽的线条覆盖了多少像素< / em>。
虽然这确实与大多数应用程序情况无关,但在这里可能值得注意。
以下是用于屏幕截图的MCVE:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.SwingUtilities;
public class PaintWithDoubleMagnified
{
public static void main(String[] args)
{
SwingUtilities.invokeLater(() -> createAndShowGui());
}
private static void createAndShowGui()
{
JFrame f = new JFrame();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.getContentPane().setLayout(new BorderLayout());
PaintWithDoubleMagnifiedPanel p = new PaintWithDoubleMagnifiedPanel();
f.getContentPane().add(p, BorderLayout.CENTER);
JSlider slider = new JSlider(0, 100, 50);
slider.addChangeListener(e -> {
int value = slider.getValue();
double relative = -0.5 + value / 100.0;
p.setY(relative * 6);
});
f.getContentPane().add(slider, BorderLayout.SOUTH);
f.setSize(500, 500);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class PaintWithDoubleMagnifiedPanel extends JPanel
{
private double y = 0;
@Override
public void paintComponent(Graphics gr)
{
super.paintComponent(gr);
Graphics2D g = (Graphics2D) gr;
g.drawString("At " + y, 10, 20);
paintLine(g);
BufferedImage image = paintIntoImage();
g.setRenderingHint(
RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
g.scale(8.0, 8.0);
g.drawImage(image, 0, 0, null);
}
public void setY(double y)
{
this.y = y;
repaint();
}
private void paintLine(Graphics2D g)
{
g.setColor(Color.BLACK);
g.setRenderingHint(
RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
g.setRenderingHint(
RenderingHints.KEY_STROKE_CONTROL,
RenderingHints.VALUE_STROKE_PURE);
Line2D line = new Line2D.Double(
10, 30, 50, 30 + y);
g.draw(line);
}
private BufferedImage paintIntoImage()
{
BufferedImage image = new BufferedImage(
100, 100, BufferedImage.TYPE_INT_ARGB);
Graphics2D g = image.createGraphics();
paintLine(g);
g.dispose();
return image;
}
}
答案 1 :(得分:0)
首先请注意,渲染系统正在将int用作每个像素的参数。
因此,如果p1
在x轴上靠近p2
,则
p1(x,y)
和p2(x+1,y)
例如:(0,0)和(1,0)
由于没有像素,因此中间没有(0.5,1)之类的东西。
这就是为什么Graphics api将int用于(x,y)坐标。
Graphics api
如果还要考虑使用double,则必须调整默认坐标系以适应您的需要。(不能在单个像素中渲染所有double,需要将它们分组在类别中)
例如说要放置x_points:0, 0.5, 1
所以0->0
,0.5(double)->1(int)
,1->2
其他像素可以映射为0.2->1
,0.7->2
,-0.9->0
一个规则图将所有范围都考虑在内(最好说in (-0.5,1]
)
可以为
-0.5<d<=0 -> 0
,0<d<=0.5 -> 1
,0.5<d<=1 -> 2
,其中d=input_x
(双精度)
这意味着您可以根据自己的需要调整坐标系
java中是否有一种方法可以绘制一个以双变量为中心的圆?
否(使用标准Graphics api)。拥有提供的api,但是您可以通过调整坐标系来呈现所需的任何输入(即使基于double)。
class MyPaint extends JPanel
{
private double x = 0, y=0;
private int width = 30, height = 30;
//adjust coordinates system
//for x in [0,1] have [0,0.1,0.2,0.3 ..]
//from no pixel between (0,1) to 9 pixels (0,0.1, ..,1)
//0->0,0.1->1,0.2->2,0.9->9,1->10
//in that way you have full control of rendering
private double scale_x = 0.1;
//same on y as x
private double scale_y = 0.1;
//pixel scaled on x,y
//drawing with
private int xs,ys;
@Override
public void paintComponent(Graphics g)
{
super.paintComponent(g);
xs = (int) (x/scale_x);
ys = (int) (y/scale_y);
g.drawString("Draw At: " + xs + ", " + ys + " From:" + x+","+y, 10, 30);
g.drawOval(xs, ys, (int) (width/scale_x), (int) (height/scale_y));
}
public void move()
{
//adjustments is better to be >= then scale(x or y) seen as absolute value
//if need 0.01 to be display on individual pixel on x
//then modify scale_x = 0.01 (or even 0.001)
x+=0.1;
y+=0.5;
}
}