Zoom All is a bit odd, but here's how that test went... Any pointers greatly appreciated!
# https://stackoverflow.com/questions/39614777/how-to-draw-a-proper-grid-on-pyqt
import sys
from PyQt5.QtCore import Qt, QRectF, QPointF
from PyQt5.QtGui import QBrush, QPainter, QPen, QColor, QTransform, QLinearGradient
from PyQt5.QtWidgets import (
QApplication,
QMainWindow,
QWidget,
QGraphicsScene,
QGraphicsView,
QHBoxLayout,
QVBoxLayout,
QPushButton,
QGraphicsItem,
QGraphicsLineItem,
QGraphicsItemGroup
)
class Settings():
WIDTH = 10
HEIGHT = 10
NUM_BLOCKS_X = 100
NUM_BLOCKS_Y = 100
class QGS(QGraphicsScene):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.settings = Settings()
# SET PAGE
self.page_width = self.settings.NUM_BLOCKS_X * self.settings.WIDTH
self.page_height = self.settings.NUM_BLOCKS_Y * self.settings.HEIGHT
self.setSceneRect(0, 0, self.page_width, self.page_height)
self.setItemIndexMethod(QGraphicsScene.NoIndex)
# CALC ORIGIN
pos_x = (self.settings.NUM_BLOCKS_X / 2) * self.settings.WIDTH
pos_y = (self.settings.NUM_BLOCKS_Y / 2) * self.settings.HEIGHT
self.origin = QPointF(pos_x, pos_y)
# GRID
self.lines = []
self.draw_grid()
self.set_opacity(0.3)
#self.set_visible(False)
#self.delete_grid()
# DRAW ORIGIN
self.draw_origin()
def draw_grid(self):
pen = QPen(QColor(222, 222, 255), 1, Qt.SolidLine)
for x in range(0, self.settings.NUM_BLOCKS_X+1):
xc = x * self.settings.WIDTH
self.lines.append(self.addLine(xc, 0, xc, self.page_height, pen))
for y in range(0, self.settings.NUM_BLOCKS_Y+1):
yc = y * self.settings.HEIGHT
self.lines.append(self.addLine(0, yc, self.page_width, yc, pen))
def set_visible(self,visible=True):
for line in self.lines:
line.setVisible(visible)
def delete_grid(self):
for line in self.lines:
self.removeItem(line)
del self.lines[:]
def set_opacity(self,opacity):
for line in self.lines:
line.setOpacity(opacity)
def draw_origin(self):
# X AXIS
ax = self.addLine(0, 0, 100, 0, Qt.red)
#ax.setPos(pos_x, pos_y)
ax.setPos(self.origin)
# Y AXIS
ay = self.addLine(0, 0, 0, 100, Qt.green)
#ay.setPos(pos_x, pos_y)
ay.setPos(self.origin)
class Win(QMainWindow):
view_scales = [0.2, 0.4, 0.6, 0.8, 1.0, 1.5, 2.0, 3.0]
view_scale_current = 4
def __init__(self):
super().__init__()
# GRAPHICS SCENE & VIEW
#self.scene = QGraphicsScene(0, 0, 2400, 2400)
#self.scene = QGV.QGS(0, 0, 2400, 2400)
self.scene = QGS(0, 0, 2400, 2400)
self.view = QGraphicsView(self.scene)
self.view.setRenderHint(QPainter.Antialiasing)
self.pen_line = QPen(Qt.black)
self.pen_line.setWidth(1)
#o.setPen(self.pen_line)
# TEST TOOLBAR
toolbox = QHBoxLayout()
btn_out = QPushButton("-")
btn_out.clicked.connect(self.view_scale_out)
toolbox.addWidget(btn_out)
btn_in = QPushButton("+")
btn_in.clicked.connect(self.view_scale_in)
toolbox.addWidget(btn_in)
btn_all = QPushButton("ALL")
btn_all.clicked.connect(self.view_scale_all)
toolbox.addWidget(btn_all)
btn_reset = QPushButton("RESET")
btn_reset.clicked.connect(self.view_scale_reset)
toolbox.addWidget(btn_reset)
# MAIN LAYOUT
vbox = QVBoxLayout()
vbox.addWidget(self.view)
vbox.addLayout(toolbox)
# WINDOW LAYOUT
widget = QWidget()
widget.setLayout(vbox)
self.setCentralWidget(widget)
# LOAD DRAWING
self.dwg_load()
def dwg_load(self):
# TMP
self.add_object({"type":"LINE", "pos":[0, 0], "v1":[10, 10], "v2":[100, 10]})
self.add_object({"type":"LINE", "pos":[0, 0], "v1":[10, 20], "v2":[100, 100]})
self.add_object({"type":"LINE", "pos":[150, 50], "v1":[0, 0], "v2":[100, 100]})
def add_object(self, data):
o = QGraphicsItemGroup()
if data["type"] == "LINE":
e = QGraphicsLineItem() #0, 0, 200, 50)
e.setPos(data["pos"][0], data["pos"][1]*-1)
#e.setLine(data["v1"][0], data["v1"][1], data["v2"][0], data["v2"][1])
e.setLine(data["v1"][0], data["v1"][1]*-1, data["v2"][0], data["v2"][1]*-1)
e.setPen(self.pen_line)
e.setData(0, data)
o.addToGroup(e)
# PROPERTIES
o.setFlag(QGraphicsItem.ItemIsMovable)
o.setFlag(QGraphicsItem.ItemIsSelectable)
# !!! NOW SET ORIGIN POS
o.setPos(self.scene.origin)
o.setData(0, {"type":"g"})
self.scene.addItem(o)
def view_scale_out(self):
self.view_scale_current -= 1
if self.view_scale_current < 0:
self.view_scale_current = 0
self.view.setTransform(QTransform())
self.view.scale(self.view_scales[self.view_scale_current], self.view_scales[self.view_scale_current])
print("View Scale:", self.view_scales[self.view_scale_current], ", ", self.view_scale_current)
def view_scale_in(self):
self.view_scale_current += 1
if self.view_scale_current > len(self.view_scales)-1:
self.view_scale_current = len(self.view_scales)-1
self.view.setTransform(QTransform())
self.view.scale(self.view_scales[self.view_scale_current], self.view_scales[self.view_scale_current])
print("View Scale:", self.view_scales[self.view_scale_current], ", ", self.view_scale_current)
def view_scale_reset(self):
self.view.setTransform(QTransform())
self.view.scale(1.0, 1.0)
self.view_scale_current = 4
print("View Scale:", self.view_scales[self.view_scale_current], ", ", self.view_scale_current)
def view_scale_all(self):
print("ZOOM ALL")
#items = self.scene.selectedItems()
items = self.scene.items()
# CALC BOUNDS
min_x = sys.float_info.max
max_x = sys.float_info.min
min_y = sys.float_info.max
max_y = sys.float_info.min
#i = 0
for item in items:
d = item.data(0)
if d != None and d["type"] == "g":
#bb = self.obj_bounds(item)
#br = item.sceneBoundingRect()
br = item.childrenBoundingRect()
br.translate(item.pos())
#br.moveTo(item.pos())
#br.moveCenter(item.pos())
# TOP LEFT
if br.left() < min_x:
min_x = br.left()
if br.top() < min_y:
min_y = br.top()
# BOTTOM RIGHT
if br.right() > max_x:
max_x = br.right()
if br.bottom() > max_y:
max_y = br.bottom()
self.view.fitInView(QRectF(min_x, min_y, max_x, max_y), Qt.KeepAspectRatio)
# IgnoreAspectRatio, KeepAspectRatio, KeepAspectRatioByExpanding
self.view.repaint()
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Win()
w.show()
sys.exit(app.exec_())