我有一个父小部件(QWidget)。我使用 PaintEvent 方法在其上绘制网格。该小部件有一个子小部件(QWidget)。子窗口小部件只能在父窗口小部件的网格单元中移动(我已经重写了这些方法)。我需要实现以下功能:
能够缩放网格。也就是说,当我滚动鼠标滚轮时,屏幕上适合的单元格数量会增加。因此,当我向另一个方向滚动滚轮时,数量会减少。我在wheelEvent方法中实现了这个功能。
增加位于单元格中的小部件的大小。也就是说,当您接近时,小部件的大小与单元格的大小成比例增长。我对此有问题,因为小部件尺寸的减小/增大与单元格尺寸不成比例。 我尝试使用坐标变换,但没有成功。让我立即澄清:我没有在 QGraphicsView 中实现所有这些功能。但这些类并不合适,因为无法在 QGraphicsScene 上放置安装了第三方应用程序窗口的小部件。我的程序涉及拦截第三方窗口并将这些窗口安装到小部件中,并进一步将这些小部件添加到网格中。我将不胜感激任何帮助!
class MoveWidget(QWidget):
def __init__(self):
super(MoveWidget, self).__init__()
self.click_rect = self.rect()
self.selected_edge = None
self.click_pos = None
self.setAutoFillBackground(True)
self.setStyleSheet("background-color: yellow; "
"color: red;"
"border: 2px solid blue;")
grid = QGridLayout(self)
self.setLayout(grid)
grid.addWidget(QPushButton("fdfdsfdsfdsf"), 0, 0)
grid.addWidget(QPushButton("1111111111111"), 1, 0)
self.setGeometry(0, 0, 300, 300)
def paintEvent(self, a0) -> None:
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
self.style().drawPrimitive(QStyle.PrimitiveElement.PE_Widget, opt, painter, self)
def mousePressEvent(self, event):
self.click_pos = event.pos()
rect = self.rect()
top = abs(rect.top())
bottom = abs(rect.bottom())
left = abs(rect.left())
right = abs(rect.right())
if abs(left - abs(self.click_pos.x())) < 30 and (
abs(bottom - abs(self.click_pos.y())) > 30) and (abs(top - abs(self.click_pos.y())) > 30):
self.selected_edge = 'left'
elif abs(right - abs(self.click_pos.x())) < 30 and (
abs(bottom - abs(self.click_pos.y())) > 30) and (abs(top - abs(self.click_pos.y())) > 30):
self.selected_edge = 'right'
elif abs(top - abs(self.click_pos.y())) < 30 and (abs(right - abs(self.click_pos.x())) > 30) and (
abs(left - abs(self.click_pos.x())) > 30):
self.selected_edge = 'top'
elif abs(bottom - abs(self.click_pos.y())) < 30 and (
abs(right - abs(self.click_pos.x())) > 30) and (abs(left - abs(self.click_pos.x())) > 30):
self.selected_edge = 'bottom'
elif (abs(bottom - abs(self.click_pos.y())) < 30) and (abs(right - abs(self.click_pos.x())) < 30):
self.selected_edge = 'diag_bottom_right'
elif (abs(bottom - abs(self.click_pos.y())) < 30) and (abs(left - abs(self.click_pos.x())) < 30):
self.selected_edge = 'diag_bottom_left'
elif (abs(top - abs(self.click_pos.y())) < 30) and (abs(right - abs(self.click_pos.x())) < 30):
self.selected_edge = 'diag_top_right'
elif (abs(top - abs(self.click_pos.y())) < 30) and (abs(left - abs(self.click_pos.x())) < 30):
self.selected_edge = 'diag_top_left'
else:
self.selected_edge = None
self.click_pos = event.pos()
self.click_rect = rect
self.cl = self.mapFromParent(QPoint(rect.x(), rect.y()))
super().mousePressEvent(event)
def mouseMoveEvent(self, event):
pos = event.pos()
x_diff = (round((pos.x() - self.click_pos.x()) / 300) * 300)
y_diff = (round((pos.y() - self.click_pos.y()) / 300) * 300)
# Start with the rectangle as it was when clicked.
rect = QRectF(self.click_rect)
# c = self.rect().getCoords()
# rect = QRectF(c[0], c[1], c[2], c[3],)
self.pos()
if self.selected_edge is None:
self.move(self.mapToParent(QPoint(x_diff, y_diff)))
print(self.pos())
return
elif self.selected_edge == 'top':
rect.adjust(0, y_diff, 0, 0)
elif self.selected_edge == 'left':
rect.adjust(x_diff, 0, 0, 0)
elif self.selected_edge == 'bottom':
rect.adjust(0, 0, 0, y_diff)
elif self.selected_edge == 'right':
rect.adjust(0, 0, (x_diff), 0)
elif self.selected_edge == 'diag_bottom_right':
rect.adjust(0, 0, (x_diff), (x_diff))
elif self.selected_edge == 'diag_top_right':
rect.adjust(0, -(x_diff), (x_diff), 0)
elif self.selected_edge == 'diag_bottom_left':
rect.adjust((x_diff), 0, 0, -(x_diff))
elif self.selected_edge == 'diag_top_left':
rect.adjust((x_diff), (x_diff), 0, 0)
s = self.mapToParent(QPoint(int(rect.x()), int(rect.y())))
d = rect.getCoords()
ee = self.mapToParent(QPoint(int(d[2]), int(d[3])))
self.setGeometry(s.x(), s.y(), int(d[2]), int(d[3]))
s = self.rect()
print(self.pos())
class WidMain(QWidget):
def __init__(self):
super().__init__()
self.setStyleSheet("background: transparent;")
self.setAutoFillBackground(True)
self.movewid = MoveWidget()
self.movewid.setParent(self)
self.factor = 1.0
def wheelEvent(self, event):
self.factor *= 1.01 ** (event.angleDelta().y() / 15.0)
self.update()
print("масштаб", self.factor)
child = self.children()
print(child[0].rect(), "геометрия дочернего виджета без применения преобразования в своих координатах")
transform = QTransform()
transform.scale(self.factor, self.factor)
print(transform.mapRect(child[0].rect()), "геометрия дочернего виджета с применения преобразования в своих координатах")
child[0].setGeometry(transform.mapRect(child[0].rect()))
print(child[0].rect(),'Новая геометрия дочернего виджета после преобразований')
transform.reset()
def paintEvent(self, a0) -> None:
opt = QStyleOption()
opt.initFrom(self)
painter = QPainter(self)
self.style().drawPrimitive(QStyle.PrimitiveElement.PE_Widget, opt, painter, self)
pen = QPen(QColor("blue"))
pen.setWidth(5)
painter.setPen(pen)
child = self.children()
transform = QTransform()
transform.scale(self.factor, self.factor)
painter.setTransform(transform)
for i in range(0, int(self.width()*1000), 300):
painter.drawLine(i, 0, i, int(self.height()*1000))
for i in range(0, int(self.height()*1000), 300):
painter.drawLine(0, i, int(self.width()*1000), i)
super().paintEvent(a0)
if __name__ == '__main__':
app = QApplication([])
w = WidMain()
w.show()
app.exec()
您没有考虑之前应用于几何体的当前比例。
一个可能更正确的实现如下:
def wheelEvent(self, event):
old = self.factor
self.factor *= 1.01 ** (event.angleDelta().y() / 15.0)
child = self.children()
new = self.factor / old
transform = QTransform().scale(new, new)
child[0].setGeometry(transform.mapRect(child[0].rect()))
self.update()
但请注意,您使用的是基于整数的几何形状,这意味着如果超出某个“放大”因子,您将遇到近似问题。
更好的方法是基于网格的占用“单元”,使用预定义的几何图形作为参考,并始终基于此计算新的几何图形。