PyQt5: Qstyle.CC_ScrollBar rendered in the wrong place - python-3.x

I am working with a listView and a custom delegate. Through the paint function I draw a set of control elements so that each row of the list acts as if it was a widget, without actually being one. This is crucial for performance since the list is composed of hundreds of thousands of elements, as pointed here and here.
The only problem is with QStyleOptionSlider complex control: if I ask for a CC.ScrollBar the control is rendered in the top left corner of the view and not where i want. If in QApplication.style().drawComplexControl(QStyle.CC_ScrollBar, self.scrollOptions, painter) i ask for a CC_Slider (instead of CC_ScrollBar) the control is rendered where expected.
I also tried to initialise the style from a real scroll widget but nothing changed.
I would like to know if I'm doing something wrong or if it's a problem with the library, since all the other controls i have painted work perfectly. The only difference I've noticed is that other elements (e.g. frame, label, pushbutton) have their own QStyleOption class while the scrollbar is merged with the slider class, but to quote the docs:
QStyleOptionSlider contains all the information that QStyle functions need to draw QSlider and QScrollBar.
Debug Info: Python 3.8.6 / PyQt 5.15.1 / Pyqt-tools 5.15.1.2 / Windows 10
Minimal example
from PyQt5.QtCore import QSize, Qt, QRect
from PyQt5.QtGui import QColor
from PyQt5.QtGui import QStandardItem
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QStyle
from PyQt5.QtWidgets import QStyledItemDelegate, QApplication, QStyleOptionFrame, \
QStyleOptionSlider
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.inferenceListView = QtWidgets.QListView(self.centralwidget)
self.inferenceListView.setGridSize(QtCore.QSize(0, 200))
self.inferenceListView.setObjectName("inferenceListView")
self.gridLayout.addWidget(self.inferenceListView, 0, 1, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 21))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.setupProposals()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
def setupProposals(self):
self.delegate = MyDelegate()
# self.delegate.initScroll(self.horizontalScrollBar)
model = QStandardItemModel(0, 0)
for index in range(0, 5000):
model.appendRow(QStandardItem(str(index)))
self.inferenceListView.setItemDelegateForRow(index, self.delegate)
self.inferenceListView.setModel(model)
class MyDelegate(QStyledItemDelegate):
def __init__(self, parent=None):
QStyledItemDelegate.__init__(self, parent)
self.frame = QStyleOptionFrame()
# ---------------
self.scrollOptions = QStyleOptionSlider()
self.scrollOptions.orientation = Qt.Vertical
self.scrollOptions.LayoutDirectionAuto = Qt.LayoutDirectionAuto
self.scrollOptions.orientation = Qt.Vertical
self.scrollOptions.state = QStyle.State_Enabled
self.scrollOptions.maximum = 10
self.scrollOptions.minimum = 0
self.scrollOptions.sliderValue = 0
def initScroll(self, scroll):
self.scrollOptions.initFrom(scroll)
def sizeHint(self, option, index):
return QSize(150, 200)
def paint(self, painter, option, index):
optX = option.rect.x()
optY = option.rect.y()
optH = option.rect.height()
optW = option.rect.width()
painter.fillRect(option.rect, QColor(100, 100, 100, 100))
painter.drawLine(optX, optY + optH, optX + optW, optY + optH)
QApplication.style().drawControl(QStyle.CE_ShapedFrame, self.frame, painter)
self.scrollOptions.rect = QRect(optX + 100, optY + 100, 50, 80)
# OK WITH CC_SLIDER
#QApplication.style().drawComplexControl(QStyle.CC_Slider, self.scrollOptions, painter)
# WRONG PLACE WITH CC_SCROLLBAR
QApplication.style().drawComplexControl(QStyle.CC_ScrollBar, self.scrollOptions, painter)
def editorEvent(self, event, model, option, index):
return False
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
EDIT
Seems to be a Windows-related problem at the moment. I had a colleague with a Mac run the code above and the scrollbar is drawn in the correct place. I attach an image of what happens on Windows in the two cases:

It seems like a possibly incomplete implementation of subControlRect in QCommonStyle, as the rectangle returned for CC_Slider is always positioned on the top left (see source).
A possible solution can be to use a proxy style and return a translated rectangle if the subrect is not contained in the option rect:
class ProxyStyle(QtWidgets.QProxyStyle):
def subControlRect(self, cc, opt, sc, widget=None):
r = super().subControlRect(cc, opt, sc, widget)
if cc == self.CC_ScrollBar and not opt.rect.contains(r):
r.translate(opt.rect.topLeft())
return r
# ...
app = QtWidgets.QApplication(sys.argv)
app.setStyle(ProxyStyle())

Related

How to make Layout use the full size of it's parent Window in PySide6? [duplicate]

This question already has answers here:
How to make a Qt Widget grow with the window size?
(4 answers)
Closed last month.
I generated a simple UI in Qt6 Designer consisting of a QGridLayout on a QDialog (or QMainWindow - the problem seems to be the same).
Now I would like this layout to fill the full size of the window and to resize itself whenever the window size is changed.
How can I achieve this?
Here is my example application with the code generated from Qt Designer and a little bit of my own code to make it run:
import sys
from PySide6.QtCore import QRect, QCoreApplication, QMetaObject
from PySide6.QtWidgets import QApplication, QWidget, QGridLayout, QLabel, QLineEdit, QSizePolicy
class Ui_Dialog():
def setupUi(self, Dialog):
if not Dialog.objectName():
Dialog.setObjectName(u"Dialog")
Dialog.resize(400, 300)
self.gridLayoutWidget = QWidget(Dialog)
self.gridLayoutWidget.setObjectName(u"gridLayoutWidget")
self.gridLayoutWidget.setGeometry(QRect(10, 20, 341, 191))
self.gridLayout = QGridLayout(self.gridLayoutWidget)
self.gridLayout.setObjectName(u"gridLayout")
self.gridLayout.setContentsMargins(0, 0, 0, 0)
self.label = QLabel(self.gridLayoutWidget)
self.label.setObjectName(u"label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.label_2 = QLabel(self.gridLayoutWidget)
self.label_2.setObjectName(u"label_2")
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
self.lineEdit = QLineEdit(self.gridLayoutWidget)
self.lineEdit.setObjectName(u"lineEdit")
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
self.lineEdit.setSizePolicy(sizePolicy)
self.gridLayout.addWidget(self.lineEdit, 0, 1, 1, 1)
self.lineEdit_2 = QLineEdit(self.gridLayoutWidget)
self.lineEdit_2.setObjectName(u"lineEdit_2")
sizePolicy.setHeightForWidth(self.lineEdit_2.sizePolicy().hasHeightForWidth())
self.lineEdit_2.setSizePolicy(sizePolicy)
self.gridLayout.addWidget(self.lineEdit_2, 1, 1, 1, 1)
self.gridLayout.setColumnStretch(1, 1)
self.retranslateUi(Dialog)
QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
Dialog.setWindowTitle(QCoreApplication.translate("Dialog", u"Dialog", None))
self.label.setText(QCoreApplication.translate("Dialog", u"TextLabel", None))
self.label_2.setText(QCoreApplication.translate("Dialog", u"TextLabel", None))
class MyMainWindow(QWidget, Ui_Dialog):
def __init__(self, *args, obj=None, **kwargs):
super().__init__(*args, **kwargs)
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = MyMainWindow()
w.show()
app.exec()
The documentation states
QGridLayout takes the space made available to it (by its parent layout or by the parentWidget()), ...
So I think the question boils down to "How do I tell the QDialog or QMainWindow to make all it's space available to one QLayout?
You need to set the layout on QDialog for it to occupy the entire space. Add the following to your Ui_Dialog() setupUi method to get this behavior.
self.gridLayout.setContentsMargins(5, 5, 5, 5)
self.setLayout(self.gridLayout)
And the output is:

Keeping track of a button status inside a thread (PyQt5)

I created this simple GUI that displays a conuter on a text box. I am using workers and threads (this is just a simplified program I have other threads). I want to be able to check the status of the push button inside the label update thread. for example if the user clicked, then the counter will increment by 5 instead of 1 (for this iteration only), basically I want to keep an eye on this button's status all the time.
here is my code for the counter, how do I add the button check functionality to it?
Edit: I've updated the code using signals and slots to print 'hi' as a start, yet I do not get any output when I run it.
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import os
import cv2
import numpy as np
import time
############################# Telemtry widgets update ##########################
class DISPLAY(QObject):
acc1_val = pyqtSignal(int)
finished = pyqtSignal()
def run(self):
global cntr
cntr = 0
self.inst = Ui_MainWindow()
self.inst.flag.connect(self.update)
print('connected')
while 1:
cntr = cntr +1
time.sleep(1)
self.acc1_val.emit(cntr)
if(cntr > 50):
cntr = 0
self.finished.emit()
#pyqtSlot()
def update(self,flag):
print('hi')
print(flag)
############################ GUI #######################################
class Ui_MainWindow(QObject):
flag = pyqtSignal(int)
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(500, 500)
MainWindow.setFocusPolicy(QtCore.Qt.NoFocus)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.Title = QtWidgets.QLabel(self.centralwidget)
self.Title.setGeometry(QtCore.QRect(30, 10, 421, 71))
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
font.setWeight(75)
self.Title.setFont(font)
self.Title.setObjectName("Title")
self.ACC1_X = QtWidgets.QLineEdit(self.centralwidget)
self.ACC1_X.setGeometry(QtCore.QRect(300, 300, 41, 31))
self.ACC1_X.setObjectName("ACC1_X")
self.btn = QtWidgets.QPushButton(self.centralwidget)
self.btn.setGeometry(QtCore.QRect(100, 100, 101, 41))
font = QtGui.QFont()
font.setPointSize(13)
self.btn.setFont(font)
self.btn.setObjectName("Release_btn")
self.btn.clicked.connect(self.release_callback)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1920, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
###################### Display thread ######################
self.thread1 = QThread()
self.worker1 = DISPLAY()
self.worker1.moveToThread(self.thread1)
self.thread1.started.connect(self.worker1.run)
self.worker1.acc1_val.connect(self.Label_update)
self.thread1.finished.connect(self.worker1.deleteLater)
self.thread1.start()
def release_callback(self,flag):
self.x = 1
print(flag)
self.flag.emit(True)
def Label_update(self,acc_val):
self.ACC1_X.setText(str(acc_val))
#print(str(acc_val))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.btn.setText(_translate("MainWindow", "click me"))
self.Title.setText(_translate("MainWindow", "TEST"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())

Set scroll area initially moved

I need to create a big widget inside a scroll area and initially set both sliders in the middle of the bar. The scroll bar does not work, the widgets are not well connected I think.
MRE:
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget
import sys
class Diedrico(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
# Draws stuff
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
ventana.resize(1500, 1015)
ventana.setFixedSize(1500, 1015)
self.widget_central = QtWidgets.QWidget(ventana)
scrol = QtWidgets.QScrollArea(self.widget_central)
scrol.setWidgetResizable(True)
scrol.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
scrol.setGeometry(QtCore.QRect(1010, 510, 470, 460))
self.Diedrico = Diedrico(scrol)
self.Diedrico.setGeometry(QtCore.QRect(0, 0, 1000, 1000))
# This widget should be big enough to use the scroll bar, but it does not work
ventana.setCentralWidget(self.widget_central)
ventana.show()
if __name__ == "__main__":
app = QtWidgets.QApplication([])
ventana = QtWidgets.QMainWindow()
ui = UiVentana()
sys.exit(app.exec_())
It seems that the problem comes from scrol.setWidgetResizable(True), which seems to resize the content... setting this to False worked for me.
Also, to center the scrollbar, there are a few options, like setting the value of the verticalScrollBar or using ensureVisible(x, y).
A working solution:
from PyQt5 import QtCore, QtWidgets
import sys
class UiVentana(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(UiVentana, self).__init__(parent)
self.setupUi()
self.label.setGeometry(QtCore.QRect(10, 0, 282, 331))
self.label.setText("this is a long text\n" * 100)
self.scrollArea.verticalScrollBar().setValue(300)
def setupUi(self):
self.resize(800, 600)
self.centralwidget = QtWidgets.QWidget(self)
self.scrollArea = QtWidgets.QScrollArea(self.centralwidget)
self.scrollArea.setGeometry(QtCore.QRect(470, 330, 301, 211))
self.scrollArea.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOn)
self.scrollArea.setWidgetResizable(False)
self.scrollAreaWidgetContents = QtWidgets.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 282, 10000))
self.label = QtWidgets.QLabel(self.scrollAreaWidgetContents)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.setCentralWidget(self.centralwidget)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ui = UiVentana()
ui.show()
sys.exit(app.exec_())

How to remove all widgets within a QGroupBox in PyQt5?

In my program there is a QGroupBox displayed that has many QPushButton's within it. During the execution of the program, the user can click a button outside of the QGroupBox and all of the buttons within it will be removed or hidden. Problem is that I can't seem to find a way to do this to the buttons directly or by clearing the QGroupBox.
I have already tried deleteLater on the buttons but that didn't work. I then tried clearing the layout of the QGroupBox but that didn't work either. Here is some code I just wrote up that has a the same problem:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import random
class UI_Dialog(object):
def addButtons(self,looping):
# Code to remove the previous QPushButton's goes here.
placement = -100
for i in range(looping):
currentName = 'btn' + str(i)
placement = placement + 110
self.btnB = QtWidgets.QPushButton(self.groupBox)
self.btnB.setGeometry(QtCore.QRect(10+placement, 30+placement, 100, 100))
self.btnB.show()
self.btnB.setObjectName(currentName)
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1300, 800)
self.btnA = QtWidgets.QPushButton(Dialog)
self.btnA.setGeometry(QtCore.QRect(10, 80, 101, 131))
self.btnA.setObjectName("btn1")
self.btnA.clicked.connect(self.pushed)
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox("Results")
self.groupBox.setLayout(self.formLayout)
self.resultScrollArea = QtWidgets.QScrollArea(Dialog)
self.resultScrollArea.setWidget(self.groupBox)
self.resultScrollArea.setGeometry(QtCore.QRect(20, 220, 1011, 531))
self.resultScrollArea.setWidgetResizable(True)
self.resultScrollArea.setObjectName("resultScrollArea")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def pushed(self):
unkownLength = random.randint(1,20)
self.addButtons(unkownLength)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Example Program"))
self.btnA.setText(_translate("Dialog", "Push Button"))
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = UI_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
There are things here that probably don't make sense like the window size, the multiple function calls or it being a Dialog window instead of a QMainWindow. However, in the context of the actual program they do make sense so just ignore that, I know it's inefficient. Also the whole point of the unkownLength variable is to emulate that in the actual program, the number of buttons generated will be determined by user input. The buttons must also not be there at the start so that is why they're created with a button click. When the button is clicked again it should remove or hide all the buttons it created before. Any ideas?
Taking advantage that the buttons are children of the QGroupBox we can get the buttons using findChildren() to use deleteLater():
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import random
class UI_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(1300, 800)
self.btnA = QtWidgets.QPushButton(Dialog)
self.btnA.setGeometry(QtCore.QRect(10, 80, 101, 131))
self.btnA.setObjectName("btn1")
self.formLayout = QtWidgets.QFormLayout()
self.groupBox = QtWidgets.QGroupBox("Results")
self.groupBox.setLayout(self.formLayout)
self.resultScrollArea = QtWidgets.QScrollArea(Dialog)
self.resultScrollArea.setWidget(self.groupBox)
self.resultScrollArea.setGeometry(QtCore.QRect(20, 220, 1011, 531))
self.resultScrollArea.setWidgetResizable(True)
self.resultScrollArea.setObjectName("resultScrollArea")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Example Program"))
self.btnA.setText(_translate("Dialog", "Push Button"))
class Dialog(QtWidgets.QDialog, UI_Dialog):
def __init__(self, parent=None):
super(Dialog, self).__init__(parent)
self.setupUi(self)
self.btnA.clicked.connect(self.pushed)
#QtCore.pyqtSlot()
def pushed(self):
unkownLength = random.randint(1, 20)
self.addButtons(unkownLength)
def addButtons(self, looping):
for button in self.groupBox.findChildren(QtWidgets.QPushButton):
button.deleteLater()
placement = -100
pos = QtCore.QPoint(20, 40)
for i in range(looping):
currentName = "btn" + str(i)
self.btnB = QtWidgets.QPushButton(
self.groupBox, objectName=currentName
)
self.btnB.setGeometry(QtCore.QRect(pos, QtCore.QSize(100, 100)))
pos += QtCore.QPoint(110, 110)
self.btnB.show()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Dialog()
w.show()
sys.exit(app.exec_())

Pyqt5 method to close or delete the widget and setup it again on command

I have created short application with Pyqt5 designer:
Here is the code:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(752, 674)
self.formLayout_2 = QtWidgets.QFormLayout(Form)
self.formLayout_2.setObjectName("formLayout_2")
self.formLayout = QtWidgets.QFormLayout()
self.formLayout.setObjectName("formLayout")
self.formLayout_2.setLayout(0, QtWidgets.QFormLayout.LabelRole, self.formLayout)
self.pushButton = QtWidgets.QPushButton(Form)
self.pushButton.setObjectName("pushButton")
self.formLayout_2.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.pushButton)
self.widget = QtWidgets.QWidget(Form)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(1)
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
self.widget.setSizePolicy(sizePolicy)
self.widget.setStyleSheet("background-color:white;")
self.widget.setObjectName("widget")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.widget)
self.pushButton_2 = QtWidgets.QPushButton(Form)
self.pushButton_2.setObjectName("pushButton_2")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.pushButton_2)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.pushButton.setText(_translate("Form", "Letters"))
self.pushButton_2.setText(_translate("Form", "Numbers"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Form = QtWidgets.QWidget()
ui = Ui_Form()
ui.setupUi(Form)
Form.show()
sys.exit(app.exec_())
This script is connected to appexe script(dialog):
import sys
from PyQt5 import QtWidgets, QtCore, QtGui
import string
from functools import partial
from setup_test import Ui_Form
from PyQt5.QtWidgets import QWidget, QGridLayout, QPushButton, QApplication
class myprog(Ui_Form):
def __init__ (self, dialog):
Ui_Form.__init__(self)
self.setupUi(dialog)
self.symbols = [string.ascii_lowercase, string.digits]
self.buttons = [self.pushButton, self.pushButton_2]
for i,v in enumerate(self.buttons):
self.buttons[i].clicked.connect(partial(self.application, i))
def application(self, i):
self.grid1 = QGridLayout(self.widget)
names = [x for x in self.symbols[i]]
positions = [(j,d) for j in range(7) for d in range(6)]
for a,b in zip(positions, names):
button = QPushButton(b)
self.grid1.addWidget(button, *a)
print(self.grid1.count())
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
dialog = QtWidgets.QDialog()
appexe = myprog(dialog)
dialog.show()
sys.exit(app.exec_())
I am new to Pyqt5. The basic idea is: whenever you click the button 'Letters' or button 'Numbers', the widget below should layout all the sysmbols within Letters or buttons.
If you do execute the appexe script, you can see, it works for the first try. (Please ignore the visual design). I am happy with the result. When button is pressed, it shows the buttons in grid(widget).
The problem I am facing is, how to clear the grid and it's widget when other button is hit > and display the new grid, new widgets.
If you look close, there is also a print statement:
print(self.grid1.count())
When I am in application and i am clicking letter and number button, it tells me how many widgets are within grid, however I just can't find a way how to display the new setup.
I would appreciate your help and your ideas. Thank you.
There are a number of different ways to remove a layout and its child widgets. However, the only one that seems to work properly with your particular example, is this one:
def application(self, i):
layout = self.widget.layout()
if layout is not None:
QWidget().setLayout(layout)
...
This works because setting the layout on a different widget will automatically re-parent that layout and all its children. Then when the temporary parent widget is immediately garbage-collected, Qt will automatically delete all its children as well.

Resources