Почему виджеты перекрываются в ООП-версии

Я упростил свою ситуацию до простой: я хочу запрограммировать GUI в PyQt5, где есть основной QGridLayout с именем grid, в котором есть еще одна сетка gridParamter и виджет QListView. В gridParamter есть 2 QLabel

Вот код

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

def window():
    app = QApplication(sys.argv)
    win = QWidget()

    list1 = QListView()

    gridParameter = QGridLayout()

    idxRow = 0
    label_1 = QLabel("I am label one")
    gridParameter.addWidget(label_1, idxRow, 0)

    idxRow = 1
    label_2 = QLabel("I am label two")
    gridParameter.addWidget(label_2, idxRow, 1)

    grid = QGridLayout()
    grid.addLayout(gridParameter, 0, 0)
    grid.setSpacing(2)
    grid.addWidget(list1)

    win.setLayout(grid)
    win.show()
    sys.exit(app.exec_())

if __name__ == '__main__':      
    window()

который может создать графический интерфейс, как я и ожидал. Но когда я пытаюсь переписать его в стиле ООП, т.е.

import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class MainWindow(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        list1 = QListView(self)

        gridParameter = QGridLayout(self)

        idxRow = 0
        label_1 = QLabel("I am label one", self)
        gridParameter.addWidget(label_1, idxRow, 0)

        idxRow = 1
        label_2 = QLabel("I am label two", self)
        gridParameter.addWidget(label_2, idxRow, 1)

        grid = QGridLayout(self)
        grid.addLayout(gridParameter, 0, 0)
        grid.setSpacing(2)
        grid.addWidget(list1)

        self.setLayout(grid)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit( app.exec_() )

Я обнаружил, что label_1 перекрывается с list1, и когда я пытаюсь изменить размер основных окон, list1 всегда занимает положение сетки (0, 0).


person oyster    schedule 26.12.2018    source источник


Ответы (1)


Сначала вы должны понять следующее:

  1. Имейте в виду, что следующее выражение:

    lay = FooLayout()
    some_widget.setWidget(lay)
    

эквивалентно:

lay = FooLayout(some_widget)

И то и другое указывает, что макет будет обрабатывать геометрию дочерних элементов.

  1. С другой стороны, если у виджета уже есть раскладка, никакая другая раскладка не может быть установлена, пока предыдущая раскладка не будет удалена.

Таким образом, в вашем случае работает только первая инструкция, а не следующие 2, поэтому сетка макета будет устранена, а список сохраняется только потому, что он является дочерним элементом виджета.

gridParameter = QGridLayout(self)
# ...
grid = QGridLayout(self)
# ...
self.setLayout(grid)

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

import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class MainWindow(QtWidgets.QWidget):
    def __init__(self):
        super(MainWindow, self).__init__()

        list1 = QtWidgets.QListView()

        gridParameter = QtWidgets.QGridLayout()

        idxRow = 0
        label_1 = QtWidgets.QLabel("I am label one")
        gridParameter.addWidget(label_1, idxRow, 0)

        idxRow = 1
        label_2 = QtWidgets.QLabel("I am label two")
        gridParameter.addWidget(label_2, idxRow, 1)

        grid = QtWidgets.QGridLayout(self) # <--- principal layout
        grid.addLayout(gridParameter, 0, 0)
        grid.setSpacing(2)
        grid.addWidget(list1)


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    mainWin = MainWindow()
    mainWin.show()
    sys.exit(app.exec_())

В заключение используйте self, когда это необходимо.

person eyllanesc    schedule 26.12.2018