【问题标题】:What does the OFFSET do in repaint()-method with varargs?使用可变参数的 repaint() 方法中的 OFFSET 有什么作用?
【发布时间】:2015-07-16 22:44:57
【问题描述】:
 private void moveSquare(int x, int y) {
    int OFFSET = 1;
    if ((squareX!=x) || (squareY!=y)) {
        repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
        squareX=x;
        squareY=y;
        repaint(squareX,squareY,squareW+OFFSET,squareH+OFFSET);
    } 
}

这是来自 Java 教程的 sn-p。这是一个关于用Java绘画的教程。 https://docs.oracle.com/javase/tutorial/uiswing/painting/step3.html

我不明白 OFFSET 究竟在做什么。
或者 repaint() 方法中会发生什么。

我知道,有必要正确绘制正方形,因为我注意到,如果没有偏移量,正方形有时会丢失一个边,该边没有被第一个 repaint() 方法绘制或删除。

我让程序在控制台中写入变量(用于绘制矩形(squareX...等))。但宽度和高度始终为 20 而不是 21(宽度 + 偏移)。即使我读取了 paintComponent() 方法中的变量。
这就是为什么我不明白,为什么正方形第一次正确绘制,但每隔一次它在没有偏移量的情况下重新绘制,然后它就被错误地绘制了。

而且我无法查看 repaint() 方法的内部(至少我不知道该怎么做)

另一个小问题:如果颜色、位置等变量没有改变,repaint 方法是否总是“删除/覆盖”它要绘制的对象(在本例中为正方形)?

这就是paintComponent()方法的作用。

g.setColor(Color.RED);
g.fillRect(squareX,squareY,squareW,squareH);
g.setColor(Color.BLACK);
g.drawRect(squareX,squareY,squareW,squareH);

我不明白的是,为什么第一个 repaint() 方法会删除旧方块。 squareX/Y/W/H 和之​​前一样。然后他们通过鼠标点击获得新坐标,然后在新位置绘制正方形。
为什么相同的代码在第一个 repaint() 中删除,而在第二个中创建一个新正方形?

对不起,如果我的英语不好。我来自德国。

提前感谢您的所有回答!!!

【问题讨论】:

  • 通常,坐标是从零开始的,因此 20 像素宽的正方形将是 0-19 之类的东西。添加额外的像素克服了这种轻微的不稳定。您正在调用的 repaint 方法设置了一个剪切矩形,它只更新组件的那部分,它不会改变 squareW/H 值的大小
  • “另一个小问题:如果颜色、位置等变量没有,repaint 方法是否总是“删除/覆盖”它想要绘制的对象(在本例中为正方形)改变了吗?” - 没有或更多,这取决于paintComponent 方法实际上在做什么。如果要更新的区域没有改变,那么从你的角度来看,它不会改变,但它会被重新粉刷或更新。这就是为什么你需要在重新绘制新位置之前重新绘制旧位置,否则你曾经存在于旧位置的东西将保留下来
  • 感谢您的超级快速解答!我将有一个快速更新,因为关于第二个问题,我还有一点不明白。

标签: java swing paint offset repaint


【解决方案1】:

我不明白,为什么第一次正确绘制正方形,

调用paintComponent(...) 方法时不进行裁剪,因此重新绘制面板的整个 (250 x 200) 区域。

但是每隔一次它在没有偏移量的情况下被重新绘制,那么它就会被错误地绘制。

当您单击面板时,将调用paintComponent(...) 方法进行裁剪,因为两个repaint(...) 请求合并为一个裁剪的绘画请求,以提高绘画的效率。

例如,最初在 (50, 50) 处绘制正方形。如果您现在单击 (80, 80),重新绘制的区域将为:(50, 50, 101, 101),这是清除旧方块并绘制新方块所需的最小区域。

在paintComponent()方法中加入如下代码可以看到裁剪区域大小的变化:

System.out.println(g.getClipBounds());

注意:对于这样一幅简单的画,你并不需要花哨。您可以在重置 x/y 值后调用单个 repaint() 语句,整个面板将被重新绘制。

【讨论】:

    【解决方案2】:

    我不明白 OFFSET 到底在做什么。

    我认为这归结为 widthheight 的实际值。

    一般来说,大多数人将widthheight 视为已编入索引的1 (1 to width/height),而计算机将其视为已编入索引的0 (0 to width/height)。

    那么,当您将一个区域定义为 20 像素宽/高时,它是 0-20、0-19 还是 1-20?

    如果您尝试在整个组件周围绘制一个矩形,您会看到这一点。如果你要做类似的事情......

    g.drawRect(0, 0, getWidth(), getHeight());
    

    屏幕的右/下边缘会出现,相反,您需要使用类似的东西

    g.drawRect(0, 0, getWidth() - 1, getHeight() - 1);
    

    这里发生的是,API 允许这两种情况。组件的大小(由widthheight 属性定义)表示为1 索引,但我们需要对此进行调整以使其成为0 索引。

    为什么会发生这种情况超出了我的知识(通常是我的关心),我只关心知道它会发生;)

    或者在 repaint() 方法中发生了什么。

    通常,您不应该这样做。您应该关心的是 API 提供了一致的结果这一事实,因为 API 的底层工作委托给本机功能(大多数情况下是 DirectX 或 OpenGL)

    我让程序在控制台中写入变量(用于绘制矩形(squareX...等))。但宽度和高度始终为 20 而不是 21(宽度 + 偏移)。即使我读取了 paintComponent() 方法中的变量。 这就是为什么我不明白,为什么第一次正确绘制正方形,但每隔一次它在没有偏移量的情况下重新绘制,然后它就绘制不正确。

    你不会的。 repaint 不会改变变量的物理状态,而是要求更新组件的一小部分区域,而不影响组件的其余部分。 API 所做的是生成一个剪切矩形(看,它是另一个矩形),它只允许更新出现在该区域内(超出它的绘制没有效果)。

    这就是它被调用两次的原因,一次用于旧位置,一次用于新位置

    另一个小问题:如果颜色、位置等变量没有改变,repaint 方法是否总是“删除/覆盖”它要绘制的对象(在本例中为正方形)?

    这取决于。绘制被认为是破坏性的,即每次调用paintComponent 时,您都需要从头开始重新绘制组件的整个状态。因此,即使状态没有改变,也必须重新绘制整个区域,因为paintComponent 不知道之前的状态是什么。

    在 Swing 中,Graphics 上下文是一个共享资源,它用于为一个通用的本地对等体绘制所有组件。

    您可以查看Painting in AWT and SwingPerforming Custom Painting,这可能会为您提供有关绘画过程的更多信息

    【讨论】:

    • 哇,谢谢你的详细回答。是的,你是对的,知道如何解决这个问题就足够了! ;) 但你的回答让我明白发生了什么!非常感谢。我也会看看你推荐的网站! :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-06-23
    • 1970-01-01
    • 2011-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-09
    相关资源
    最近更新 更多