java.awt drawRect()错误地解释了;宽度“;及;高度“;(左右各产生一个像素) 我开始使用Swing编程,发现了一个非常奇怪的东西,我认为它是基本的错误。

java.awt drawRect()错误地解释了;宽度“;及;高度“;(左右各产生一个像素) 我开始使用Swing编程,发现了一个非常奇怪的东西,我认为它是基本的错误。,swing,awt,drawrect,Swing,Awt,Drawrect,下面的示例显示,创建矩形和显示矩形时,“宽度”和“高度”值的处理方式不同 import java.awt.*; // I create a rectangle 2 x 2 with height=2, width=2 Rectangle rec = new Rectangle(1, 1, 2, 2); // I make sure that it contains only 4 points: (1,1), (1,2), (2,1), (2,2) println("- " + rec.con

下面的示例显示,创建矩形和显示矩形时,“宽度”和“高度”值的处理方式不同

import java.awt.*;
//  I create a rectangle 2 x 2 with height=2, width=2
Rectangle rec = new Rectangle(1, 1, 2, 2);

// I make sure that it contains only 4 points: (1,1), (1,2), (2,1), (2,2)
println("- " + rec.contains(1, 1) + ", " + rec.contains(1, 2) + ", " + rec.contains(1, 3));
println("- " + rec.contains(2, 1) + ", " + rec.contains(2, 2) + ", " + rec.contains(2, 3));
println("- " + rec.contains(3, 1) + ", " + rec.contains(3, 2) + ", " + rec.contains(3, 3));
输出:

  • ,假
  • ,假
  • 假,假,假
然后:

输出:

  • 相交(2,2):真
  • 相交(3,3):false
从数学的角度来看,这是一个2 x 2的矩形,它有4个整数点(即4个像素):(1,1),(1,2),(2,1),(2,2)。但是如果我们尝试渲染它呢

// Let's check what is get drawn
g.drawRect(1, 1, 2, 2); // displays 3 x 3 (as if width=3, height=3) !!
// Try it different way
((Graphics2D)g).draw(rec); // displays 3 x 3 again (as if width=3, height=3) !!
黄色小矩形显示为3 x 3:

结论:矩形()类构造函数将宽度/高度视为像素的实际宽度/高度,而绘制方法绘制矩形()将宽度/高度考虑为相对于左上像素的偏移。 因此java.awt在计算时表示与nxm相同的矩形,但在使用drawRect()渲染时表示为(N+1)x(M+1)

我发现这是完全错误的,因为人类的默认逻辑是假设我们画的正是我们所拥有的

我想知道是否有其他人知道这个问题,并且可以给bug追踪器提供一些参考或/和对这种行为的一些逻辑解释。只是谷歌搜索没有告诉我什么

我还想知道其他程序员是如何解决这个问题的。使用包装器拖动直线推送(x、y、宽度-1、高度-1)?我真不敢相信它如此怪异的工作对每个人来说都是好的

更新1:发布复制问题的“最小”代码段:

import javax.swing.*;
import java.awt.*;

public class Main {
    public static void main(String args[]) {
        JFrame jFrame = new JFrame("Bug of drawRect() demo");
    JPanel jPanel = new JPanel() {
        @Override
        public void paintComponent(Graphics g) {
            g.drawRect(1,1,2,2);
        }
    };

    jFrame.add(jPanel);
    jFrame.setSize(400, 100);
    jFrame.setLocationRelativeTo(null);
    jFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    jFrame.setVisible(true);
    }
}
更新2:我正在使用来自的OpenJDK 8。如果我在IDE中使用“Go To->Implementation(s)”,我会在这里看到drawRect()实现:C:\Program Files\ojdkbuild\java-1.8.0-openjdk-1.8.0.181-1\src.zip\java\awt\Graphics.java

public void drawRect(int x, int y, int width, int height) {
    if ((width < 0) || (height < 0)) {
        return;
    }

    if (height == 0 || width == 0) {
        drawLine(x, y, x + width, y + height);
    } else {
        drawLine(x, y, x + width - 1, y);
        drawLine(x + width, y, x + width, y + height - 1);
        drawLine(x + width, y + height, x + 1, y + height);
        drawLine(x, y + height, x, y + 1);
    }
}
public void drawRect(整数x、整数y、整数宽度、整数高度){
如果((宽度<0)| |(高度<0)){
回来
}
如果(高度=0 | |宽度=0){
抽绳(x,y,x+宽度,y+高度);
}否则{
抽绳(x,y,x+宽度-1,y);
抽绳(x+宽度,y,x+宽度,y+高度-1);
抽绳(x+宽度,y+高度,x+1,y+高度);
抽绳(x,y+高度,x,y+1);
}
}

在这个实现中,我看到它在“x+width”处绘制了第二行和第三行,而不是导致错误的“x+width-1”。

当我遇到同样的问题时,下面的代码(比这更复杂),我花了一些时间来理解我做错了什么(我在这里强调,就像你一样,我认为API是错误的:你画的是100x100的矩形,它应该是100x100,而不是101x101。):

在示例窗口中,我们可以看到绘制的矩形在宽度/高度上增加了一个像素

在我的例子中,这是有问题的,因为我正在使用绘制矩形的区域调用repaint。因此:

  • 我正在调用重新绘制(0,0,100,100)
  • Swing重新粉刷100x100正方形
  • 白线仍然存在,因为它没有重新喷漆
问题在于
Graphic
类在如何使用宽度和高度方面并不一致,正如下面的Javadoc摘录所示:

  • 从javadoc: 绘制指定矩形的轮廓。左右边缘 矩形的宽度为x和x+宽度。上边缘和下边缘为 在y和y+高度。使用图形绘制矩形 上下文的当前颜色

  • 从javadoc: 填充指定的矩形。矩形的左边缘和右边缘 矩形位于x和x+宽度-1。上边缘和下边缘位于 y和y+高度-1。生成的矩形覆盖一个区域宽度 宽像素高像素。矩形用 图形上下文的当前颜色

修复这样一个API是困难的,因为依赖它的代码将失败(因为要修复上面代码的实际问题,我将把99x99传递给100x100矩形:修复API将导致99x99矩形)

除非该类被改装成新的包(可能会合并
Graphics2D

TL;DR:您可能应该创建一个与
fillRect
相同的静态方法
drawRect
,如下所示:

public static void drawRect(Graphics g, int x, int y, int w, int h) {
  g.drawRect(x, y, w - 1, h - 1);
}

g.fillRect(1,1,2,2);
-对我来说只是一个2x2的正方形。在我看来,它就像API中描述的那样绘制。我在Windows 7上使用JDK 8。发布一篇正确的演示问题的文章,而不仅仅是几行代码。对不起,关于fillRect,你是对的。但是drawRect()仍然有一个问题。我已经相应地更新了我的问题,并将对我正在使用的JDK的引用和drawRect()的实现放在那里,这证明它是错误的。您能确认drawRect()也有问题吗?
但是drawRect()有问题仍然有一个问题。
-不,没有。它按照API中的描述进行绘制。阅读这两种方法的API,您将看到它们的区别。我在处阅读了它。我看到当前的行为是“矩形的左边缘和右边缘在x和x+宽度处”这句话所期望的。但是参数描述我认为下面的“宽度-要绘制的矩形的宽度”是错误的,因为它实际上不是一个宽度。宽度是实际显示的边缘的像素数,严格来说。你同意吗?我想人们一般都理解“宽度”这个词“意思是从一个起点向右。如果你不这样做,你还会用什么术语?”
    public class MyComponent extends JComponent {
      @Override
      public void paintComponent(final Graphics g) {
        g.setColor(Color.BLACK);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.RED);
        g.fillRect(0, 0, 100, getHeight());
        g.setColor(Color.WHITE);
        g.drawRect(0, 0, 100, 100);
      }

      public static void main(final String[] args) {
        final JFrame frame = new JFrame("Test");
        frame.setSize(150, +156);
        frame.getContentPane().add(new MyComponent());
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
      }
    }
public static void drawRect(Graphics g, int x, int y, int w, int h) {
  g.drawRect(x, y, w - 1, h - 1);
}