Qt Python GUI Crashes on Button Click - python

The code is smaller version I put together to demonstrate what I am trying to do. I just need to get information from a QButtonGroup of radio buttons. Specifically the text of which one has been clicked. However, when I run click the button in the GUI python crashes. There is no error message so I can't pinpoint the cause. Below is the example code, below that is the image show upon clicking a radio button:
Working earlier with a more inefficient method I got to sending commands to the server however the same error occurred when I tried to save the changes to the couchDB document specifically using db.save(doc) command.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(400, 300)
self.verticalLayoutWidget = QtWidgets.QWidget(Dialog)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(130, 80, 101, 80))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.rad2 = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.rad2.setObjectName("rad2")
self.group1 = QtWidgets.QButtonGroup(Dialog)
self.group1.setObjectName("group1")
self.group1.addButton(self.rad2)
self.verticalLayout.addWidget(self.rad2)
self.rad3 = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.rad3.setObjectName("rad3")
self.group1.addButton(self.rad3)
self.verticalLayout.addWidget(self.rad3)
self.rad1 = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.rad1.setObjectName("rad1")
self.group1.addButton(self.rad1)
self.verticalLayout.addWidget(self.rad1)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def printText(button):
print(button.text())
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.rad2.setText(_translate("Dialog", "RadioButton"))
self.rad3.setText(_translate("Dialog", "RadioButton"))
self.rad1.setText(_translate("Dialog", "RadioButton"))
ui.group1.buttonClicked.connect(self.printText)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())

You need to define the slot with a self argument:
def printText(self, button):
print(button.text())

Related

Pyinstaller and PyQt5 macOS Mojave compatibility issues

My application, created with Pyinstaller, worked fine until I upgraded from High Sierra to Mojave. In order to demonstrate the issue I create the simple application.
Main window has only one button. When you press the button its text should be changed to "Please wait" for 10 seconds.
When I run this program as .py script, everything works fine, but after creating .app file with Pyinstaller it behaves differently. The text is not updated until you click anywhere outside of the window.
I tried to reinstall Pyinstaller, but the problem still exists.
from PyQt5 import QtCore, QtGui, QtWidgets
import time
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(303, 304)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(50, 80, 300, 43))
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(80, 170, 113, 32))
self.pushButton.setObjectName("pushButton")
self.pushButton.setDefault(True)
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
self.pushButton.clicked.connect(self.click)
self.thread = Thread()
self.thread.finished.connect(lambda: self.pushButton.setEnabled(True))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "Click me"))
def click(self):
if not self.thread.isRunning():
self.pushButton.setEnabled(False)
self.pushButton.setText("Please wait")
self.label.setText("The button below should display \n 'Please wait' for 10 seconds")
self.thread.start()
class Thread(QtCore.QThread):
def run(self):
time.sleep(10)
ui.pushButton.setEnabled(False)
ui.pushButton.setText("Click me")
ui.label.setText("")
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 found an answer to my question. In order to solve this rendering issue you need to add the following line for a ui element, which needs to be updated. In my case it is required only if I need to run this application on macOS Mojave.
<element>.repaint()
For example:
def click(self):
self.pushButton.setEnabled(False)
self.pushButton.setText("Button is clicked...")
self.pushButton.repaint()

How pyqt use unittest to check login name and password and result?

my error message is
AttributeError: type object 'MainWindow' has no attribute
'nameLineEdit'
i try use pyqt unittest check login name and password (cause my project is pyqt5)
but many unittest are for not gui python project
so i google a tutorial(the tutorial is for pyqt4 but i will need use pyqt5)
http://johnnado.com/pyqt-qtest-example/
below is my project source code
https://drive.google.com/file/d/1gxVzY2yg83_y5OmHYUprsljMoP5xhbLT/view?usp=sharing
and i record my screen
https://youtu.be/yiMUGphm6fk
about project
my simple pyqt5 project to practice unittest to check login status
i follow a pyqt4 project tutorial ,but not work the project include three scripts
first script(main.py)
# -*- coding: utf-8 -*-
"""
Module implementing MainWindow.
"""
import sys
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtWidgets import QMainWindow, QApplication
from Ui_main import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
"""
Class documentation goes here.
"""
def __init__(self, parent=None):
"""
Constructor
#param parent reference to the parent widget
#type QWidget
"""
super(MainWindow, self).__init__(parent)
self.setupUi(self)
#pyqtSlot()
def on_loginButton_clicked(self):
if self.nameLineEdit.text()=='admin' and self.passwordLineEdit.text()=='123456':
self.loginStatusLabel.setText('Success Login')
else:
self.loginStatusLabel.setText('Failed Login')
if __name__=="__main__":
app=QApplication(sys.argv)
Main=MainWindow()
Main.show()
sys.exit(app.exec_())
second script (test_login.py)
import sys
import unittest
from PyQt5 import QtCore
from PyQt5.QtWidgets import QMainWindow, QApplication
from PyQt5.QtTest import QTest
import main
app = QApplication(sys.argv)
class test01(unittest.TestCase):
'''Test the margarita mixer GUI'''
def setUp(self):
print('inital ok')
def test_defaults(self):
self.nameLineEdit=main.MainWindow.nameLineEdit
self.passwordLineEdit=main.MainWindow.passwordLineEdit
loginButton = main.MainWindow.loginButton
self.assertEqual(self.nameLineEdit.text(), 'admin')
self.assertEqual(self.passwordLineEdit.text(), '123456')
QTest.mouseClick(loginButton, QtCore.Qt.LeftButton)
if __name__ == "__main__":
unittest.main()
third script(Ui_main)
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'F:\project\pyqt_unitest01\main.ui'
#
# Created by: PyQt5 UI code generator 5.10.1
#
# 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(302, 157)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.loginButton = QtWidgets.QPushButton(self.centralWidget)
self.loginButton.setGeometry(QtCore.QRect(200, 100, 81, 41))
font = QtGui.QFont()
font.setFamily("Agency FB")
font.setPointSize(16)
self.loginButton.setFont(font)
self.loginButton.setObjectName("loginButton")
self.nameLineEdit = QtWidgets.QLineEdit(self.centralWidget)
self.nameLineEdit.setGeometry(QtCore.QRect(110, 10, 181, 31))
font = QtGui.QFont()
font.setFamily("Agency FB")
font.setPointSize(16)
self.nameLineEdit.setFont(font)
self.nameLineEdit.setObjectName("nameLineEdit")
self.passwordLineEdit = QtWidgets.QLineEdit(self.centralWidget)
self.passwordLineEdit.setGeometry(QtCore.QRect(110, 60, 181, 31))
font = QtGui.QFont()
font.setFamily("Agency FB")
font.setPointSize(16)
self.passwordLineEdit.setFont(font)
self.passwordLineEdit.setObjectName("passwordLineEdit")
self.nameLabel = QtWidgets.QLabel(self.centralWidget)
self.nameLabel.setGeometry(QtCore.QRect(20, 10, 81, 31))
font = QtGui.QFont()
font.setFamily("Agency FB")
font.setPointSize(16)
self.nameLabel.setFont(font)
self.nameLabel.setObjectName("nameLabel")
self.passwordLabel = QtWidgets.QLabel(self.centralWidget)
self.passwordLabel.setGeometry(QtCore.QRect(20, 60, 81, 31))
font = QtGui.QFont()
font.setFamily("Agency FB")
font.setPointSize(16)
self.passwordLabel.setFont(font)
self.passwordLabel.setObjectName("passwordLabel")
self.loginStatusLabel = QtWidgets.QLabel(self.centralWidget)
self.loginStatusLabel.setGeometry(QtCore.QRect(20, 105, 141, 31))
font = QtGui.QFont()
font.setFamily("Agency FB")
font.setPointSize(16)
self.loginStatusLabel.setFont(font)
self.loginStatusLabel.setObjectName("loginStatusLabel")
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.loginButton.setText(_translate("MainWindow", "login"))
self.nameLabel.setText(_translate("MainWindow", "name"))
self.passwordLabel.setText(_translate("MainWindow", "password"))
self.loginStatusLabel.setText(_translate("MainWindow", "login_status"))
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_())
how to correct use unittest to test pyqt5 project (or any better idea or framework)
thank you everybody!!
The problem that you show is the little knowledge about OOP, the classes are abstractions or molds, they only serve to create objects, and that is what you have not done, so one part of the solution is to create an object of the MainWindow class.
On the other hand the testing is done to verify the correct functioning, in your case the verification could not occur in the QLineEdits since for this to have text you must place it, the correct thing is to verify the loginStatusLabel since the GUI is the one that has control about it, that is, the user places the username and password, clicks and consequently the indicated label must change.
import sys
import unittest
from PyQt5 import QtCore, QtWidgets, QtTest
from main import MainWindow
app = QtWidgets.QApplication(sys.argv)
class test01(unittest.TestCase):
'''Test the margarita mixer GUI'''
def setUp(self):
self.form = MainWindow()
def test_defaults(self):
self.form.nameLineEdit.setText('admin')
self.form.passwordLineEdit.setText('123456')
QtTest.QTest.mouseClick(self.form.loginButton, QtCore.Qt.LeftButton)
self.assertEqual(self.form.loginStatusLabel.text(), 'Success Login')
if __name__ == "__main__":
unittest.main()

update a python ui without rewrite all the button event

I'm looking for a better way to handle python UI "update" from QtDesigner without overwrite button event. The workflow I got now is:
Design UI layout in QtDesigner
convert .ui to .py by pyuic5
adding button event in .py file
excute .py to see window and button action
So if my UI keep changing the design, how do I keep all the button event I add into .py without being overwrite after convert? Thank you.
Answer my own question, what I found is have three python files. Main.py, CallUI.py and MainWindow.py. (Named as you want.)
So you can keep regenerate UI and override MainWindow.py without clear button event you wrote.
1.Main.py is the one to launch everything, name == "main". Call CAllUI.py's setup function.
#Main.py
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
import CallUI
def setUp():
CallUI.setUpWindow()
raw_input()
if __name__ == "__main__":
setUp()
2.CallUI.py is the one to use "QtWidgets.QApplication(sys.argv)" to show UI and add button click functions.
#CallUI.py
import sys
from MainWindow import Ui_Dialog
from PyQt5 import QtCore, QtGui, QtWidgets
import os
class CallUI(QtWidgets.QWidget):
def __init__(self):
QtWidgets.QWidget.__init__(self)
self.ui = Ui_Dialog()
self.ui.setupUi(self)
self.setUpBtnconnect()
def setUpBtnconnect(self):
self.ui.pushButton.clicked.connect(self.myFunction)
def myFunction(self):
os.system("ipconfig")
raw_input()
def setUpWindow():
app = QtWidgets.QApplication(sys.argv)
nowWindow = CallUI()
nowWindow.show()
sys.exit(app.exec_())
3.MainWindow.py is the one you converted from pyuic5, it's describe all the UI layout.
#MainWindow.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("MainWindow")
Dialog.resize(466, 417)
self.centralwidget = QtWidgets.QWidget(Dialog)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(160, 260, 75, 23))
self.pushButton.setObjectName("pushButton")
self.menubar = QtWidgets.QMenuBar(Dialog)
self.menubar.setGeometry(QtCore.QRect(0, 0, 466, 21))
self.menubar.setObjectName("menubar")
self.statusbar = QtWidgets.QStatusBar(Dialog)
self.statusbar.setObjectName("statusbar")
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
self.pushButton.setText(_translate("MainWindow", "PushButton"))

How to play video in a QVideoWidget promoted in Qt Designer?

I am a beginner in Qt. But following some tutorials I created a UI in qt designer which would display a live stream video. I have read that in order to add video i need to promote widget to a QVideoWidget. Then I convert the .ui to a .py file to access it using python language. The thing is once i have done that i dont know how to put the video in the widget that i made in the ui. Thank you.
The code below show the GUI.py file. I am importing it in another file where I would code it show the video. but dont know how thanks
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'facebio.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# 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(558, 388)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(280, 10, 261, 221))
self.listWidget.setObjectName("listWidget")
self.listWidget_2 = QtWidgets.QListWidget(self.centralwidget)
self.listWidget_2.setGeometry(QtCore.QRect(20, 240, 521, 101))
self.listWidget_2.setObjectName("listWidget_2")
self.widget = QVideoWidget(self.centralwidget)
self.widget.setGeometry(QtCore.QRect(20, 10, 241, 221))
self.widget.setObjectName("widget")
MainWindow.setCentralWidget(self.centralwidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
from PyQt5.QtMultimediaWidgets import QVideoWidget
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_())
You only have to inherit from the widget selected in Qt Designer and use the generated design, then use a QMediaPlayer and then set it to the QVideoWidget:
main.py
from PyQt5 import QtCore, QtGui, QtWidgets, QtMultimedia
from GUI import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, **kwargs):
QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
self.setupUi(self)
self.mediaPlayer = QtMultimedia.QMediaPlayer(self)
self.mediaPlayer.setVideoOutput(self.widget)
# fileName = "/path/of/your/local_file"
# url = QtCore.QUrl.fromLocalFile(fileName)
url = QtCore.QUrl("http://clips.vorwaerts-gmbh.de/VfE_html5.mp4")
self.mediaPlayer.setMedia(QtMultimedia.QMediaContent(url))
self.mediaPlayer.play()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())

Qt Designer UI (python) to JSON

I recently started using qt to build a python GUI. I have two problems I can't quite find the solutions to. the code below is a sample of what I need to build.
1: Check which radio button from a list of radio buttons in a vertical layout has been clicked. In the GUI it only selects one radio button out of all others available in the layout. How do I perceive which has been clicked?
2:I would like to add the clicked value to a JSON object but I believe that is a simple if statement of if this then that. Unless it's more complicated in which case please push me in the right direction.
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'test.ui'
#
# Created by: PyQt5 UI code generator 5.6
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Dialog(object):
def setupUi(self, Dialog):
Dialog.setObjectName("Dialog")
Dialog.resize(596, 466)
self.verticalLayoutWidget = QtWidgets.QWidget(Dialog)
self.verticalLayoutWidget.setGeometry(QtCore.QRect(180, 70, 61, 80))
self.verticalLayoutWidget.setObjectName("verticalLayoutWidget")
self.verticalLayout = QtWidgets.QVBoxLayout(self.verticalLayoutWidget)
self.verticalLayout.setContentsMargins(0, 0, 0, 0)
self.verticalLayout.setObjectName("verticalLayout")
self.that = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.that.setObjectName("that")
self.verticalLayout.addWidget(self.that)
self.thi = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.thi.setObjectName("thi")
self.verticalLayout.addWidget(self.thi)
self.sure = QtWidgets.QRadioButton(self.verticalLayoutWidget)
self.sure.setObjectName("sure")
self.verticalLayout.addWidget(self.sure)
self.retranslateUi(Dialog)
QtCore.QMetaObject.connectSlotsByName(Dialog)
def retranslateUi(self, Dialog):
_translate = QtCore.QCoreApplication.translate
Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
self.that.setText(_translate("Dialog", "that"))
self.thi.setText(_translate("Dialog", "this"))
self.sure.setText(_translate("Dialog", "sure"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
Dialog = QtWidgets.QDialog()
ui = Ui_Dialog()
ui.setupUi(Dialog)
Dialog.show()
sys.exit(app.exec_())
There is a nice way to solve this using Qt Designer, which allows you to group your buttons into a QButtonGroup, and then connect to its buttonClicked signal to get the button that was clicked.
All you need to do is, in Qt Designer, select all the buttons (using Ctrl+click), then right-click one of the buttons and select Assign to button group -> New button group. This will create a new button-group object and automatically add all the buttons to it.
After re-generating your gui module, you can then do somehting like this:
ui.radioButtonGroup.buttonClicked.connect(radioButtonClicked)
def radioButtonClicked(button):
print(button.text())
I think you need something like this (not tested)
# Set Default
self.thi.setChecked(True)
# create a signal
QtCore.QObject.connect(self.that,
QtCore.SIGNAL("toggled(bool)"),
self.radio_clicked)
then create a function
def self.radio_clicked(self):
print 'ive been clicked' # work from here

Categories

Resources