Код работает не так, как я планировал(Python3, PyQt5)
Ниже оставлю код, в котором есть три класса - ListWidget, Label и MyWindow. ListWidget создает резиновую ленту, а Label создает виджет QLabel с закругленным изображением. На эти классы не стоит обращать внимания, они точно правильно выполняют свои функции. Проблема(проблемы) в классе MyWindow.
- Тут я создаю кнопку
simple_btn, которая потом попадает в вертикальный контейнерbox2. Пока она не выполняет и не должна выполнять никаких функций. - Создаю
listWidget- копию классаListWidget, который наполняю виджетами QLable, полученными из классаLabel. - Создаю
scrollArea(QScrollArea), но пока нигде не размещаю. - Создаю QGridLayout -
box1, куда первым виджетом(0, 0) добавляюlistWidget. - К виджету
label1привязываю метод классаMyWindow-click(), который с помощьюhide()скрываетlistWidgetи создает привязанный кscrollAreaконтейнер QGridLayout -box3, если он еще не был создан.box3наполняется кнопками. В вертикальный контейнерbox2попадает кнопкаback_btn. - К кнопке
back_btnпривязваю методonButton. Этот метод должен удалять все виджеты контейнераbox3, скрыватьscrollAreaс помощьюhide()и делать обратно видимымlistWidgetс помощьюshow().
К сожалению, все это работает совсем не так, как я себе представлял:
- Клик на
label1действительно скрываетlistWidget. Но виджеты, которыми должен наполнитьсяbox3, не появляются в окне:
- Если вернуться кнопкой
back_btnк исходному состоянию окна и попробовать сделать еще один клик наlabel1, произойдет что-то странное. Как я понял,scrollAreaоткрывается в новом окне:
Пожалуйста, подскажите, как мне починить код?
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(self.click)
self.label2 = Label('picture1.png')
self.listWidget.makeItem(self.label2)
self.label3 = Label('picture1.png')
self.listWidget.makeItem(self.label3)
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):
self.listWidget.hide()
if not hasattr(self, 'box3'):
self.box3 = QtWidgets.QGridLayout(self.content_widget)
else:
self.scrollArea.show()
for n in range(1, 17):
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()):
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 шт):
Любой виджет Qt, является окном, если у него нет родителя.
Когда виджету указывается родитель (обычно это в конструкторе указывается или через метод setParent), то содержимое виджета разместится на родителе.
Кст, если виджет располагается на компоновщике, то автоматически у него указывается родитель (поэтому у меня вызывает недоумение, когда вижу код с использованием компоновщиков и принудительной установкой родителя типа: ... = QLabel("...", self)).
Поэтому, self.scrollArea появляется как окно, т.к. не была добавлена на форму. Хоть ее и создали, но у нее не было родителя, а виджет по умолчанию скрыт.. Т.е. ее нужно на какой-нибудь компоновщик добавить и скрыть в конструкторе MyWindow или добавлять на форму в def click(self):

