Why drawing lines with integer coords is not correct:
Qt Code:
  1. #include <QApplication>
  2. #include <QLabel>
  3. #include <QCheckBox>
  4. #include <QPainter>
  5. #include <QMouseEvent>
  6. #include <QLayout>
  7.  
  8. class DrawLine: public QWidget {
  9. Q_OBJECT
  10. public:
  11. DrawLine() : size(17), scale(40), radius(5), active(-1), hover(-1),
  12. image(size, size, QImage::Format_RGB32), round(false),
  13. antialiasing(false) {
  14. int sz = size*scale;
  15. setMinimumSize(sz, sz);
  16. int half = sz/2;
  17. pts[0] = QPoint(half/2, half);
  18. pts[1] = QPoint(half*3/2, half);
  19. renderLine();
  20. setMouseTracking(true);
  21. }
  22. void emitCoords() {
  23. QString str;
  24. if (round) {
  25. QPoint p0 = roundCoords(0);
  26. QPoint p1 = roundCoords(1);
  27. str.sprintf("P0: (%d, %d) P1: (%d, %d)", p0.x(), p0.y(), p1.x(), p1.y());
  28. } else {
  29. QPointF p0 = coords(0);
  30. QPointF p1 = coords(1);
  31. str.sprintf("P0: (%.2f, %.2f) P1: (%.2f, %.2f)", p0.x(), p0.y(), p1.x(), p1.y());
  32. }
  33. emit coordsUpdated(str);
  34. }
  35. public slots:
  36. void setRound(bool round) {
  37. this->round = round;
  38. renderLine();
  39. }
  40. void setAntialiasing(bool antialiasing) {
  41. this->antialiasing = antialiasing;
  42. renderLine();
  43. }
  44. signals:
  45. void coordsUpdated(QString coords);
  46. protected:
  47. virtual void paintEvent(QPaintEvent*) {
  48. QPainter p(this);
  49. for (int i = 0; i < size; ++i) {
  50. for (int j = 0; j < size; ++j) {
  51. QRgb cur = image.pixel(i, j);
  52. p.fillRect(i*scale, j*scale, scale, scale, QColor(cur));
  53. }
  54. }
  55. p.setPen(Qt::lightGray);
  56. int sz = size*scale;
  57. for (int i = 0; i < size; ++i) {
  58. int x = i*scale;
  59. p.drawLine(x, 0, x, sz);
  60. p.drawLine(0, x, sz, x);
  61. }
  62. p.setRenderHint(QPainter::Antialiasing);
  63. p.setPen(Qt::blue);
  64. p.drawLine(pts[0], pts[1]);
  65. p.setPen(Qt::NoPen);
  66. for (int i = 0; i < 2; ++i) {
  67. p.setBrush(i == hover ? Qt::yellow : Qt::blue);
  68. p.drawEllipse(pts[i], radius, radius);
  69. }
  70. }
  71. virtual void mousePressEvent(QMouseEvent *event) {
  72. if (active == -1 && event->button() == Qt::LeftButton) {
  73. int current = index(event->pos());
  74. if (current != -1)
  75. active = current;
  76. }
  77. }
  78. virtual void mouseReleaseEvent(QMouseEvent *event) {
  79. if (active != -1 && event->button() == Qt::LeftButton) {
  80. active = -1;
  81. }
  82. }
  83. virtual void mouseMoveEvent(QMouseEvent *event) {
  84. if (active != -1) {
  85. pts[active] = event->pos();
  86. renderLine();
  87. }
  88. int current = index(event->pos());
  89. if (current != hover) {
  90. hover = current;
  91. update();
  92. }
  93. }
  94. private:
  95. QPointF coords(int idx) {
  96. return QPointF(pts[idx])/scale;
  97. }
  98. QPoint roundCoords(int idx) {
  99. return (coords(idx) - QPointF(0.5, 0.5)).toPoint();
  100. }
  101. int index(QPoint p) {
  102. for (int i = 0; i < 2; ++i) {
  103. if (QLineF(p, pts[i]).length() <= radius)
  104. return i;
  105. }
  106. return -1;
  107. }
  108. void renderLine() {
  109. image.fill(qRgb(255, 255, 255));
  110. QPainter p(&image);
  111. p.setRenderHint(QPainter::Antialiasing, antialiasing);
  112. p.setPen(Qt::red);
  113. if (round) {
  114. p.drawLine(roundCoords(0), roundCoords(1));
  115. } else {
  116. p.drawLine(coords(0), coords(1));
  117. }
  118. emitCoords();
  119. update();
  120. }
  121. int size;
  122. int scale;
  123. int radius;
  124. int active;
  125. int hover;
  126. QImage image;
  127. QPoint pts[2];
  128. bool round;
  129. bool antialiasing;
  130. };
  131.  
  132. int main(int argc, char *argv[])
  133. {
  134. QApplication app(argc, argv);
  135. QWidget widget;
  136. QLabel label;
  137. QCheckBox round("Round coords");
  138. QCheckBox antialiasing("Antialiasing");
  139. DrawLine draw;
  140. QObject::connect(&draw, SIGNAL(coordsUpdated(QString)), &label, SLOT(setText(QString)));
  141. QObject::connect(&round, SIGNAL(toggled(bool)), &draw, SLOT(setRound(bool)));
  142. QObject::connect(&antialiasing, SIGNAL(toggled(bool)), &draw, SLOT(setAntialiasing(bool)));
  143. QGridLayout layout;
  144. layout.addWidget(&round, 0, 0);
  145. layout.addWidget(&antialiasing, 0, 1);
  146. layout.addWidget(&label, 0, 2);
  147. layout.addWidget(&draw, 1, 0, 1, 3);
  148. layout.setColumnStretch(2, 1);
  149. widget.setLayout(&layout);
  150. widget.show();
  151. draw.emitCoords();
  152. return app.exec();
  153. }
  154.  
  155. #include "main.moc"
To copy to clipboard, switch view to plain text mode 

QPainter-DrawLine.jpg