Основная проблема с начальным позиционированием QGraphicsView / QGraphicsScene после show () в Qt5 - PullRequest
0 голосов
/ 02 ноября 2019

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

Я понятия не имею, что я делаю неправильно с этой инициализацией.

Сразу после .show ():

enter image description here

После потери фокуса (я переключаюсь, чтобы написать этот вопрос):

enter image description here

После изменения размера оно становится таким, как должно выглядетьКак / что я хочу достичь: enter image description here

Как исправить этот код, чтобы он работал при инициализации формы - я 1-й уровень в Qt5 (новичок) и 7-й уровень в программировании. Возможно, нужно очень простое изменение.

Вот рабочий код Python 3.8 / Qt5:

import logging
import sys
import typing

from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QSize, QPoint, Qt, QRect, QMargins
from PyQt5.QtGui import QFont, QPaintEvent, QPainter, QBrush, QColor, QPen
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QSizePolicy, QVBoxLayout, QHBoxLayout, QGraphicsWidget, \
    QGraphicsScene, QGraphicsView, QGraphicsGridLayout, QStyleOptionGraphicsItem, QGraphicsSceneMouseEvent


class Application(QApplication):
    pass


class SquareWidget(QGraphicsWidget):
    def __init__(self, color):
        super().__init__()
        if color:
            self.color = QtCore.Qt.white
        else:
            self.color = QtCore.Qt.black

    def paint(self, painter: QtGui.QPainter, option: QStyleOptionGraphicsItem, widget: typing.Optional[QWidget] = ...) -> None:
        painter.fillRect(option.rect, self.color)


class BoardContainer(QGraphicsWidget):
    def __init__(self):
        super().__init__()
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)

        grid = QGraphicsGridLayout()
        grid.setSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        self.setLayout(grid)
        for row in range(8):
            for column in range(8):
                square_widget = SquareWidget((row + column) % 2)
                grid.addItem(square_widget, row, column)


class BoardScene(QGraphicsScene):
    def __init__(self):
        super().__init__()

        self.board_container = board_container = BoardContainer()
        self.addItem(board_container)


class BoardView(QGraphicsView):
    def __init__(self):
        super().__init__()
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)

        scene = BoardScene()
        self.setScene(scene)
        # no frame
        self.setFrameShape(0)
        # transparent background
        # self.setStyleSheet('QGraphicsView {background: transparent;}')
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
        super().resizeEvent(event)
        self.fitInView(self.scene().board_container, Qt.KeepAspectRatio)


class BoardWidget(QWidget):
    def __init__(self):
        super().__init__()
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)

        grid = QGridLayout()

        board_view = BoardView()
        grid.addWidget(board_view, 0, 0)

        self.setLayout(grid)


def main():
    # show exceptions
    def excepthook(cls, exception, traceback):
        sys.__excepthook__(cls, exception, traceback)
    sys.excepthook = excepthook

    logging.basicConfig(level=logging.DEBUG)
    app = Application(sys.argv)
    app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)

    default_font = QFont()
    default_font.setPointSize(12)
    app.setFont(default_font)

    board_widget = BoardWidget()
    board_widget.setMinimumSize(640, 640)
    board_widget.show()

    sys.exit(app.exec())


if __name__ == '__main__':
    main()

Ответы [ 2 ]

2 голосов
/ 02 ноября 2019

Попробуйте:

import logging
import sys
import typing

from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QSize, QPoint, Qt, QRect, QMargins
from PyQt5.QtGui import QFont, QPaintEvent, QPainter, QBrush, QColor, QPen
from PyQt5.QtWidgets import QApplication, QWidget, QGridLayout, QSizePolicy, QVBoxLayout, QHBoxLayout, QGraphicsWidget, \
    QGraphicsScene, QGraphicsView, QGraphicsGridLayout, QStyleOptionGraphicsItem, QGraphicsSceneMouseEvent


class Application(QApplication):
    pass


class SquareWidget(QGraphicsWidget):
    def __init__(self, color):
        super().__init__()

        self.resize(640, 640)                                    # +++        

        if color:
            self.color = QtCore.Qt.white
        else:
            self.color = QtCore.Qt.black

    def paint(self, painter: QtGui.QPainter, option: QStyleOptionGraphicsItem, widget: typing.Optional[QWidget] = ...) -> None:
        painter.fillRect(option.rect, self.color)


class BoardContainer(QGraphicsWidget):
    def __init__(self):
        super().__init__()
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)

        self.resize(640, 640)                                     # +++
        self.setMinimumSize(80, 80)                               # +++       


        grid = QGraphicsGridLayout()
        grid.setSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        self.setLayout(grid)
        for row in range(8):
            for column in range(8):
                square_widget = SquareWidget((row + column) % 2)
                grid.addItem(square_widget, row, column)


class BoardScene(QGraphicsScene):
    def __init__(self):
        super().__init__()

        self.board_container = board_container = BoardContainer()
        self.addItem(board_container)


class BoardView(QGraphicsView):
    def __init__(self):
        super().__init__()
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)

        scene = BoardScene()
        self.setScene(scene)
        # no frame
        self.setFrameShape(0)
        # transparent background
        # self.setStyleSheet('QGraphicsView {background: transparent;}')
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)

    def resizeEvent(self, event: QtGui.QResizeEvent) -> None:
        super().resizeEvent(event)
        self.fitInView(self.scene().board_container, Qt.KeepAspectRatio)


class BoardWidget(QWidget):
    def __init__(self):
        super().__init__()
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)

        grid = QGridLayout()

        board_view = BoardView()
        grid.addWidget(board_view, 0, 0)

        self.setLayout(grid)


def main():
    # show exceptions
    def excepthook(cls, exception, traceback):
        sys.__excepthook__(cls, exception, traceback)
    sys.excepthook = excepthook

    logging.basicConfig(level=logging.DEBUG)
    app = Application(sys.argv)
    app.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling, True)

    default_font = QFont()
    default_font.setPointSize(12)
    app.setFont(default_font)

    board_widget = BoardWidget()
    board_widget.setMinimumSize(640, 640)
    board_widget.show()

    sys.exit(app.exec())


if __name__ == '__main__':
    main()

enter image description here

2 голосов
/ 02 ноября 2019

Поскольку сетка не имеет никакого значения для размера BoardContainer, она не может правильно расположить элементы в размере 0. Вы можете явно установить размер BoardContainer для любого размера, который вы хотите. Вот фиксированная часть кода:

class BoardContainer(QGraphicsWidget):
    def __init__(self):
        super().__init__()
        self.resize(100,100)
        logging.debug('size is %s for %s.', self.size(), self.__class__.__name__)
        grid = QGraphicsGridLayout()
        grid.setSpacing(0)
        grid.setContentsMargins(0, 0, 0, 0)
        self.setLayout(grid)
        for row in range(8):
            for column in range(8):
                square_widget = SquareWidget((row + column) % 2)
                grid.addItem(square_widget, row, column)
        grid.activate()  

, в конце концов, вызов grid.activate () заставляет компоновку на основе размера.

Чтобы поощрить вас к использованию QML, вотминимальный пример QML того же приложения с причудливой анимацией, чтобы продемонстрировать, как легко использовать анимацию в QML. Если вы удалите добавленную анимацию из этой реализации, чтобы она стала такой же, как версия вашего кода на c ++, это всего лишь 30 строк кода, что является фантастическим ИМХО.

import QtQml 2.12
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12

ApplicationWindow {

    id:mywin
    visible: true
    width: 640
    height: 640
    minimumWidth: 640
    minimumHeight: 480
    title: qsTr("Fancy Board")

    Item {
        anchors.centerIn: parent
        width: Math.min(parent.width,parent.height);
        height: width

        GridLayout{
            id : grid
            anchors.fill: parent
            rows: 8
            columns: 8
            rowSpacing: 0
            columnSpacing: 0
            Repeater{
                model: 64
                Rectangle{
                    Layout.fillWidth: true
                    Layout.fillHeight: true
                    color: ((index%8) - (index/8 | 0)) %2 === 0 ? 'black' : 'white'

                    Rectangle{
                        anchors.fill: parent
                        opacity: mouseArea.containsMouse ? 0.5 : 0
                        scale: mouseArea.containsMouse? 1 : 0
                        color: 'red'
                        Behavior on opacity{
                            NumberAnimation{ duration: 300 }
                        }
                        Behavior on scale {
                            NumberAnimation{ duration: 300; easing.type: Easing.OutCubic}
                        }
                    }
                    MouseArea{
                        id: mouseArea
                        anchors.fill: parent
                        hoverEnabled: true
                    }
                }
            }
        }
    }
}

Вы также можете скопировать и вставить этот код вФайл main.qml, заархивируйте его и загрузите в https://qt -webassembly.io / designviewer / , чтобы запустить его в браузере и убедиться, что он может работать и в вашем браузере.

...