Dynamically created labels won't display on the screen pyqt5 [duplicate] - python-3.x

This question already has answers here:
QLabel does not display in QWidget
(2 answers)
Closed 2 years ago.
I am making a basic GUI application using PyQt5, and need to create labels dynamically after user input. Now, the problem is they won't show on the screen, although the objects themselves are created. This function is getting called on button press after user finishes input:
def set_result_labels(self):
font = QtGui.QFont()
font.setPointSize(15)
for i in range(len(self.text_parties_names)):
label = QtWidgets.QLabel(self.centralwidget)
setattr(self, f"label_{i+5}", label)
label.setGeometry(QtCore.QRect(700, (100+4*i), 50, 50))
label.setFont(font)
label.setText(self.text_parties_names[i])
label.setObjectName(f"label_{i+5}")
But, if I "explicitly" create them, like this:
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(600, 400, 171, 40))
self.label_5.setFont(font)
self.label_5.setText(self.text_parties_names[0])
self.label_5.setObjectName("label_25")
It works with no issues. I do not understand why.

as an option, you can insert the label in the layout, for example like this:
import sys
from PyQt5 import QtWidgets, QtGui, QtCore
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
button = QtWidgets.QPushButton("Button")
button.clicked.connect(self.set_result_labels)
scrollArea = QtWidgets.QScrollArea()
widget = QtWidgets.QWidget()
scrollArea.setMinimumWidth(200)
scrollArea.setMinimumHeight(200)
scrollArea.setWidget(widget)
scrollArea.setWidgetResizable(True)
scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.scroll_box = QtWidgets.QVBoxLayout(widget)
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(scrollArea)
layout.addStretch(1)
layout.addWidget(button)
self.text_parties_names = '12345'
def set_result_labels(self):
font = QtGui.QFont()
font.setPointSize(15)
for i in range(len(self.text_parties_names)):
label = QtWidgets.QLabel()
setattr(self, f"label_{i+5}", label)
# label.setGeometry(QtCore.QRect(700, (100+4*i), 50, 50))
label.setFont(font)
label.setText(self.text_parties_names[i])
label.setObjectName(f"label_{i+5}")
self.scroll_box.addWidget(label) # <<<---
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = Window()
w.show()
sys.exit(app.exec_())

Related

Can the style of a custom QFileDialog be changed

I did a custom QFileDialog in other to add a label and a check box to it. It works the way I want but the problem is that when you modify this class the style changes since we aren't calling the static method. I'm doing this in a larger project and this change in style isn't aesthetically pleasing to the user, compared to how the whole app looks. Is there a way to style it? I'm sure the style changes due to this options=QtWidgets.QFileDialog.DontUseNativeDialog, but if I take it out, the code won't work. Below is a sample of the code
import sys
from PyQt5 import QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
button = QtWidgets.QPushButton("Open")
button.clicked.connect(self.OpenFile)
button.setStyleSheet('background-color: rgba(53, 53, 53,50)')
save_button = QtWidgets.QPushButton("Save")
# save_button.clicked.connect(self.savingFile)
save_button.setStyleSheet('background-color: rgba(53, 53, 53,50)')
hlayout = QtWidgets.QHBoxLayout()
hlayout.addWidget(button)
hlayout.addWidget(save_button)
lay = QtWidgets.QVBoxLayout(self)
lay.addLayout(hlayout)
def OpenFile(self):
dialog = QtWidgets.QFileDialog(
self,
"Open File",
"",
"Image Files (*.dcm *.DCM *.tif *.tiff *.TIF "
"*.TIFF *.oct *.OCT);;All Files (*)",
supportedSchemes=["file"],
options=QtWidgets.QFileDialog.DontUseNativeDialog,
)
checkBox = QtWidgets.QCheckBox()
labelWidget = QtWidgets.QLabel()
labelWidget.setText("Repeated Frame Averaging")
dialog.layout().addWidget(labelWidget)
dialog.layout().addWidget(checkBox)
dialog.setOption(QtWidgets.QFileDialog.DontUseNativeDialog, True)
if dialog.exec_() == QtWidgets.QDialog.Accepted:
filename = dialog.selectedFiles()[0]
cbSelection = checkBox.isChecked()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.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_())

Close second widget after pressing save button pyqt5

I am writing an application where main widget windows opens second widget window and in the second widget window, I am taking some inputs from user and on hitting save button, second widget window should saves the data into xml file and should get closed but the second window is not closing.
I tried most of the things from google like self.close(), self.destroy(),self.hide() self.window().hide(), self.window().destroy() none of them are working.
I don't want to do sys.exit() as this is closing complete application but just have to close secondWidgetWindow after clicking save button so that user can do another work in first widget window.
Below is the snippet :
FirstWidgetWindow.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_firstWidgetWindow(QtWidgets.QMainWindow):
def __init__(self,firstWidgetWindow):
super().__init__()
self.setupUi(firstWidgetWindow)
def setupUi(self, firstWidgetWindow):
### code to create Button ###
self.btnOpenNewWidgetWindow.clicked.connect(self.openNewWindow)
def openNewWindow(self):
self.secondWidgetWindow = QtWidgets.QWidget()
self.ui = Ui_secondWidgetWindow()
self.ui.setupUi(self.secondWidgetWindow)
self.secondWidgetWindow.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
firstWidgetWindow = QtWidgets.QWidget()
ui = Ui_firstWidgetWindow(firstWidgetWindow)
firstWidgetWindow.show()
sys.exit(app.exec_())
secondWidgetWindow.py
class Ui_secondWidgetWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
def setupUi(self, secondWidgetWindow):
### creating line edit to take input from user
### creating save button
self.btnSave.clicked.connect(self.saveUserInput)
def saveUserInput(self):
## saving user inputs in xml file
self.close() ## here i needs to close this window.
Close second widget after pressing save button:
self.secondWidgetWindow.hide()
Try it:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_secondWidgetWindow(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.secondWidgetWindow = None
def setupUi(self, secondWidgetWindow):
self.secondWidgetWindow = secondWidgetWindow
### creating line edit to take input from user
self.line_edit = QtWidgets.QLineEdit(secondWidgetWindow)
self.line_edit.setGeometry(20, 20, 300, 20)
### creating save button
self.btnSave = QtWidgets.QPushButton('save', secondWidgetWindow)
self.btnSave.setGeometry(50, 50, 100, 50)
self.btnSave.clicked.connect(self.saveUserInput)
def saveUserInput(self):
## saving user inputs in xml file
#self.close() ## here i needs to close this window.
self.secondWidgetWindow.hide()
QtWidgets.QMessageBox.information(self, "SAVE",
"saving user inputs in xml file")
class Ui_firstWidgetWindow(QtWidgets.QMainWindow):
def __init__(self,firstWidgetWindow):
super().__init__()
self.setupUi(firstWidgetWindow)
def setupUi(self, firstWidgetWindow):
### code to create Button ###
self.btnOpenNewWidgetWindow = QtWidgets.QPushButton('OpenNewWidgetWindow', firstWidgetWindow)
self.btnOpenNewWidgetWindow.setGeometry(50, 100, 300, 50)
self.btnOpenNewWidgetWindow.clicked.connect(self.openNewWindow)
def openNewWindow(self):
self.secondWidgetWindow = QtWidgets.QWidget()
self.ui = Ui_secondWidgetWindow()
self.ui.setupUi(self.secondWidgetWindow)
self.secondWidgetWindow.show()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
firstWidgetWindow = QtWidgets.QWidget()
ui = Ui_firstWidgetWindow(firstWidgetWindow)
firstWidgetWindow.setGeometry(700, 250, 400, 200)
firstWidgetWindow.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.

PyQt QScrollArea not scrolling

I want to put some elements of my UI in a scroll area as there can be a lot of them. I tried the following peice of code, but the area just keeps growing as I put more elements on it.
In the first part I set up a scroll area, a widget and a layout. I apply the layout to the widget and I set the widget to the scrollarea. Then I fill in my layout in an external function. The button under all of it allows to fill more elements in the layout.
scrollRow = QtGui.QScrollArea()
scrollRow.setMaximumSize(600, 400)
self.rowAssetWidget = QtGui.QWidget()
self.rowAssetLayout = QtGui.QGridLayout()
self.rowAssetLayout.setSpacing(20)
self.rowAssetWidget.setLayout(self.rowAssetLayout)
scrollRow.setWidget(self.rowAssetWidget)
#self.mainLayout.addLayout(self.rowAssetLayout, 2, 0)
self.mainLayout.addWidget(self.rowAssetWidget, 2, 0)
self.assetRow()
self.addAssetRowBtn = QtGui.QPushButton("+")
self.addAssetRowBtn.setFixedSize(20, 20)
self.mainLayout.addWidget(self.addAssetRowBtn, 3, 0)
self.connect(self.addAssetRowBtn, QtCore.SIGNAL("clicked()"), self.addAssetRow)
My elements appear fine, but it is not scrolling. Any idea ?
import sys
from PyQt4 import QtGui,QtCore
class LayoutTest(QtGui.QWidget):
def __init__(self):
super(LayoutTest, self).__init__()
self.horizontalLayout = QtGui.QVBoxLayout(self)
self.scrollArea = QtGui.QScrollArea(self)
self.scrollArea.setWidgetResizable(True)
self.scrollAreaWidgetContents = QtGui.QWidget()
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 380, 280))
self.horizontalLayout_2 = QtGui.QHBoxLayout(self.scrollAreaWidgetContents)
self.gridLayout = QtGui.QGridLayout()
self.horizontalLayout_2.addLayout(self.gridLayout)
self.scrollArea.setWidget(self.scrollAreaWidgetContents)
self.add_button = QtGui.QPushButton("Add Items")
self.horizontalLayout.addWidget(self.scrollArea)
self.horizontalLayout.addWidget(self.add_button)
self.connect(self.add_button, QtCore.SIGNAL("clicked()"), self.addButtons)
self.setGeometry(300, 200, 400, 300)
def addButtons(self):
for i in range(0, 50):
self.r_button = QtGui.QPushButton("Button %s " % i)
self.gridLayout.addWidget(self.r_button)
def run():
app = QtGui.QApplication(sys.argv)
ex = LayoutTest()
ex.show()
sys.exit(app.exec_())
if __name__ == "__main__":
run()
I know its too late to answer for this question, but here is a working example and you missing the parent layout.
Yeah. My mistake was on my end is that PyQT Designer set a .setGeometry() for the ScrollAreaWidgetContents widget within the QScrollArea. My solution was to use instead the .setMinimumHeight( ) and .setMinimumWidth( ).
Remove this:
self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 380, 280))
And replace with:
self.scrollAreaWidgetContents.setMinimumWidth(380)
self.scrollAreaWidgetContents.setMinimumHeight(280)

Resources