#python #pyqt5
Вопрос:
Я пытаюсь создать простой графический интерфейс редактора изображений с помощью сетки. Однако я сталкиваюсь с проблемой, когда соотношения между изображением и боковыми панелями не такие, какими я хочу их видеть. В настоящее время мой код является:
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class Window(QMainWindow):
def __init__(self, parent = None):
super().__init__(parent)
self.setWindowTitle("PyEditor")
self.setGeometry(100, 100, 500, 300)
self.centralWidget = QLabel()
self.setCentralWidget(self.centralWidget)
self.gridLayout = QGridLayout(self.centralWidget)
self.createImagePanel()
self.createDrawPanel()
self.createLayerPanel()
def createImagePanel(self):
imageLabel = QLabel(self)
pixmap = QPixmap('amongus.png')
imageLabel.setPixmap(pixmap)
self.gridLayout.addWidget(imageLabel, 0, 0, 3, 4)
def createDrawPanel(self):
drawPanel = QLabel(self)
drawLayout = QVBoxLayout()
drawPanel.setLayout(drawLayout)
tabs = QTabWidget()
filterTab = QWidget()
drawTab = QWidget()
tabs.addTab(filterTab, "Filter")
tabs.addTab(drawTab, "Draw")
drawLayout.addWidget(tabs)
self.gridLayout.addWidget(drawPanel, 0, 4, 1, 1)
def createLayerPanel(self):
layerPanel = QLabel(self)
layerLayout = QVBoxLayout()
layerPanel.setLayout(layerLayout)
tab = QTabWidget()
layerTab = QWidget()
tab.addTab(layerTab, "Layers")
layerLayout.addWidget(tab)
self.gridLayout.addWidget(layerPanel, 1, 4, 1, 1)
if __name__ == "__main__":
app = QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
Это дает мне следующее окно:
Когда я изменяю размер окна, растягиваются только панели фильтра/рисования и слоя, а не панель изображения. Я хочу, чтобы панель изображений также растягивалась и занимала большую часть окна.
Комментарии:
1. Почему вы пытаетесь настроить менеджеры макетов на ярлыках? Qlabel не предназначен для этой цели.
2. Ах, я этого не знал. Должен ли я попробовать вместо этого использовать макеты на виджетах или что-то другое?
3. QLabel- это виджет. QWidget является основой для всех виджетов Qt и может использоваться в качестве контейнера. Другими аналогичными и основными альтернативами являются QFrame или QGroupBox.
Ответ №1:
Хотя теоретически каждый виджет Qt может использоваться в качестве контейнера, некоторые виджеты не следует использовать для такой цели, поскольку их подсказки по размеру, политики размеров и изменение размера имеют различное и специфическое поведение в зависимости от их природы.
QLabel предназначен для отображения виджета, а не контейнера. Все, что связано с его размером, основано на содержимом (текст, изображение или анимация), поэтому возможный набор макетов для него не будет иметь никакого отношения к размеру, а также создаст некоторые несоответствия в отображении виджетов, добавленных в этот макет.
Если требуется базовый контейнер, то базовый QWidget является наиболее логичным выбором.
Затем, если растяжение также является обязательным требованием, его следует применять с использованием коэффициентов растяжения виджета или макета. Для QGridLayout это достигается с помощью setColumnStretch()
или setRowStretch()
.
Попытка использовать диапазон строк или столбцов не подходит для этой цели, так как охват только указывает, сколько «ячеек» сетки будет использоваться определенным элементом макета, что имеет смысл только тогда, когда есть виджеты, которые должны занимать более одной «ячейки», точно так же, как охват таблицы.
Таким образом, для достижения желаемого поведения требуются следующие изменения:
- измените все QLabel на QWidget (очевидно, за исключением метки, на которой показано изображение).;
- используйте правильные промежутки строк/столбцов;
imageLabel
они должны быть добавлены только с одним промежутком столбцов (если не требуется иное).:self.gridLayout.addWidget(imageLabel, 0, 0, 3, 1, alignment=Qt.AlignCenter)
- установите длину столбца (не менее) 1 для первого столбца:
self.gridLayout.setColumnStretch(0, 1)
- если вы хотите, чтобы изображение было выровнено по центру в доступном пространстве, установите выравнивание на виджете (не при добавлении его в макет).:
imageLabel = QLabel(self, alignment=Qt.AlignCenter)
Обратите внимание, что все вышеперечисленное не будет масштабировать изображение всякий раз, когда доступный размер будет больше, чем у изображения. Хотя вы можете установить scaledContents
True
значение «равно», в результате изображение будет растянуто, чтобы заполнить все доступное пространство, и, к сожалению, QLabel не обеспечивает возможность сохранения соотношения сторон. Если вам это нужно, то обычно проще подклассировать QWidget и обеспечить надлежащую реализацию подсказки размера и события рисования.
class ImageViewer(QWidget):
_pixmap = None
def __init__(self, pixmap=None, parent=None):
super().__init__(parent)
self.setPixmap(pixmap)
def setPixmap(self, pixmap):
if self._pixmap != pixmap:
self._pixmap = pixmap
self.updateGeometry()
def sizeHint(self):
if self._pixmap and not self._pixmap.isNull():
return self._pixmap.size()
return super().sizeHint()
def paintEvent(self, event):
if self._pixmap and not self._pixmap.isNull():
qp = QPainter(self)
scaled = self._pixmap.scaled(self.width(), self.height(),
Qt.KeepAspectRatio, Qt.SmoothTransformation)
rect = scaled.rect()
rect.moveCenter(self.rect().center())
qp.drawPixmap(rect, scaled)