Фиксированный размер QGraphicsView и QGraphicsScene - PullRequest
0 голосов
/ 27 апреля 2020

У меня есть QMdiSubWindow, который содержит QTabWidget, который содержит QGraphicsView внутри виджета с QHBoxLayout. Подокно находится в области mdi в моем главном окне. Моя цель - иметь фиксированный размер для QGraphicScene, в зависимости от размера бумаги, которую я использую. В этом случае представление должно либо соответствовать тому же размеру, что и сцена, не показывая полос прокрутки, если эта область может вписаться в общую доступную область mdi, также изменяя размер подокна, или должно изменять размер, чтобы заполнить доступную область, изменяя размер подокна, и должны показывать полосы прокрутки для перехода к оставшемуся пространству.

Мой текущий подход вращается вокруг изменения размера сначала подокна mdi, а затем вызова для изменения размера текущего активного виджета в QTabWidget окна. Это все сделано согласно реализации musicamante. Текущий виджет выбирает минимальное значение между родительским (QStackedWidget) родительским (QTabWidget) родительским (QMdiSubWindow) прямоугольником (с изменением размера в первую очередь) и размерами QGraphicsScene, который обновляется, когда я устанавливаю размеры.

-> Установить размеры QGraphicsScene из пользовательского ввода

-> Изменить размер подокна

-> Изменить размер QGraphicsView

Я использую ту же логику c, в моей программе, которая вообще не отображает полосы прокрутки, и представление расширяется, чтобы соответствовать QGraphicsScene, несмотря на то, что вместо этого указывается размер подокна (подокно имеет правильный размер), и в следующем примере, где они показывают при необходимости, но частично обрезается.

from PyQt5 import QtWidgets, QtCore, QtGui
paperSizes = {
    "A0": {
        "72": [2384, 3370],
        "96": [3179, 4494],
        "150": [4967, 7022],
        "300": [9933, 14043]
    },
    "A1": {
        "72": [1684, 2384],
        "96": [2245, 3179],
        "150": [3508, 4967],
        "300": [7016, 9933]
    },
    "A2": {
        "72": [1191, 1684],
        "96": [1587, 2245],
        "150": [2480, 3508],
        "300": [4960, 7016]
    },
    "A3": {
        "72": [842, 1191],
        "96": [1123, 1587],
        "150": [1754, 2480],
        "300": [3508, 4960]
    },
    "A4": {
        "72": [595, 842],
        "96": [794, 1123],
        "150": [1240, 1754],
        "300": [2480, 3508]
    }
}
class canvas(QtWidgets.QWidget):

    def __init__(self, parent=None, size= 'A4', ppi= '72'):
        super(canvas, self).__init__(parent)
        self._ppi = ppi
        self._canvasSize = size 
        self.painter = QtWidgets.QGraphicsScene()        
        self.painter.setBackgroundBrush(QtGui.QBrush(QtCore.Qt.white))

        self.view = QtWidgets.QGraphicsView(self.painter)
        # self.view.setMinimumSize(595, 842)

        self.layout = QtWidgets.QHBoxLayout(self)
        self.layout.addWidget(self.view, stretch = 1, alignment= QtCore.Qt.AlignCenter)
        self.setLayout(self.layout)

        self.painter.setSceneRect(0, 0, *paperSizes[self.canvasSize][self.ppi])

    def resizeView(self, w, h):
        self.painter.setSceneRect(0, 0, w, h)
        self.adjustView()

    def adjustView(self):
        self.view.setSceneRect(0, 0, self.painter.sceneRect().width() - self.view.frameWidth() * 2, 
            self.painter.sceneRect().height())
        # give the view some time to adjust itself
        QtWidgets.QApplication.processEvents()
        width = self.painter.sceneRect().width() + self.view.frameWidth()*2
        if self.view.verticalScrollBar().isVisible():
            width += self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollBarExtent)
        height = self.painter.sceneRect().height() + self.view.frameWidth()*2
        if self.view.verticalScrollBar().isVisible():
            height += self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollBarExtent)

        self.view.setFixedWidth(min(self.parent().rect().width() - self.view.frameWidth()*2, width))
        self.view.setFixedHeight(min(self.parent().rect().height()- self.view.frameWidth()*2, height))
    def resizeEvent(self, event):
        self.adjustView()

    def setCanvasSize(self, size):
        self.canvasSize = size

    def setCanvasPPI(self, ppi):
        self.ppi = ppi

    @property
    def canvasSize(self):
        return self._canvasSize
    @property
    def ppi(self):
        return self._ppi

    @canvasSize.setter
    def canvasSize(self, size):
        self._canvasSize = size
        if self.painter:
            self.resizeView(*paperSizes[self.canvasSize][self.ppi])

    @ppi.setter
    def ppi(self, ppi):
        self._ppi = ppi
        if self.painter:
            self.resizeView(*paperSizes[self.canvasSize][self.ppi])

    @property
    def dimensions(self):
        #returns the dimension of the current scene
        return self.painter.sceneRect().width(), self.painter.sceneRect().height()

class AppDemo(QtWidgets.QMainWindow):
    def __init__(self):
        super(AppDemo, self).__init__()
        self.centralwidget = canvas(self)
        width, height = paperSizes['A4']['72']
        wsetter = min(1800, width - self.centralwidget.view.frameWidth()*2)
        hsetter = min(900, height - self.centralwidget.view.frameWidth()*2)
        self.setFixedSize(wsetter, hsetter)
        self.centralwidget.resizeView(width, height)
        self.setCentralWidget(self.centralwidget)
        self.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.resizer)
        self.show()

    def resizer(self, point):
        width, height = paperSizes['A0']['300']
        wsetter = min(1800, width - self.centralwidget.view.frameWidth()*2)
        hsetter = min(900, height - self.centralwidget.view.frameWidth()*2)
        self.setFixedSize(wsetter, hsetter)
        self.centralWidget().resizeView(width, height)
def main():
    import sys
    app = QtWidgets.QApplication(sys.argv)

    w = AppDemo()
    w.setWindowTitle('AppDemo')
    w.centralwidget.resizeView(*paperSizes['A0']['72'])
    w.show()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

1 Ответ

0 голосов
/ 27 апреля 2020

Если вы собираетесь всегда сохранять преобразование по умолчанию (без масштабирования), может иметь смысл установить представление sceneRect, используя реальный прямоугольник сцены в качестве ссылки.

Обратите внимание, что, поскольку окно может быть При изменении размера обычно лучше использовать для этого общую функцию и вызывать ее также в resizeEvent(). Это также обеспечивает изменение размера представления, если вертикальная полоса прокрутки становится видимой.

class canvas(QtWidgets.QWidget):
    def __init__(self, parent=None, size= 'A4', ppi= '72'):
        # ...
        w, h = paperSizes[self.canvasSize][self.ppi]
        self.painter.setSceneRect(0, 0, w, h)
        # ensure that the scene is always aligned on the left, instead of being
        # centered (the default)
        self.view.setAlignment(QtCore.Qt.AlignLeft|QtCore.Qt.AlignTop)
        # no need for this here
        # self.view.setSceneRect(0, 0, w, h) 

    def resizeView(self, w, h):
        self.painter.setSceneRect(0, 0, w, h)
        self.adjustView()

    def adjustView(self):
        self.view.setSceneRect(0, 0, self.painter.sceneRect().width() - self.view.frameWidth() * 2, 
            self.painter.sceneRect().height())
        # give the view some time to adjust itself
        QtWidgets.QApplication.processEvents()
        width = self.painter.sceneRect().width() + self.view.frameWidth() * 2
        if self.view.verticalScrollBar().isVisible():
            width += self.style().pixelMetric(QtWidgets.QStyle.PM_ScrollBarExtent)
        self.view.setFixedWidth(width)

    def resizeEvent(self, event):
        self.adjustView()

Очевидно, если вы уверены, что представление всегда будет отображать всю ширину сцены, вы также можете полностью отключить горизонтальная полоса прокрутки, установив ее horizontalScrollBarPolicy в Qt.ScrollBarAlwaysOff.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...