How to modify this current setup to enable resizing(horizontally and vertically) between the layouts shown below? Let\'s say I want to resize the lists in the right toward the l
You need to use QSplitter.
It acts almost like a box layout, but has handles that allow the resizing of each item.
Be aware that you can only add widgets to a QSplitter, not layouts, so if you need to add a "section" (a label and a widget) that can resize its contents, you'll have to create a container widget with its own layout.
Also note that using dictionaries for these kind of things is highly discouraged. For versions of Python older than 3.7, dictionary order is completely arbitrary, and while sometimes it might be consistent (for example, when keys are integers), it usually isn't: with your code some times the labels were put all together, sometimes the widgets were inverted, etc., so if somebody is using your program with <=3.6 your interface won't be consistent. Consider that, while python 3.6 will reach end of life in 2022, it's possible that even after that a lot of people will still be using previous versions.
If you need a way to group objects, it's better to use a list or a tuple, as I did in the following example.
If you really "need" to use a key based group, then you can use OrderedDict, but it's most likely that there's just something wrong with the logic behind that need to begin with.
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)
One way to rescale the image to an arbitrary size while maintaining its aspect ratio is to subclass QWidget
and override sizeHint
and paintEvent
and use that instead of a QLabel
for displaying the image, e.g.
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)
Since you are subclassing QMainWindow
you could use DockWidget
s to display the lists instead of adding them to the layout of the central widget, e.g.
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)
Screenshots