Я начал заниматься программированием на Swing и обнаружил одну действительно странную вещь, которую я считаю ошибкой в основах.
В приведенном ниже примере показано, что значения "ширина" и "высота" обрабатываются по-разному при создании прямоугольника и при его отображении.
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));
Выход:
- true , true , false
- true , true , false
- ложь, ложь, ложь
Тогда:
// I make sure again that the right-bottom point of my rectangle is (2,2)
// by checking the intersection result with another Rectangle
println("intersect (2,2): " + rec.intersects(new Rectangle(2, 2, 5, 5)));
println("intersect (3,3): " + rec.intersects(new Rectangle(3, 3, 5, 5)));
Выход:
- пересечение (2,2): правда
- пересечение (3,3): ложь
Таким образом, с математической точки зрения это действительно прямоугольник 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:
Вывод: конструктор класса Rectangle () рассматривает ширину / высоту как реальную ширину / высоту фигуры в пикселях, в то время как метод рисования drawRect () учитывает ширину / высоту как сдвиг относительно левого верхнего пикселя.
Так java.awt представляет тот же прямоугольник, что и N x M для вычислений, но в виде (N + 1) x (M + 1), когда он отображается с drawRect () .
Я нахожу это совершенно неправильным, потому что человеческая логика по умолчанию предполагает, что мы рисуем именно то, что имеем!
Интересно, знает ли кто-то еще об этой проблеме и может ли дать некоторые ссылки на средства отслеживания ошибок или / и некоторые логические объяснения такого поведения. Просто поиск в Google мне ничего не дает.
Интересно также, как другие программисты решают эту проблему. Использовать обертки для рисования pushRect (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 из https://github.com/ojdkbuild/ojdkbuild/releases. Если я использую «Перейти к -> Реализация (и)» в моей IDE, я вижу реализацию 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);
}
}
В этой реализации я вижу, что она рисует вторую и третью строку в виде «x + width» вместо «x + width - 1», что вызывает ошибку.