Как изменить текущую настройку PyQt5 для включения изменения размера перетаскивания между макетами - PullRequest
0 голосов
/ 02 марта 2020

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

window

Вот код:

from PyQt5.QtWidgets import (QMainWindow, QApplication, QDesktopWidget, QHBoxLayout, QVBoxLayout, QWidget,
                             QLabel, QListWidget)
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt
import sys


class TestWindow(QMainWindow):
    def __init__(self, left_ratio, right_ratio, window_title):
        super().__init__()
        self.left_ratio = left_ratio
        self.right_ratio = right_ratio
        self.current_image = None
        self.window_title = window_title
        self.setWindowTitle(self.window_title)
        win_rectangle = self.frameGeometry()
        center_point = QDesktopWidget().availableGeometry().center()
        win_rectangle.moveCenter(center_point)
        self.move(win_rectangle.topLeft())
        self.tools = self.addToolBar('Tools')
        self.left_widgets = {'Image': QLabel()}
        self.right_widgets = {'List1t': QLabel('List1'), 'List1l': QListWidget(),
                              'List2t': QLabel('List2'), 'List2l': QListWidget()}
        self.central_widget = QWidget(self)
        self.main_layout = QHBoxLayout()
        self.left_layout = QVBoxLayout()
        self.right_layout = QVBoxLayout()
        self.adjust_widgets()
        self.adjust_layouts()
        self.show()

    def adjust_layouts(self):
        self.main_layout.addLayout(self.left_layout, self.left_ratio)
        self.main_layout.addLayout(self.right_layout, self.right_ratio)
        self.central_widget.setLayout(self.main_layout)
        self.setCentralWidget(self.central_widget)

    def adjust_widgets(self):
        self.left_layout.addWidget(self.left_widgets['Image'])
        self.left_widgets['Image'].setPixmap(QPixmap('test.jpg').scaled(500, 400, Qt.IgnoreAspectRatio,
                                                                        Qt.SmoothTransformation))
        for widget in self.right_widgets.values():
            self.right_layout.addWidget(widget)


if __name__ == '__main__':
    test = QApplication(sys.argv)
    test_window = TestWindow(6, 4, 'Test')
    sys.exit(test.exec_())

Ответы [ 2 ]

1 голос
/ 02 марта 2020

Вам необходимо использовать QSplitter .

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

Имейте в виду, что вы можно добавлять только виджеты в QSplitter, а не макеты, поэтому, если вам нужно добавить «раздел» (метку и виджет), который может изменять размеры его содержимого, вам нужно будет создать виджет container с его собственный макет.

Также обратите внимание, что использование словарей для подобных вещей крайне не рекомендуется. Для версий Python старше 3.7 порядок словаря совершенно произвольный, и хотя иногда может быть согласованным (например, когда ключи являются целыми числами), обычно это не так: с вашим кодом несколько раз все метки были собраны вместе, иногда виджеты были перевернуты и т. д. c., поэтому, если кто-то использует вашу программу с <= 3.6, ваш интерфейс не будет согласованным. Учтите, что хотя python 3.6 достигнет конца жизни в 2022 году, возможно, что даже после этого многие люди все еще будут использовать предыдущие версии. <br>Если вам нужен способ группировки объектов, лучше использовать list или кортеж, как я сделал в следующем примере.

Если вам действительно "нужно" , чтобы использовать группу на основе ключей, тогда вы можете использовать OrderedDict , но, скорее всего, что-то не так с логикой c, за которой нужно начинать.

class TestWindow(QMainWindow):
    def __init__(self, left_ratio, right_ratio, window_title):
        super().__init__()
        self.left_ratio = left_ratio
        self.right_ratio = right_ratio
        self.current_image = None
        self.window_title = window_title
        self.setWindowTitle(self.window_title)
        win_rectangle = self.frameGeometry()
        center_point = QDesktopWidget().availableGeometry().center()
        win_rectangle.moveCenter(center_point)
        self.move(win_rectangle.topLeft())
        self.tools = self.addToolBar('Tools')
        self.left_widgets = {'Image': QLabel()}
        self.right_widgets = [(QLabel('List1'), QListWidget()),
                              (QLabel('List2'), QListWidget())]
        self.central_widget = QSplitter(Qt.Horizontal, self)
        self.setCentralWidget(self.central_widget)
        self.right_splitter = QSplitter(Qt.Vertical, self)
        self.adjust_widgets()
        self.central_widget.setStretchFactor(0, left_ratio)
        self.central_widget.setStretchFactor(1, right_ratio)
        self.show()

    def adjust_widgets(self):
        self.central_widget.addWidget(self.left_widgets['Image'])
        self.left_widgets['Image'].setPixmap(QPixmap('test.jpg').scaled(500, 400, Qt.IgnoreAspectRatio,
                                                                        Qt.SmoothTransformation))
        self.left_widgets['Image'].setScaledContents(True)
        self.central_widget.addWidget(self.right_splitter)
        for label, widget in self.right_widgets:
            container = QWidget()
            layout = QVBoxLayout(container)
            layout.addWidget(label)
            layout.addWidget(widget)
            self.right_splitter.addWidget(container)
1 голос
/ 02 марта 2020

Один из способов изменить масштаб изображения до произвольного размера при сохранении его соотношения сторон - это создать подкласс QWidget и переопределить sizeHint и paintEvent и использовать его вместо QLabel для отображения изображения, например,

class PixmapWidget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self._pixmap = None

    def sizeHint(self):
        if self._pixmap:
            return self._pixmap.size()
        else:
            return QSize()

    def setPixmap(self, pixmap):
        self._pixmap = pixmap
        self.update()

    def paintEvent(self, event):
        painter = QPainter(self)
        super().paintEvent(event)
        if self._pixmap:
            size = self._pixmap.size().scaled(self.size(), Qt.KeepAspectRatio)
            offset = (self.size() - size)/2
            rect = QRect(offset.width(), offset.height(), size.width(), size.height())
            painter.drawPixmap(rect, self._pixmap)

Так как вы создаете подклассы QMainWindow, вы можете использовать DockWidget s для отображения списков вместо добавления их в макет центрального виджета, например

class TestWindow(QMainWindow):
    def __init__(self, left_ratio, right_ratio, window_title):
        super().__init__()
        #self.left_ratio = left_ratio    <--- not needed since image and lists
        #self.right_ratio = right_ratio  <--- are not sharing a layout anymore

        ...

        # use PixmapWidget instead of QLabel for showing image
        # refactor dictionary for storing lists to make adding DockWidgets easier
        self.left_widgets = {'Image': PixmapWidget()}
        self.right_widgets = {'List1': QListWidget(),
                              'List2': QListWidget()}
        self.central_widget = QWidget(self)
        # self.main_layout = QHBoxLayout()  <-- not needed anymore
        self.left_layout = QVBoxLayout()

        self.adjust_widgets()
        self.adjust_layouts()
        self.show()

    def adjust_layouts(self):
        self.central_widget.setLayout(self.left_layout)
        self.setCentralWidget(self.central_widget)

    def adjust_widgets(self):
        self.left_layout.addWidget(self.left_widgets['Image'])
        self.left_widgets['Image'].setPixmap(QPixmap('test.jpg').scaled(500, 400, Qt.IgnoreAspectRatio, Qt.SmoothTransformation))

        self.dock_widgets = []
        for text, widget in self.right_widgets.items():
            dock_widget = QDockWidget(text)
            dock_widget.setFeatures(QDockWidget.NoDockWidgetFeatures)
            dock_widget.setWidget(widget)
            self.addDockWidget(Qt.RightDockWidgetArea, dock_widget)
            self.dock_widgets.append(dock_widget)

Скриншоты

image image

...