С чем может быть связано нестабильное поведение QListWidget?(Python3, PyQt5)
Я только что задавал вопрос касательно кода ниже. Но теперь у меня появилась еще одна проблема.
У меня есть три класса - ListWidget, Label и MyWindow. ListWidget создает резиновую ленту, а Label создает виджет QLabel с закругленным изображением. На эти классы не стоит обращать внимания, они точно правильно выполняют свои функции. Проблема(проблемы) в классе MyWindow.
- Тут я создаю кнопку
simple_btn, которая потом попадает в вертикальный контейнерbox2. Пока она не выполняет и не должна выполнять никаких функций. - Создаю
listWidget- копию классаListWidget, который наполняю виджетами QLable(label1,label2,label3), полученными из классаLabel. - Создаю
scrollArea(QScrollArea), но пока нигде не размещаю. - Создаю QGridLayout -
box1, куда первым виджетом(0, 0) добавляюlistWidget. - К виджетам
label1,label2иlabel3привязываю метод классаMyWindow-click()(при этом передаю этому методу аргументnum), который с помощьюhide()скрываетlistWidgetи создает привязанный кscrollAreaконтейнер QGridLayout -box3, если он еще не был создан.box3наполняется кнопками, число которых зависит от аргументаnum. В вертикальный контейнерbox2попадает кнопкаback_btn. - К кнопке
back_btnпривязваю методonButton. Этот метод должен удалять все виджеты контейнераbox3, скрыватьscrollAreaс помощьюhide()и делать обратно видимымlistWidgetс помощьюshow().
В чем проблема:
Если выполнить некоторую комбинацию действий несколько раз(нажать на какой-нибудь из виджетов QLabel, а потом вернуться обратно кнопкой back_btn), часто listWidget перестает нормально работать. Виджеты внутри него перестают менять свое пололожение в зависимости от размера окна. Это происходит достаточно спонтанно(чаще всего при нажатии на label3) и я не могу объяснить, что именно вызывает проблему. На другом компьютере происходит то же самое.

Вот правильное отображение виджетов:
Баг происходит при любом положении виджетов:
Честно говоря, я очень огорчен этим, и мне очень нужна помощь. Не могу представить, как это можно загуглить, куда копать. Пожалуйста, подскажите, что может приводить к этой ошибке?
from PyQt5 import QtCore, QtWidgets, QtGui
class ListWidget(QtWidgets.QListWidget):
def __init__(self, *args, **kwargs):
super(ListWidget, self).__init__(*args, **kwargs)
#self.setWindowTitle('ListWidget')
#self.setStyleSheet('border-style: hidden;')
self.resize(520, 400)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setEditTriggers(self.NoEditTriggers)
self.setDefaultDropAction(QtCore.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 = None #QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle, self)
def makeItem(self, lb):
item = QtWidgets.QListWidgetItem(self)
item.setSizeHint(QtCore.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.simple_btn = QtWidgets.QPushButton('Button')
self.simple_btn.setFixedSize(100, 60)
self.listWidget = ListWidget()
self.scrollArea = QtWidgets.QScrollArea()
self.content_widget = QtWidgets.QWidget()
self.scrollArea.setWidget(self.content_widget)
self.scrollArea.setWidgetResizable(True)
self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.label1 = Label('picture1.png')
self.listWidget.makeItem(self.label1)
self.label1.clicked.connect(lambda num=2: self.click(num))
self.label2 = Label('picture1.png')
self.listWidget.makeItem(self.label2)
self.label2.clicked.connect(lambda num=3: self.click(num))
self.label3 = Label('picture1.png')
self.listWidget.makeItem(self.label3)
self.label3.clicked.connect(lambda num=4: self.click(num))
self.box2 = QtWidgets.QVBoxLayout()
self.box2.addWidget(self.simple_btn, 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, num):
self.listWidget.hide()
if not hasattr(self, 'box3'):
self.box1.addWidget(self.scrollArea, 0, 0)
self.box3 = QtWidgets.QGridLayout(self.content_widget)
else:
self.scrollArea.show()
for n in range(1, num):
btn = QtWidgets.QPushButton(f'Button{n}')
self.box3.addWidget(btn, n-1, 0)
self.back_btn = QtWidgets.QPushButton('Back', clicked=self.onButton)
self.back_btn.setFixedSize(100, 60)
self.box2.addWidget(self.back_btn, alignment=QtCore.Qt.AlignRight)
def onButton(self):
self.back_btn.deleteLater()
col = 0
for row in range(self.box3.rowCount()):
if self.box3.itemAtPosition(row, col) is not None:
w = self.box3.itemAtPosition(row, col).widget()
w.deleteLater()
self.scrollArea.hide()
self.listWidget.show()
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())
Ответы (1 шт):
я переписал только class MyWindow и отметил основные изменения.
Пробуйте.
from PyQt5 import QtCore, QtWidgets, QtGui
class ListWidget(QtWidgets.QListWidget):
def __init__(self, *args, **kwargs):
super(ListWidget, self).__init__(*args, **kwargs)
#self.setWindowTitle('ListWidget')
#self.setStyleSheet('border-style: hidden;')
self.resize(520, 400)
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setEditTriggers(self.NoEditTriggers)
self.setDefaultDropAction(QtCore.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 = None #QtWidgets.QRubberBand(QtWidgets.QRubberBand.Rectangle, self)
def makeItem(self, lb):
item = QtWidgets.QListWidgetItem(self)
item.setSizeHint(QtCore.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.setMinimumSize(310, 190) # +
self.simple_btn = QtWidgets.QPushButton('Button')
self.simple_btn.setFixedSize(100, 60)
listWidget = ListWidget() # +
self._listLabel = [] # +!!!
self.label1 = Label('head3.png')
self.label1.clicked.connect(lambda num=2: self.click(num))
self._listLabel.append(self.label1)
self.label2 = Label('Ok.png')
self.label2.clicked.connect(lambda num=3: self.click(num))
self._listLabel.append(self.label2)
self.label3 = Label('im.png')
self.label3.clicked.connect(lambda num=4: self.click(num))
self._listLabel.append(self.label3)
for lb in self._listLabel:
listWidget.makeItem(lb)
self.back_btn = QtWidgets.QPushButton('Back', clicked=self.onButton) # +!!!
self.back_btn.setFixedSize(100, 60)
self.box2 = QtWidgets.QVBoxLayout()
self.box2.addWidget(self.simple_btn, alignment=QtCore.Qt.AlignRight)
self.box2.addWidget(self.back_btn, alignment=QtCore.Qt.AlignRight) # +++
self.back_btn.hide() # +++
self.box1 = QtWidgets.QGridLayout(self)
self.box1.addWidget(listWidget, 0, 0)
self.box1.setColumnStretch(0, 1)
self.box1.addLayout(self.box2, 0, 1)
def click(self, num):
scrollArea = QtWidgets.QScrollArea()
content_widget = QtWidgets.QWidget()
scrollArea.setWidget(content_widget)
scrollArea.setWidgetResizable(True)
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
box3 = QtWidgets.QGridLayout(content_widget)
self.box1.addWidget(scrollArea, 0, 0)
for n in range(1, num):
btn = QtWidgets.QPushButton(f'Button{n}')
box3.addWidget(btn, n-1, 0)
self.back_btn.show()
def onButton(self):
self.back_btn.hide()
listWidget = ListWidget()
for lb in self._listLabel:
listWidget.makeItem(lb)
self.box1.addWidget(listWidget, 0, 0)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
window = MyWindow()
window.setWindowTitle(' ')
window.show()
sys.exit(app.exec_())





