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.
Screenshot of Window
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_())
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.
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_())
Related
I want to make Pushbutton show me the text like this
1 You clicked
2 PushButton
not in the same line.
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
Class Ui_MainWindow (object):
def setupUi(self, MainWindow):
MainWindow.resize(506, 312)
self.centralwidget = QtWidgets.QWidget(MainWindow)
# adding pushbutton
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(200, 150, 93, 28))
# adding signal and slot
self.pushButton.clicked.connect(self.changelabeltext)
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(140, 90, 221, 20))
# keeping the text of label empty before button get clicked
self.label.setText("")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Push Button"))
def changelabeltext(self):
# changing the text of label after button get clicked
self.label.setText("You clicked PushButton")
# Hiding pushbutton from the main window
# after button get clicked.
self.pushButton.hide()
If __name__ == "__main__":
app = QtWidgets.QApplication (sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
if I understand you correctly, you want the text to be displayed as follows:
You clicked
PushButton
To achieve this, try placing a newline character in between the words like this:
"You clicked \nPushButton"
Alternatively, if this does not display correctly, try adding a new label with the second half of the text to it, or increase the size of the rectangle in which you placed the text.
Although you technically only asked how to place "You clicked" below "Pushbutton" (which can be done by putting a newline in the string "You clicked \nPushButton"), when you do this you will run into another fundamental problem with your code, mainly that you are positioning widgets by drawing them inside a QRect with a static position.
This will produce problems when you change the text or window size, since you will have to manually change the coordinates of the QRect to place then in the correct position.
I took the liberty of rewriting your setupUi to use layouts (which I recommend you research) instead of QRect's. Hope this helps, it should be a drop in replacement:
def setupUi(self, MainWindow):
MainWindow.resize(506, 312)
self.mainWidget = QtWidgets.QWidget(MainWindow)
self.pushButton = QtWidgets.QPushButton()
self.pushButton.clicked.connect(self.changelabeltext)
self.label = QtWidgets.QLabel()
self.label.setText("")
self.hbox = QtWidgets.QHBoxLayout()
self.hbox.addWidget(self.pushButton)
self.hbox.addWidget(self.label)
self.vbox = QtWidgets.QVBoxLayout()
self.vbox.addLayout(self.hbox)
self.hbox.setAlignment(QtCore.Qt.AlignCenter)
self.vbox.setAlignment(QtCore.Qt.AlignCenter)
self.mainWidget.setLayout(self.vbox)
MainWindow.setCentralWidget(self.mainWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
I am trying to let a user choose from a GUI a choice of procedures to be executed. Without the GUI section, i can execute the procedures and both appear at the same time on separate windows that i can run independently. Now i want the user to choose from a GUI which procedure to run first to avoid multiple windows open at the same time. While the procedures execute properly when i choose the second pushbutton i have this error message : RuntimeError: wrapped C/C++ object of type QPlainTextEdit has been deleted. I ve seen this issue around and tried what has been proposed but without success. Following sugestions from
[https://stackoverflow.com/questions/63302430/call-different-window-classes-into-a-main-window-in-pqt5-python], I tried to reduce the code as much as possible. Despite some specific packages utilized these are not responsible for the error observed and anyone should be able to run this code. the Mainwindow class is already using Qt for displaying a window but when used standalone i do not have any error. The error is inherent to the Ui_MainWindow(object) class, i also tried with item list the same issue occurs.The error appears each time i press Queue when choosing the Run 2 procedure.
import logging
log = logging.getLogger(__name__)
log.addHandler(logging.NullHandler())
import sys
import random
import pandas as pd
from pymeasure.log import console_log
from pymeasure.display.Qt import QtGui
from PyQt5 import QtCore, QtGui, QtWidgets
from pymeasure.display.windows import ManagedWindow
from pymeasure.experiment import Procedure, Results
from pymeasure.experiment import IntegerParameter, FloatParameter, Parameter
import tempfile
# this class uses the Pymeasure package to run and display experiments here it s just generating a random number. the iterations
#number being the input parameter on the window and one can queue several runs
# execute is the method generating the random number and Mainwindow is the dipsplay and the queue of the runs. the data are
# save in a temp file
class RandomProcedure_1(Procedure):
iterations = IntegerParameter('Loop Iterations', default=10)
DATA_COLUMNS = ['Iteration', 'Random Number']
#
def startup(self):
log.info("Setting the time of the random number generator")
random.seed(self.seed)
def execute(self):
log.info("Starting the loop of %d iterations" % self.iterations)
for i in range(self.iterations):
data = {
'Iteration': i,
'Random Number': random.randint(1, 50)
}
self.emit('results', data)
log.debug("Emitting results: %s" % data)
if self.should_stop():
log.warning("Caught the stop flag in the procedure")
break
class MainWindow_1(ManagedWindow):
# this define the window where the random number vs iteration plot is displayed
def __init__(self):
super(MainWindow_1, self).__init__(
procedure_class=RandomProcedure_1,
inputs=['iterations'],
displays=['iterations'],
x_axis='Iteration',
y_axis='Random Number',
)
self.setWindowTitle('RandomProcedure_1')
def queue(self, *, procedure=None):
if procedure is None:
procedure = self.make_procedure()
filename = tempfile.mktemp()
log.info("Constructing the Results with a data file: %s" % filename)
results = Results(procedure, filename)
experiment = self.new_experiment(results)
self.manager.queue(experiment)
# the GUI with 2 pushbuttons for each procedure (here the same duplicated for simplicity)
# i also tried with a list of item but the same error occurs
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.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(110, 160, 112, 34))
self.pushButton.setObjectName("EXP1")
self.pushButton.clicked.connect(self.startProcedure_1)
self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(580, 170, 112, 34))
self.pushButton_2.setObjectName("EXP2")
self.pushButton_2.clicked.connect(self.startProcedure_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)
def startProcedure_1(self):
self.window = MainWindow_1()
self.window.show()
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "Procedures"))
self.pushButton.setText(_translate("MainWindow", "Run 1"))
self.pushButton_2.setText(_translate("MainWindow", "Run 2"))
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_())
I designed a windows desktop app with QT Designer and PYQT5. The problem is that, I can not select any item, text on main window, or on qtablewidget to paste it manually somewhere else. It will make things easier for users not for me. `
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.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(260, 160, 256, 192))
self.tableWidget.setRowCount(3)
self.tableWidget.setColumnCount(2)
self.tableWidget.setObjectName("tableWidget")
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setItem(1, 0, item)
self.input_gunduz = QtWidgets.QLineEdit(self.centralwidget)
self.input_gunduz.setGeometry(QtCore.QRect(370, 70, 71, 20))
self.input_gunduz.setObjectName("input_gunduz")
self.label_5 = QtWidgets.QLabel(self.centralwidget)
self.label_5.setGeometry(QtCore.QRect(220, 70, 101, 21))
font = QtGui.QFont()
font.setPointSize(9)
font.setBold(True)
font.setWeight(75)
self.label_5.setFont(font)
self.label_5.setObjectName("label_5")
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)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
__sortingEnabled = self.tableWidget.isSortingEnabled()
self.tableWidget.setSortingEnabled(False)
item = self.tableWidget.item(1, 0)
item.setText(_translate("MainWindow", "trial"))
self.tableWidget.setSortingEnabled(__sortingEnabled)
self.label_5.setText(_translate("MainWindow", "Gündüz (kWhr):"))
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_())
`
The code is as seen above. Please help me make the main window selectable
Copying of text does not work in the same way for every widget, because each widget type uses even radically different way to show or interact with text.
If you want to copy the text of a QLabel, you have to make it selectable (by using label.setTextInteractionFlags(Qt.TextSelectableByMouse)).
But if you want to copy the text from QTableWidget, things are very different, since a table allows interaction with their items that prevent a simple text selection.
Obviously, the most simple method would be to start editing the item (assuming it's editable) and select its text, but if you want other ways to do that, it depends on how you want to be able to copy the text.
A possibility is to use the ctrl+c keyboard shortcut. To do so, we need to install an event filter on the table widget:
from PyQt5 import QtCore, QtGui, QtWidgets
from mainwindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
# install an event filter on the table widget, so that we can filter all
# its event, including keyboard presses
self.tableWidget.installEventFilter(self)
def eventFilter(self, source, event):
if event.type() == QtCore.QEvent.KeyPress and event == QtGui.QKeySequence.Copy:
# check if an index is currently selected and it has text
text = self.tableWidget.currentIndex().data()
if text:
# copy that text to the clipboard
QtWidgets.QApplication.clipboard().setText(text)
return super().eventFilter(source, event)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
Note that in the example above I used the multiple inheritance method explained in the documentation about using Designer with ui files. You should never edit the files created by pyuic.
It's also possible to set a menu for the table widget and copy the text from there:
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
# ...
# use the custom context menu policy for the table widget, so that we can
# connect the menu request to a slot
self.tableWidget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
self.tableWidget.customContextMenuRequested.connect(self.showTableMenu)
def showTableMenu(self, pos):
# get the text of the index at the mouse cursor (if any)
text = self.tableWidget.indexAt(pos).data()
menu = QtWidgets.QMenu()
copyAction = menu.addAction('Copy')
if not text:
copyAction.setEnabled(False)
# show the menu
res = menu.exec_(QtGui.QCursor.pos())
if res == copyAction:
# if the menu has been triggered by the action, copy to the clipboard
QtWidgets.QApplication.clipboard().setText(text)
I'm still trying to figure out PyQt and running into another issue that I've been beating my head over for the last several hours. When I use pyuic5 to convert the .ui file into the .py file, part of the output (in the class Ui_MainWindow) connects signals to slots:
self.browseButton.clicked.connect(MainWindow.browseSlot)
self.importButton.clicked.connect(MainWindow.importSlot)
self.lineEdit.returnPressed.connect(MainWindow.returnPressedSlot)
This is called from the main function:
def main():
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = MainWindowUI()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
Above this, in the same file, I have the following code:
class MainWindowUI(Ui_MainWindow):
def __init__(self):
super().__init__()
self.model = Model()
def setupUi(self, mainWindow):
super().setupUi(mainWindow)
def debugPrint(self, msg):
self.textEdit.append(msg)
def refreshAll(self):
self.lineEdit.setText(self.model.getFileName())
self.textEdit.setText(self.model.getFileContents())
def returnPressedSlot(self):
self.debugPrint('Return key pressed')
def importSlot(self):
self.debugPrint('Import button pressed')
def browseSlot(self):
self.debugPrint('Browse button pressed')
The exact error I'm getting is this:
AttributeError: 'QMainWindow' object has no attribute 'browseSlot'
This actually makes perfect sense, because there's no reason QtWidgets.QMainWindow() should know anything about the custom slots I defined in the MainWindowUI class. So it makes sense that it doesn't work, but I'm confused about what I should be doing differently. This is how every tutorial I've seen sets it up, so clearly I have a fundamental misunderstanding somewhere. Any help in clarifying this issue would be appreciated!
Many thanks in advance.
Edited to add the full code of my Ui_MainWindow class:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.11.3
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(798, 593)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.gridLayout = QtWidgets.QGridLayout(self.centralwidget)
self.gridLayout.setObjectName("gridLayout")
self.tabWidget = QtWidgets.QTabWidget(self.centralwidget)
self.tabWidget.setObjectName("tabWidget")
self.tab = QtWidgets.QWidget()
self.tab.setObjectName("tab")
self.verticalLayout = QtWidgets.QVBoxLayout(self.tab)
self.verticalLayout.setObjectName("verticalLayout")
self.horizontalLayout_2 = QtWidgets.QHBoxLayout()
self.horizontalLayout_2.setObjectName("horizontalLayout_2")
self.frame_2 = QtWidgets.QFrame(self.tab)
self.frame_2.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame_2.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame_2.setObjectName("frame_2")
self.debugTextBrowser = QtWidgets.QTextBrowser(self.frame_2)
self.debugTextBrowser.setGeometry(QtCore.QRect(10, 10, 351, 461))
self.debugTextBrowser.setObjectName("debugTextBrowser")
self.horizontalLayout_2.addWidget(self.frame_2)
self.frame = QtWidgets.QFrame(self.tab)
self.frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
self.frame.setFrameShadow(QtWidgets.QFrame.Raised)
self.frame.setObjectName("frame")
self.browseButton = QtWidgets.QPushButton(self.frame)
self.browseButton.setGeometry(QtCore.QRect(80, 30, 51, 20))
self.browseButton.setObjectName("browseButton")
self.lineEdit = QtWidgets.QLineEdit(self.frame)
self.lineEdit.setGeometry(QtCore.QRect(80, 10, 281, 20))
self.lineEdit.setObjectName("lineEdit")
self.importButton = QtWidgets.QPushButton(self.frame)
self.importButton.setGeometry(QtCore.QRect(310, 30, 51, 20))
self.importButton.setObjectName("importButton")
self.textEdit = QtWidgets.QTextEdit(self.frame)
self.textEdit.setGeometry(QtCore.QRect(80, 130, 281, 81))
self.textEdit.setObjectName("textEdit")
self.horizontalLayout_2.addWidget(self.frame)
self.verticalLayout.addLayout(self.horizontalLayout_2)
self.setupProgressBar = QtWidgets.QProgressBar(self.tab)
self.setupProgressBar.setProperty("value", 0)
self.setupProgressBar.setTextVisible(False)
self.setupProgressBar.setInvertedAppearance(False)
self.setupProgressBar.setTextDirection(QtWidgets.QProgressBar.TopToBottom)
self.setupProgressBar.setObjectName("setupProgressBar")
self.verticalLayout.addWidget(self.setupProgressBar)
self.tabWidget.addTab(self.tab, "")
self.tab_2 = QtWidgets.QWidget()
self.tab_2.setObjectName("tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.tab_3 = QtWidgets.QWidget()
self.tab_3.setObjectName("tab_3")
self.tabWidget.addTab(self.tab_3, "")
self.tab_4 = QtWidgets.QWidget()
self.tab_4.setObjectName("tab_4")
self.tabWidget.addTab(self.tab_4, "")
self.tab_5 = QtWidgets.QWidget()
self.tab_5.setObjectName("tab_5")
self.tabWidget.addTab(self.tab_5, "")
self.gridLayout.addWidget(self.tabWidget, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 798, 18))
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.tabWidget.setCurrentIndex(0)
self.browseButton.clicked.connect(MainWindow.browseSlot)
self.importButton.clicked.connect(MainWindow.importSlot)
self.lineEdit.returnPressed.connect(MainWindow.returnPressedSlot)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.browseButton.setText(_translate("MainWindow", "Browse"))
self.importButton.setText(_translate("MainWindow", "Import"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Setup"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Production Forecast"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), _translate("MainWindow", "Production Forecast"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_4), _translate("MainWindow", "Page"))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_5), _translate("MainWindow", "Page"))
PyQt recommends in your docs that you should inherit from the appropriate widget, in this case QMainWindow, and use Ui_MainWindow as an interface, it is also recommended that you use the decorator #QtCore.pyqtSlot() since you save resources and avoid having problems with overloaded signals.
class MainWindowUI(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
self.setupUi(self)
self.model = Model()
def setupUi(self, mainWindow):
super().setupUi(mainWindow)
def debugPrint(self, msg):
self.textEdit.append(msg)
def refreshAll(self):
self.lineEdit.setText(self.model.getFileName())
self.textEdit.setText(self.model.getFileContents())
#QtCore.pyqtSlot()
def returnPressedSlot(self):
self.debugPrint('Return key pressed')
#QtCore.pyqtSlot()
def importSlot(self):
self.debugPrint('Import button pressed')
#QtCore.pyqtSlot()
def browseSlot(self):
self.debugPrint('Browse button pressed')
def main():
app = QtWidgets.QApplication(sys.argv)
w = MainWindowUI()
w.show()
sys.exit(app.exec_())
if __name__ == '__main__': main()
The PyQt 5 Designer generates files with .ui extension. The file contains xml code which can be converted to Python code with the pyuic5 command. The pyuic5 command produces a file with .py extension.
But each time the pyuic5 command is run, it overwrites any changes made to the Python file. To prevent this we need to copy the "main" code in the generated Python file to a separate file and then use this file as our main program file. In this file we can import the Python class generated by the pyuic5 command. We can also add our custom slots in this file
This practice of separating Qt Desginer code from custom code is good Qt programming practice. It has been suggested in Section 3 of the video ebook: "Python GUI Programming Recipes using PyQt5".
This question already has answers here:
PYQT Qcombobox set value selected to a variable
(2 answers)
Closed 4 years ago.
Hi can anyone please tell me about it? I am new to PyQt.
For instance I have 3 options A, B and C in a combobox and if I select A, it should display one set widgets, maybe call X. If I choose B, it should display another set of widgets say Y and so on.
Further I have grouped all the widgets to be displayed in respective containers using GROUP box. Specifically, Here I just want to link A option of Combobox to the groupbox.
Thank You :)
This is my Code here:
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.comboBox = QtWidgets.QComboBox(self.centralwidget)
self.comboBox.setGeometry(QtCore.QRect(220, 40, 281, 22))
self.comboBox.setObjectName("comboBox")
self.comboBox.addItem("-")
self.comboBox.addItem("A")
self.comboBox.addItem("B")
self.comboBox.addItem("C")
self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
self.groupBox.setGeometry(QtCore.QRect(70, 90, 631, 321))
self.groupBox.setObjectName("groupBox")
**#######################################################**
self.groupBox.hide()
**#######################################################**
self.pushButton_1 = QtWidgets.QPushButton(self.groupBox)
self.pushButton_1.setGeometry(QtCore.QRect(120, 40, 391, 101))
self.pushButton_1.setObjectName("pushButton_1")
self.label_1 = QtWidgets.QLabel(self.groupBox)
self.label_1.setGeometry(QtCore.QRect(280, 220, 150, 61))
self.label_1.setStyleSheet("font: 14pt \"MS Shell Dlg 2\";")
self.label_1.setObjectName("label_1")
**#######################################################**
cur_txt = self.comboBox.currentText()
if cur_txt == 'A':
self.groupBox.show()
else:
self.groupBox.hide()
**#######################################################**
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.groupBox.setTitle(_translate("MainWindow", "Yupp"))
self.pushButton_1.setText(_translate("MainWindow", "Press Me1"))
self.label_1.setText(_translate("MainWindow", "Hello Moto1"))
self.pushButton_2.setText(_translate("MainWindow", "Press Me2"))
self.label_2.setText(_translate("MainWindow", "Hello Moto2"))
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_())
The majority of the part has been generated using Qt designer. Just the things between # has been written by me. I know there are somethings which are wrong but I don't know how to rectify them.
I got the answer from the following link:
PYQT Qcombobox set value selected to a variable
It is quite helpful.
Just had to add the following lines to the code. The code looks neat by creating a separate method (temp_var).
self.comboBox.activated[str].connect(self.temp_var)
def temp_var(self, text):
cur_txt = text
if cur_txt == 'A':
self.groupBox.show()
else:
self.groupBox.hide()