PyQt QGridLayout () неправильное поведение - PullRequest
0 голосов
/ 27 января 2020

Я пытаюсь заставить работать приложение GUI, но, к сожалению, интервал между отдельными объектами холста не такой, как ожидалось. Я хочу иметь следующую раскладку:

enter image description here

Для схемы сетки я использую следующий код:

# Adapt Widget StyleSheet
self.button_classification.setStyleSheet("font: bold 10pt Consolas; color: #009682")  # #009682 is the KIT-Green
self.button_start.setStyleSheet('font: bold 10pt Consolas; color: #009682; border-style: outset; border-width: 2px; border-radius: 10px; border-color: #646873; padding: 6px')
self.layout4_image_widget.setStyleSheet('background-image: url(Python_logo.png);')

# Define Layouts
self.window = QWidget()
self.layout = QGridLayout()

# Add Widgets to layouts
self.layout.addWidget(self.canvas_left, 0, 0, 5, 5)
self.layout.addWidget(self.canvas_right, 0, 5, 5, 5)
self.layout.addWidget(self.canvas_right_buttom, 8, 7, 3, 3)
self.layout.addWidget(self.canvas_right_top, 5, 7, 3, 3)
self.layout.addWidget(self.canvas_middle_buttom, 8, 3, 3, 4)
self.layout.addWidget(self.canvas_middle_top, 5, 3, 3, 4)
self.layout.addWidget(self.layout4_image_widget, 5, 0, 3, 3)
self.layout.addWidget(self.button_start, 8, 0, 1, 3)
self.layout.addWidget(self.button_classification, 9, 0, 1, 3)
self.layout.addWidget(self.LCD_Number, 10, 0, 1, 3)
self.window.setLayout(self.layout)

Но, к сожалению, в результате я получаю:

enter image description here

Итак, строки в середине 5-7 слишком широкие.

Ответы [ 2 ]

1 голос
/ 28 января 2020

Использование диапазонов столбцов и строк для виджетов не работает, как вы, кажется, верите. Каждая «ячейка» в макете сетки может иметь разные размеры, и все зависит от каждого sizeHint виджета и sizePolicy.

Все виджеты имеют размер по умолчанию policy, которая является свойством, которое виджет использует, чтобы сообщить своему контейнеру, как он ведет себя при изменении размера (если он расширяется, имеет фиксированную высоту / ширину, может ли он уменьшаться и т. д. c).
По умолчанию кнопки и флажки имеют фиксированную вертикальную политику, что означает, что они никогда не могут увеличиваться или уменьшаться.

Каждый макет имеет значение растяжения, которое можно назначить для каждого из его «слотов». Растяжка по умолчанию всегда равна 0, что оставляет каждому виджету возможность увеличиваться или уменьшаться в соответствии с его потребностями, но когда это значение установлено, доступные пространства вычисляются суммой каждого растяжения в макете и затем делятся поровну. Например, если у вас есть простой макет с 2 виджетами и растяжкой = 1 для первого и 2 для второго, доступное пространство будет разделено на 3 (1 + 2), причем первый занимает треть его, а второй 2 трети.
Для макетов сетки вы можете использовать setRowStretch() и setColumnStretch() для достижения чего-то, как вы предложили, но это будет работать только для виджетов, которые имеют совместимые политики (предпочтительно или с расширением), и, поскольку в вашем случае эти кнопки имеют фиксированную высоту, этого будет недостаточно.

Есть две возможности, но в обоих случаях я буду использовать более простую компоновку, поскольку нет необходимо использовать большое количество строк и столбцов по причинам, описанным выше, и вместо этого можно использовать setRowStretch / setColumnStretch.

В макете используется только 4 столбца:

+----+---+---+----+
|        |        |
+----+---+---+----+
|    |       |    |
+----+---+---+----+
|    |       |    |
+----+---+---+----+

В первом ряду есть две «ячейки» с интервалом в 2 столбца, а в следующих строках 2 центральных слота объединены в одну ячейку с одинаковым интервалом.

1. Вручную установите политику для этих виджетов

В этом случае фактически есть 5 строк, первая имеет rowStretch = 5, вторая 3 и оставшиеся 1. Путем установки политики вертикальных размеров для виджетов вручную, они могут вырасти до высоты, необходимой для растяжения ряда, который они занимают.

    # first row, notice the spans
    self.layout.addWidget(self.canvas_left, 0, 0, 1, 2)
    self.layout.addWidget(self.canvas_right, 0, 2, 1, 2)

    # second row, if the span is not specified defaults to (1, 1)
    self.layout.addWidget(self.layout4_image_widget, 1, 0)
    self.layout.addWidget(self.canvas_middle_top, 1, 1, 1, 2)
    self.layout.addWidget(self.canvas_right_top, 1, 3)

    # left widgets for third, fourth and fifth rows
    self.layout.addWidget(self.button_start, 2, 0)
    self.layout.addWidget(self.button_classification, 3, 0)
    self.layout.addWidget(self.LCD_Number, 4, 0)

    # remaining widgets, notice the vertical and horizontal spans
    self.layout.addWidget(self.canvas_right_buttom, 2, 1, 3, 2)
    self.layout.addWidget(self.canvas_middle_buttom, 2, 3, 3, 1)

    # the column stretches set based on the grid given by you
    self.layout.setColumnStretch(0, 3)
    self.layout.setColumnStretch(1, 2)
    self.layout.setColumnStretch(2, 2)
    self.layout.setColumnStretch(3, 3)

    # the row stretches, with the final 3 rows set to 1
    self.layout.setRowStretch(0, 5)
    self.layout.setRowStretch(1, 3)
    self.layout.setRowStretch(2, 1)
    self.layout.setRowStretch(3, 1)
    self.layout.setRowStretch(4, 1)

    # the default policy for both buttons and checkboxes is QSizePolicy.Minimum
    # horizontally, and QSizePolicy.Fixed vertically, let's just change the latter
    self.button_start.setSizePolicy(
        QSizePolicy.Minimum, QSizePolicy.Preferred)
    self.button_classification.setSizePolicy(
        QSizePolicy.Minimum, QSizePolicy.Preferred)

К сожалению, это не идеально: как вы можете видеть, кнопка может стать слишком большой, и флажок имеет много ненужные поля, которые могли бы использоваться виджетом LCD вместо этого.

size policy result

2. Используйте контейнерный виджет

В этом случае есть только 3 строки, и дополнительный QWidget используется в качестве контейнера для виджетов слева внизу.

    self.layout.addWidget(self.canvas_left, 0, 0, 1, 2)
    self.layout.addWidget(self.canvas_right, 0, 2, 1, 2)

    self.layout.addWidget(self.layout4_image_widget, 1, 0)
    self.layout.addWidget(self.canvas_middle_top, 1, 1, 1, 2)
    self.layout.addWidget(self.canvas_right_top, 1, 3)

    # create a container widget and add it to the main layout
    self.container = QWidget()
    self.layout.addWidget(self.container, 2, 0)
    containerLayout = QVBoxLayout(self.container)

    # add the widgets to the container
    containerLayout.addWidget(self.button_start)
    containerLayout.addWidget(self.button_classification)
    containerLayout.addWidget(self.LCD_Number)

    # the remaining widgets on the third row
    self.layout.addWidget(self.canvas_right_buttom, 2, 1, 1, 2)
    self.layout.addWidget(self.canvas_middle_buttom, 2, 3)

    self.layout.setColumnStretch(0, 3)
    self.layout.setColumnStretch(1, 2)
    self.layout.setColumnStretch(2, 2)
    self.layout.setColumnStretch(3, 3)

    # there are only 3 rows, the second and third have the same row span
    self.layout.setRowStretch(0, 5)
    self.layout.setRowStretch(1, 3)
    self.layout.setRowStretch(2, 3)

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

container result

...