Reputation: 409
I'm a complete beginner using Qt and at building GUIs in general, so apologies if this is a stupid question but I can't find an answer on the internet. I'm hoping you can help me with a couple of questions:
First, I've created a GUI using Qt Designer, and I've run into an issue on "wiring it up". I have a combo box with a variety of options, and what I want to do is have the choice in the box change the text in a bunch of line edit boxes. The problem is, when the textActivated()
signal of the combo box is sent to the setText()
slot of the line edit, the line edit is filled in with the text in the combo box.
Below I put a small example to show what I mean. This combo box has values A, B and C. When an option is selected, that letter appears in the box. What I want to do is have each entry of the combo box be a 'key' to a value, so if e.g. A is selected then the line edit is filled in with Option 1 or something like that. The reason I want to do it this way is because the combo box will set a bunch of default parameters based on the input, and then the user can tweak the values if desired.
I know the line that I need to modify/the line responsible for the signal/slot connection is
self.comboBox.textActivated['QString'].connect(self.lineEdit.setText)
but I don't really understand how I would pass in the value of the combobox when .connect is an instance function.
Does anyone know how to do this with a custom function/slot? The full code is at the bottom of this post.
Second, a related question, why do these signal/slots go in the __init__()
function of the window? Does app.exec_()
continuously run __init__()
? Wouldn't it be more sensible to instantiate an object and then have an "update" function that is run in the app loop?
Thanks in advance!
Full Code:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'practice.ui'
#
# Created by: PyQt5 UI code generator 5.15.0
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(493, 124)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.horizontalLayout.addWidget(self.comboBox)
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setObjectName("lineEdit")
self.horizontalLayout.addWidget(self.lineEdit)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 493, 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)
self.comboBox.textActivated['QString'].connect(self.lineEdit.setText)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.comboBox.setItemText(0, _translate("MainWindow", "A"))
self.comboBox.setItemText(1, _translate("MainWindow", "B"))
self.comboBox.setItemText(2, _translate("MainWindow", "C"))
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_())
Upvotes: 1
Views: 5979
Reputation: 2083
Update
from PyQt5 import QtCore, QtGui, QtWidgets
#here you make dict in advance.
dic = {'A':'You choose A',
'B':'You choose B',
'C':'You choose C'}
# a list of the dict key. #[*dic] is also ok instead of lis
lis = dic.keys()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(493, 124)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setObjectName("comboBox")
#addItems is for multiple items.
self.comboBox.addItems(lis)
self.horizontalLayout.addWidget(self.comboBox)
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setObjectName("lineEdit")
self.horizontalLayout.addWidget(self.lineEdit)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 493, 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)
self.comboBox.activated['QString'].connect(self.new_selection)
#I think it is not bothered with .emit of my first answer.
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
# number and value you can use enumerate func.
for num, key in enumerate(lis):
self.comboBox.setItemText(num, _translate("MainWindow", key))
def new_selection(self):
self.lineEdit.setText(dic[self.comboBox.currentText()])
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv) # Whole application
MainWindow = QtWidgets.QMainWindow() # create the actual window
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show() # Actually show the window
sys.exit(app.exec_())
You make a dict somewhere.
And you always refer it.
I don't know how long you expand the key & value connections, but you now set the same key & value anywhere directly.It is verbose , you may as well always get the key from one object as much as you can. And if you do so, whatever you add new keys& values in the dict, the changes reflect without changing other codes.
When you want to expand your key & value, all you have to do is to rewrite the data of dic
only once.
Fortunately, dict can conserve the order of keys from ...python3.6
You can use keys like a list.
Please, append 'D': 'You choose D' or other datas and try it!
I'm glad my answer is what you want.
Simply, can you achieve your purpose by this code?
What I understood from your question is to set the first item on the lineedit at the first time.
I don't know what you want to set actually, but, textActivated() since (PyQt5.14) (I could do it activated() because my version is 5.9.x) ...
`signal.connect(somthing slot)` means that make a connection between signal & slot.
`signal.emit(object)` means that to emit the connected signal.
Because you have connected textActivated
(signal) with lineEdit.setText
(slot), so, if you set the currentText() for object when it is emitted, the setText catch the object.If you connect the signal to three lineedit.setText
, all of the lineedits set text by the same information.
Before emitting, you must make a connection except for default settings.
I think you don't need to make a custom signal & slot if my answer is what you want.
Second, a related question, why do these signal/slots go in the init() function of the window? Does app.exec_() continuously run init()? Wouldn't it be more sensible to instantiate an object and then have an "update" function that is run in the app loop?
You can connect signal/slots out of the init().
But it is often very convenient to make a connection in that place.
For the most part, there is no chance to disconnect.And if you don't want to connect, you can block the connection by using blockSignals()
method.
So, for the evidence of it, you may try to write test code somewhere to make a connection after __init__
.
For example, a signal&slot for making a signal&slot.
app.exec_()
run a loop but not run __init__()
over and over again.
app.exec_()
is waiting for user input, eventHandler, for example, keyPressEvent
, mousePressEvent
.
Especially, paintEvent()
for showing the GUI.
init is only called once. The variables of it are allotted into your computer's address of memory.
To call init over and over again means that the memory is rewritten over and over again.Memory is mainly necessary for avoiding this waste.
If you change the contents of variables after usage of your application by keyPressEvent
or mousePressEvent
, or signal&slot mechanism, it is that you rewrite the allotted addresses of the memory to other things.
I think update is called after that change. This is for updating the GUI surface information according to the new variables.
Upvotes: 0
Reputation: 409
Thanks for the help @Haru, I figured it out:
This is the relevant code:
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
...
...
...
self.comboBox.textActivated['QString'].connect(self.new_selection)
def new_selection(self):
if self.comboBox.currentText() == 'A':
self.lineEdit.setText('You chose B')
elif self.comboBox.currentText() == 'B':
self.lineEdit.setText('You chose B')
elif self.comboBox.currentText() == 'C':
self.lineEdit.setText('You chose C')
Where, upon selection of a combo box item, some text (that's not one of the options in the combo box) is displayed on the line edit. The above code works for the initialization of the window, but not when a new selection is made.
Full code here:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(493, 124)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.comboBox.addItem("")
self.horizontalLayout.addWidget(self.comboBox)
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setObjectName("lineEdit")
self.horizontalLayout.addWidget(self.lineEdit)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 493, 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)
self.comboBox.textActivated['QString'].connect(self.new_selection)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.comboBox.setItemText(0, _translate("MainWindow", "A"))
self.comboBox.setItemText(1, _translate("MainWindow", "B"))
self.comboBox.setItemText(2, _translate("MainWindow", "C"))
def new_selection(self):
if self.comboBox.currentText() == 'A':
self.lineEdit.setText('You chose B')
elif self.comboBox.currentText() == 'B':
self.lineEdit.setText('You chose B')
elif self.comboBox.currentText() == 'C':
self.lineEdit.setText('You chose C')
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv) # Whole application
MainWindow = QtWidgets.QMainWindow() # create the actual window
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show() # Actually show the window
sys.exit(app.exec_())
Upvotes: 0