Librecad uses a widget which can be infinitely resized, you can zoom in and out as much as you can. Which widget does it uses?
When I paint into a common widget, the painting is done at certain coordinates of the widget. However, I would like to draw at floating coordinates of the widget and use a line width which is fixed to certain pixels of the viewport.
Before resizing:
After resizing:
Which widget provides this functionality?
You have to use QGraphicsView and QGraphicsScene(see Graphics View Framework):
from PyQt5 import QtCore, QtGui, QtWidgets
class GraphicsView(QtWidgets.QGraphicsView):
def __init__(self, parent=None):
super(GraphicsView, self).__init__(parent)
self.factor = 1.2
self.setDragMode(QtWidgets.QGraphicsView.ScrollHandDrag)
self.setRenderHints(
QtGui.QPainter.Antialiasing | QtGui.QPainter.SmoothPixmapTransform
)
self.setMouseTracking(True)
self.setScene(
QtWidgets.QGraphicsScene(QtCore.QRectF(-400, -400, 800, 800), self)
)
QtWidgets.QShortcut(QtGui.QKeySequence.ZoomIn, self, activated=self.zoomIn) # Ctrl + +
QtWidgets.QShortcut(QtGui.QKeySequence.ZoomOut, self, activated=self.zoomOut) # Ctrl + -
@QtCore.pyqtSlot()
def zoomIn(self):
self.zoom(self.factor)
@QtCore.pyqtSlot()
def zoomOut(self):
self.zoom(1 / self.factor)
def zoom(self, f):
self.scale(f, f)
def drawForeground(self, painter, rect):
super(GraphicsView, self).drawForeground(painter, rect)
if not hasattr(self, "cursor_position"):
return
painter.save()
painter.setTransform(QtGui.QTransform())
pen = QtGui.QPen(QtGui.QColor("yellow"))
pen.setWidth(4)
painter.setPen(pen)
r = self.mapFromScene(rect).boundingRect()
linex = QtCore.QLine(
r.left(), self.cursor_position.y(), r.right(), self.cursor_position.y(),
)
liney = QtCore.QLine(
self.cursor_position.x(), r.top(), self.cursor_position.x(), r.bottom(),
)
for line in (linex, liney):
painter.drawLine(line)
painter.restore()
def mouseMoveEvent(self, event):
self.cursor_position = event.pos()
self.scene().update()
super(GraphicsView, self).mouseMoveEvent(event)
def wheelEvent(self, event):
angle = event.angleDelta().y()
if angle < 0:
self.zoomIn()
else:
self.zoomOut()
super(GraphicsView, self).wheelEvent(event)
if __name__ == "__main__":
import sys
import random
app = QtWidgets.QApplication(sys.argv)
w = GraphicsView()
for _ in range(4):
r = QtCore.QLineF(
*random.sample(range(-200, 200), 2), *random.sample(range(50, 150), 2)
)
it = w.scene().addLine(r)
pen = QtGui.QPen(QtGui.QColor(*random.sample(range(255), 3)))
pen.setWidthF(5.0)
pen.setCosmetic(True)
it.setPen(pen)
w.resize(640, 480)
w.show()
sys.exit(app.exec_())