Почему неправильно отображается QScrollArea?(PyQt5, Python3)
У меня есть код, который я оставлю ниже.
Класс Label принимает путь к изображению и закругляет его края. Из-за некоторых обстоятельств буду использовать его экземпляры вместо кнопок.
В классе MyWindow я создаю два QGridLayout'а - box1 и box3 и один QVBoxLayout - box2:
- В
box2добавляю кнопкуbutton. - Создаю QScrollArea(
scrollArea) и привязываю ее кbox3 box3наполняю двумя виджетами QLabel, которые получаю из классаLabel.box2иscrollAreaпомещаю в box1.
Все это может показаться лишними, но мне действительно нужно такое количество контейнеров. Этого не будет видно в оставленном мною коде, т.к. перед созданием вопроса я пытаюсь упростить ситуацию, чтобы было проще искать ошибки.
Сейчас у меня есть минимум две проблемы.
Первая проблема:
Почему-то QScrollArea отказывается принимать нормальные размеры. Даже если растянусь окно на весь экран, элементы box3(а их всего два) не будут видны полностью. Полосы прокрутки остаются на своих местах, хотя виджетам хватило бы места.
Если добавить третий QLabel:
Вторая проблема:
Я пытаюсь применить метод setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) к scrollArea. Но, почему-то это работает совсем не так, как мне хотелось - пропадают обе полосы прокрутки(горизонтальная и вертикальная). Я не знаю, в чем дело.
Пожалуйста, подскажите, как мне починить код?
from PyQt5 import QtCore, QtWidgets, QtGui
class Label(QtWidgets.QLabel):
clicked = QtCore.pyqtSignal()
def __init__(self, picture, *args, **kwargs):
super(Label, self).__init__(*args, **kwargs)
self.setMaximumSize(140, 140)
self.setMinimumSize(140, 140)
self.radius = 10
self.target = QtGui.QPixmap(self.size())
self.target.fill(QtCore.Qt.transparent)
p = QtGui.QPixmap(picture).scaled(140, 140, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(self.target)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
path = QtGui.QPainterPath()
path.addRoundedRect(0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(self.target)
def mouseReleaseEvent(self, event):
self.clicked.emit()
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.button = QtWidgets.QPushButton('Button')
self.button.setFixedSize(60, 60)
self.label1 = Label('picture1.png')
self.label1.clicked.connect(self.click)
self.label2 = Label('picture1.png')
self.new_button = QtWidgets.QPushButton('New Button')
self.box2 = QtWidgets.QVBoxLayout() # QVBoxLayout
self.box2.addWidget(self.button, alignment=QtCore.Qt.AlignRight)
scrollArea = QtWidgets.QScrollArea()
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff) #<--- ПРИВОДИТ К НЕПРАВИЛЬНОМУ ОТОБРАЖЕНИЮ
content_widget = QtWidgets.QWidget()
scrollArea.setWidget(content_widget)
scrollArea.setWidgetResizable(True)
self.box3 = QtWidgets.QGridLayout(content_widget) # QGridLayout
self.box3.setSpacing(200)
self.box3.addWidget(self.label1, 0, 0)
self.box3.addWidget(self.label2, 0, 1)
self.box1 = QtWidgets.QGridLayout(self) # QGridLayout
self.box1.addWidget(scrollArea, 0, 0, 1, 1, QtCore.Qt.AlignCenter)
self.box1.setColumnStretch(0, 1)
self.box1.addLayout(self.box2, 0, 1)
def click(self):
for row in range(self.box3.rowCount()):
for col in range(self.box3.columnCount()):
w = self.box3.itemAtPosition(row, col).widget()
w.deleteLater()
self.box3.addWidget(self.new_button, 0, 0, 1, 1, QtCore.Qt.AlignCenter)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())
UPD: Я хочу, чтобы контейнер QGridLayout в QScrollArea занимал все свободное пространство окна, которое не занимает вертикальный контейнер box2. Еще на картинке виджеты контейнера box3 перескакивают на другую строчку, если им не хватает места. Понимаю, что наглею, но, если это будет не трудно, расскажите, как можно добиться такого?
Чтобы было понятнее нарисовал схему:
Ответы (1 шт):
То, что вы хотите сделать - Резиновая лента.
для этого нам нужен - class ListWidget(QListWidget):.
также посмотрите в class MyWindow(QtWidgets.QWidget): где задействована self.listWidget
Нажимайте на кнопку Button, изменяйте размер окна.
from PyQt5 import QtCore, QtWidgets, QtGui
from PyQt5.Qt import *
class ListWidget(QListWidget):
def __init__(self, *args, **kwargs):
super(ListWidget, self).__init__(*args, **kwargs)
self.setWindowTitle('ListWidget')
self.resize(520, 400)
# Скрыть горизонтальную полосу прокрутки
self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
# Невозможно отредактировать
self.setEditTriggers(self.NoEditTriggers)
self.setDefaultDropAction(Qt.IgnoreAction)
self.setSelectionMode(self.ContiguousSelection)
# Установите слева направо, оберните и упорядочьте по порядку
self.setFlow(self.LeftToRight)
self.setWrapping(True)
self.setResizeMode(self.Adjust)
# Интервал позиций
self.setSpacing(10)
# Резиновая лента (для эффекта выбора рамки)
self._rubberPos = None
self._rubberBand = QRubberBand(QRubberBand.Rectangle, self)
def makeItem(self, lb):
item = QListWidgetItem(self)
item.setSizeHint(QSize(140, 140))
self.setItemWidget(item, lb)
class Label(QtWidgets.QLabel):
clicked = QtCore.pyqtSignal()
def __init__(self, picture, *args, **kwargs):
super(Label, self).__init__(*args, **kwargs)
self.setMaximumSize(140, 140)
self.setMinimumSize(140, 140)
self.radius = 10
self.target = QtGui.QPixmap(self.size())
self.target.fill(QtCore.Qt.transparent)
p = QtGui.QPixmap(picture).scaled(140, 140, QtCore.Qt.KeepAspectRatioByExpanding, QtCore.Qt.SmoothTransformation)
painter = QtGui.QPainter(self.target)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
path = QtGui.QPainterPath()
path.addRoundedRect(0, 0, self.width(), self.height(), self.radius, self.radius)
painter.setClipPath(path)
painter.drawPixmap(0, 0, p)
self.setPixmap(self.target)
def mouseReleaseEvent(self, event):
self.clicked.emit()
class MyWindow(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.button = QtWidgets.QPushButton('Button', clicked=self.onButton)
self.button.setFixedSize(60, 60)
self.listWidget = ListWidget() # +++
self.label1 = Label('head3.png')
self.listWidget.makeItem(self.label1) # +++ ...
self.label1.clicked.connect(self.click)
self.label2 = Label('Ok.png')
self.listWidget.makeItem(self.label2)
self.label3 = Label('head3.png')
self.listWidget.makeItem(self.label3)
self.new_button = QtWidgets.QPushButton('New Button')
self.box2 = QtWidgets.QVBoxLayout()
self.box2.addWidget(self.button, alignment=QtCore.Qt.AlignRight)
self.box1 = QtWidgets.QGridLayout(self)
self.box1.addWidget(self.listWidget, 0, 0) # +++
self.box1.setColumnStretch(0, 1)
self.box1.addLayout(self.box2, 0, 1)
def click(self):
self.listWidget.hide()
self.box1.addWidget(self.new_button, 0, 0, 1, 1, QtCore.Qt.AlignCenter)
self.new_button.show()
def onButton(self):
self.new_button.hide()
self.listWidget.show()
label = Label('im.png')
self.listWidget.makeItem(label)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle('Резиновая лента')
window.show()
sys.exit(app.exec_())





