I'm new to GUI-programming and need help with a QThread application. I have a gui program that makes a query and lists the results of the query on the screen. I want an information dialog to open when the listing on the screen is finished. I wrote a function for this and when the operation is successful, it works without any problems. But I couldn't figure out how to show an error dialog if an invalid link entry occurs. Thank you for helping.
-I have commented out some of the methods I tried and failed.
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
from time import sleep
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 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.running = False
self.pushButton.clicked.connect(self.startBs4Worker)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "GET"))
def reveiceData(self, data):
# This method is the method that will
# process the data sent by the thread.
if data == None:
return
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
item.setText(_translate("MainWindow", data))
self.listWidget.addItem(item)
def setThreadStatus(self):
self.running = not self.running
def startBs4Worker(self):
if self.running:
print("Thread is still running ...")
return
else:
self.thread = QThread()
# We send the URL address that the thread will process as a parameter.
self.worker = Bs4Worker(url=self.lineEdit.text())
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.setThreadStatus)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.notifyProgress.connect(self.reveiceData)
self.worker.finished.connect(self.uyariBox) #---> With this place active, I couldn't figure out how to activate the Error message when wrong connection was entered.
self.running = True
self.thread.start()
def uyariBox(self):
self.msg = QMessageBox()
self.msg.thread()
self.msg.setWindowTitle("Bilgi !")
self.msg.setText("Tüm Sonuçlar Getirildi")
self.msg.setIcon(QMessageBox.Information)
self.msg.exec_()
class Bs4Worker(QThread):
notifyProgress = QtCore.pyqtSignal(str)
def __init__(self, url, parent=None):
QThread.__init__(self, parent)
self.url = url
def run(self):
try:
r = requests.get(self.url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
# Sending header information to master class
self.notifyProgress.emit(baslik)
self.finished.connect(ui.uyariBox) #---> When you activate this place, the warning appears instantly and disappears immediately.
#---> and there is no click anywhere in the app. (Since completion is not pressed in the warning message)
self.finished.emit()
# self.finished.connect(ui.uyariBox) #----> Warning does not appear when you activate this place.
except:
print("link error")
self.finished.emit()
# When I create a new QMessageBox to show the error message, the application crashes.
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())
You can pass the operation result as string to the uyariBox method.
First you can create another signal in Bs4Worker:
class Bs4Worker(QThread):
result = QtCore.pyqtSignal(str)
Change the previous worker.finished connection to worker.result:
def startBs4Worker(self):
else:
self.worker.result.connect(self.uyariBox)
#Previous was self.worker.finished.connect(self.uyariBox)
Add variable to function:
def uyariBox(self,message):
self.msg = QMessageBox()
self.msg.thread()
self.msg.setWindowTitle("Bilgi !")
self.msg.setText(message)
self.msg.setIcon(QMessageBox.Information)
self.msg.exec_()
Then use signal to pass on the result of the operation:
def run(self):
try:
self.result.emit("Tüm Sonuçlar Getirildi")
except Exception as e:
self.result.emit(f"Error: {e}")
Full code:
import sys
import requests
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow, QApplication, QMessageBox
from bs4 import BeautifulSoup
from time import sleep
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(476, 391)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(0, 270, 471, 81))
self.pushButton.setObjectName("pushButton")
self.lineEdit = QtWidgets.QLineEdit(self.centralwidget)
self.lineEdit.setGeometry(QtCore.QRect(0, 0, 471, 31))
self.lineEdit.setObjectName("lineEdit")
self.listWidget = QtWidgets.QListWidget(self.centralwidget)
self.listWidget.setGeometry(QtCore.QRect(0, 50, 471, 192))
self.listWidget.setObjectName("listWidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 476, 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.running = False
self.pushButton.clicked.connect(self.startBs4Worker)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.pushButton.setText(_translate("MainWindow", "GET"))
def reveiceData(self, data):
# This method is the method that will
# process the data sent by the thread.
if data == None:
return
_translate = QtCore.QCoreApplication.translate
item = QtWidgets.QListWidgetItem()
font = QtGui.QFont()
font.setFamily("Arial")
font.setPointSize(11)
item.setFont(font)
item.setCheckState(QtCore.Qt.Checked)
item.setText(_translate("MainWindow", data))
self.listWidget.addItem(item)
def setThreadStatus(self):
self.running = not self.running
def startBs4Worker(self):
if self.running:
print("Thread is still running ...")
return
else:
self.thread = QThread()
# We send the URL address that the thread will process as a parameter.
self.worker = Bs4Worker(url=self.lineEdit.text())
self.worker.moveToThread(self.thread)
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.worker.finished.connect(self.setThreadStatus)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.notifyProgress.connect(self.reveiceData)
self.worker.result.connect(
self.uyariBox) # ---> With this place active, I couldn't figure out how to activate the Error message when wrong connection was entered.
self.running = True
self.thread.start()
def uyariBox(self,message):
self.msg = QMessageBox()
self.msg.thread()
self.msg.setWindowTitle("Bilgi !")
self.msg.setText(message)
self.msg.setIcon(QMessageBox.Information)
self.msg.exec_()
class Bs4Worker(QThread):
result = QtCore.pyqtSignal(str)
notifyProgress = QtCore.pyqtSignal(str)
def __init__(self, url, parent=None):
QThread.__init__(self, parent)
self.url = url
def run(self):
try:
r = requests.get(self.url)
soup = BeautifulSoup(r.content)
linkler = soup.find_all("a")
for link in linkler:
baslik = link.get("title")
# Sending header information to master class
self.notifyProgress.emit(baslik)
self.finished.connect(
ui.uyariBox) # ---> When you activate this place, the warning appears instantly and disappears immediately.
# ---> and there is no click anywhere in the app. (Since completion is not pressed in the warning message)
self.finished.emit()
self.result.emit("Tüm Sonuçlar Getirildi")
# self.finished.connect(ui.uyariBox) #----> Warning does not appear when you activate this place.
except Exception as e:
print("link error")
self.finished.emit()
self.result.emit(f"Error: {e}")
# When I create a new QMessageBox to show the error message, the application crashes.
Uygulama = QApplication(sys.argv)
menu = QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(menu)
menu.show()
sys.exit(Uygulama.exec_())
Related
We are creating an object detection project using Object detection API. We are train the program making pyqt5 GUI application. Trying to run the training part using thread. We want to stop the running thread using a push button. Here the code sample
class stopClass(QtCore.QThread):
def __init__(self, parent=None):
super(stopClass, self).__init__(parent)
def startTrain(self):
#changing directory
os.chdir(r"c://tensorflow_1//models//research//object_detection")
args3 = shlex.split('python train.py --logtostderr --train_dir=training/ --
pipeline_config_path=training/faster_rcnn_inception_v2_pets.config')
subprocess.run(args3, shell = True)
return
def run(self):
self.startTrain()
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(701, 495)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.Annotation = QtWidgets.QPushButton(self.centralwidget)
self.Annotation.setGeometry(QtCore.QRect(480, 10, 181, 41))
self.Annotation.setToolTip("")
self.Annotation.setObjectName("Annotation")
self.Start_train = QtWidgets.QPushButton(self.centralwidget)
self.Start_train.setGeometry(QtCore.QRect(480, 110, 181, 41))
self.Start_train.setObjectName("Start_train")
self.Stop_train = QtWidgets.QPushButton(self.centralwidget)
self.Stop_train.setEnabled(False)
self.Stop_train.setGeometry(QtCore.QRect(480, 160, 181, 41))
self.Stop_train.setObjectName("Stop_train")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 701, 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.Start_train.clicked.connect(self.starting)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Start_train.setText(_translate("MainWindow", "start train"))
self.Stop_train.setText(_translate("MainWindow", "stop train"))
def starting(self):
self.stopThread = stopClass()
self.stopThread.start()
self.Stop_train.setEnabled(True)
self.Stop_train.clicked.connect(self.stopThread.exit)
self.Start_train.setEnabled(False)
In this case I do not see the need to use threads since it is enough to use QProcess that allows a simple handling of the execution of the script. On the other hand, do not modify the script generated by pyuic so my solution assumes that you must recreate that script that must be called gui.py:
import shlex
import sys
from PyQt5.QtCore import QObject, QProcess
from PyQt5.QtWidgets import QApplication, QMainWindow
from gui import Ui_MainWindow
class Manager(QObject):
def __init__(self, parent=None):
super().__init__(parent)
self._process = QProcess()
working_directory = r"c://tensorflow_1//models//research//object_detection"
self.process.setWorkingDirectory(working_directory)
self.process.setProgram(sys.executable)
args = shlex.split(
"train.py --logtostderr --train_dir=training/ --pipeline_config_path=training/faster_rcnn_inception_v2_pets.config"
)
self.process.setArguments(args)
#property
def process(self):
return self._process
def start(self):
if self.process.state() == QProcess.NotRunning:
self.process.start()
def stop(self):
if self.process.state() != QProcess.NotRunning:
self.process.kill()
class MainWindow(QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.manager = Manager()
self.Start_train.clicked.connect(self.manager.start)
self.Stop_train.clicked.connect(self.manager.stop)
self.manager.process.stateChanged.connect(self._handle_stateChanged)
def _handle_stateChanged(self, state):
self.Start_train.setEnabled(state != QProcess.Running)
self.Stop_train.setEnabled(state == QProcess.Running)
def main():
app = QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I have a 2 classes
1. Main_window another is Load_file_window.
When I Press a Load_file option in my Mainwindow, it should open Load_file_window and browse the file and send the file name to my main windows both are 2 different classes. I'm able to browse the file from Load_file_window but when I tried to pass that value to Mainwindow its not happening.
How can I proceed with this?
This code will run in windows machine, with Python PyQt5 Module
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import (QInputDialog,QFileDialog,QMessageBox,QWidget)
class Ui_Load_FILE(QWidget):
def _init__(self,parent=None):
super().__init__()
self.parent=parent
self.Loaded_File_data=[]
def setupUi(self, Load_FILE):
Load_FILE.setObjectName("Load_FILE")
Load_FILE.resize(581, 89)
self.Load_group_box = QtWidgets.QGroupBox(Load_FILE)
self.Load_group_box.setGeometry(QtCore.QRect(10, 0, 561, 81))
self.Load_group_box.setTitle("")
self.Load_group_box.setObjectName("groupBox")
self.Load_progressBar = QtWidgets.QProgressBar(self.Load_group_box)
self.Load_progressBar.setGeometry(QtCore.QRect(10, 50, 471, 16))
self.Load_progressBar.setProperty("value", 0)
self.Load_progressBar.setObjectName("progressBar")
self.Import_button = QtWidgets.QPushButton(self.Load_group_box)
self.Import_button.setGeometry(QtCore.QRect(480, 10, 75, 23))
self.Import_button.setObjectName("Import_button")
self.File_Name= self.Import_button.clicked.connect (self.openFileNameDialog)
#self.pushButton.clicked.connect()
self.Input_textBox = QtWidgets.QLineEdit(self.Load_group_box)
self.Input_textBox.setGeometry(QtCore.QRect(60, 10, 411, 31))
self.Input_textBox.setObjectName("Input_textBox")
self.Input_txtbx_lbl = QtWidgets.QLabel(self.Load_group_box)
self.Input_txtbx_lbl.setGeometry(QtCore.QRect(10, 20, 47, 13))
self.Input_txtbx_lbl.setObjectName("Input_txtbx_lbl")
self.Load_button = QtWidgets.QPushButton(self.Load_group_box)
self.Load_button.setGeometry(QtCore.QRect(480, 50, 75, 23))
self.Load_button.setObjectName("Load_button")
self.File1=self.Load_button.clicked.connect(self.Load_Action)
self.retranslateUi(Load_FILE)
QtCore.QMetaObject.connectSlotsByName(Load_FILE)
return self.File1
def retranslateUi(self, Load_FILE):
_translate = QtCore.QCoreApplication.translate
Load_FILE.setWindowTitle(_translate("Load_FILE", "Load File"))
self.Import_button.setText(_translate("Load_FILE", "Import"))
self.Input_txtbx_lbl.setText(_translate("Load_FILE", "Load_File"))
self.Load_button.setText(_translate("Load_FILE", "Load"))
def openFileNameDialog(self):
'''Opens Files diralog to browse the data'''
fileName=QFileDialog.getOpenFileName(caption='Open file',directory='.',filter="FILE Files (*.std *.FILE);;All Files (*.*)")
if fileName[0]!='':
self.Input_textBox.setText(fileName[0])
else:
msg='Please select a File'
self.Messagebox(msg,'info','Please select a File')
return fileName
def Load_Action(self,Load_FILE):
self.File_Name=self.Input_textBox.text()
if self.File_Name:
print(self.File_Name)
return self.File_Name
else:
self.Messagebox('Please browse a file then try to load the file','info','Please select a file before you load')
def Messagebox(self,msg_text,msgtype='info',title='Message Box'):
''' Message is a function to call the message box in PyQt Quickly. msgtype can be (info, warn,que,criti).
msg_text is the msg you want to display, Title will be window Title'''
if msgtype=='info':
reply=QMessageBox.information(self,title,msg_text,QMessageBox.Ok ,QMessageBox.Ok)
elif msgtype=='warn':
reply=QMessageBox.warning(self,title,msg_text,QMessageBox.Ok ,QMessageBox.Ok)
elif msgtype=='que':
reply=QMessageBox.question(self,title,msg_text,QMessageBox.Yes | QMessageBox.No ,QMessageBox.Yes)
elif msgtype=='criti':
reply=QMessageBox.critical(self,title,msg_text,QMessageBox.Ok | QMessageBox.Cancel ,QMessageBox.Ok)
return reply
## THIS IS MY LOAD_FILE_WINDOW CODE
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'Tool_Main_Frame.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
from PyQt5.QtWidgets import (QInputDialog,QFileDialog,QMessageBox,QWidget,QMainWindow,QDialog)
from Load_FILE import Ui_Load_FILE
class Ui_MainWindow(QMainWindow):
def __init__(self):
super().__init__()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1390, 914)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1390, 21))
self.menubar.setObjectName("menubar")
self.File = QtWidgets.QMenu(self.menubar)
self.File.setObjectName("File")
self.Menu = QtWidgets.QMenu(self.menubar)
self.Menu.setObjectName("Menu")
self.View = QtWidgets.QMenu(self.menubar)
self.View.setObjectName("View")
self.Data = QtWidgets.QMenu(self.menubar)
self.Data.setObjectName("Data")
#self.Data.setShortcut('Alt+D')
self.Export = QtWidgets.QMenu(self.Data)
self.Export.setObjectName("Export")
self.Import = QtWidgets.QMenu(self.Data)
self.Import.setObjectName("Import")
#self.Import.setShortcut('Ctrl+I')
self.Help = QtWidgets.QMenu(self.menubar)
self.Help.setObjectName("Help")
self.Editmenu=QtWidgets.QMenu(self.menubar)
self.Editmenu.setObjectName("Edit")
MainWindow.setMenuBar(self.menubar)
self.statusbar = QtWidgets.QStatusBar(MainWindow)
self.statusbar.setObjectName("statusbar")
MainWindow.setStatusBar(self.statusbar)
self.Load = QtWidgets.QAction(MainWindow)
self.Load.setObjectName("Load")
self.Save = QtWidgets.QAction(MainWindow)
self.Save.setObjectName("Save")
self.Save.setShortcut("Ctrl+S")
self.Save_As = QtWidgets.QAction(MainWindow)
self.Save_As.setObjectName("Save_As")
self.Save_As.setShortcut("Ctrl+Shift+S")
self.Exit = QtWidgets.QAction(MainWindow)
self.Exit.setObjectName("Exit")
self.Exit.setShortcut("Ctrl+Q")
self.Exit.triggered.connect(self.Exit_the_main_window)
self.Open = QtWidgets.QAction(MainWindow)
self.Open.setObjectName("Open")
self.Open.setShortcut("Ctrl+O")
self.Load_CSV = QtWidgets.QAction(MainWindow)
self.Load_CSV.setObjectName("Load_CSV")
self.Export_Excel = QtWidgets.QAction(MainWindow)
self.Export_Excel.setObjectName("Export_Excel")
self.Export_CSV = QtWidgets.QAction(MainWindow)
self.Export_CSV.setObjectName("Export_CSV")
self.Export_TXT = QtWidgets.QAction(MainWindow)
self.Export_TXT.setObjectName("Export_TXT")
self.Load_FILE = QtWidgets.QAction(MainWindow)
self.Load_FILE.setObjectName("Load_FILE")
k=self.Load_FILE.triggered.connect(self.Open_Load_Action)
self.Load_FILE.setShortcut('Ctrl+L')
self.Load_Excel = QtWidgets.QAction(MainWindow)
self.Load_Excel.setObjectName("Load_Excel")
self.Load_Txt = QtWidgets.QAction(MainWindow)
self.Load_Txt.setObjectName("Load_Txt")
self.File.addAction(self.Open)
self.File.addAction(self.Save)
self.File.addAction(self.Save_As)
self.File.addAction(self.Exit)
self.Export.addAction(self.Export_Excel)
self.Export.addAction(self.Export_CSV)
self.Export.addAction(self.Export_TXT)
self.Import.addAction(self.Load_FILE)
self.Import.addAction(self.Load_Excel)
self.Import.addAction(self.Load_Txt)
self.Data.addAction(self.Import.menuAction())
self.Data.addAction(self.Export.menuAction())
self.Help.addSeparator()
self.menubar.addAction(self.File.menuAction())
self.menubar.addAction(self.Menu.menuAction())
self.menubar.addAction(self.Editmenu.menuAction())
self.menubar.addAction(self.View.menuAction())
self.menubar.addAction(self.Data.menuAction())
self.menubar.addAction(self.Help.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "TOOL_TOOL"))
self.File.setTitle(_translate("MainWindow", "File"))
self.Menu.setTitle(_translate("MainWindow", "Menu"))
self.View.setTitle(_translate("MainWindow", "View"))
self.Data.setTitle(_translate("MainWindow", "Data"))
self.Export.setTitle(_translate("MainWindow", "Export"))
self.Import.setTitle(_translate("MainWindow", "Import"))
self.Help.setTitle(_translate("MainWindow", "Help"))
self.Editmenu.setTitle(_translate('MainWindow','Edit'))
self.Save.setText(_translate("MainWindow", "Save"))
self.Save_As.setText(_translate("MainWindow", "Save As.."))
self.Exit.setText(_translate("MainWindow", "Exit"))
self.Open.setText(_translate("MainWindow", "Open"))
self.Load_CSV.setText(_translate("MainWindow", "Load_CSV"))
self.Export_Excel.setText(_translate("MainWindow", "Export_Excel"))
self.Export_CSV.setText(_translate("MainWindow", "Export_CSV"))
self.Export_TXT.setText(_translate("MainWindow", "Export_TXT"))
self.Load_FILE.setText(_translate("MainWindow", "Load_FILE"))
self.Load_Excel.setText(_translate("MainWindow", "Load_Excel"))
self.Load_Txt.setText(_translate("MainWindow", "Load_Txt"))
def Open_Load_Action(self):
self.Load_FILE = QDialog()
self.Load_FILE_ui = Ui_Load_FILE()
self.Load_FILE_ui.setupUi(self.Load_FILE)
self.Load_FILE.show()
self.Load_FILE.exec_() #<<----- After this all my code is not working as I wanted
def Exit_the_main_window(self):
sys.exit(Main_Application.exec_())
def Launch_app():
import sys
Main_Application = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
First_time_loading=True
ui_Main_Window = Ui_MainWindow()
ui_Main_Window.setupUi(MainWindow)
MainWindow.show()
if First_time_loading==True:
First_time_loading=False
sys.exit(Main_Application.exec_())
Launch_app()
This is my Main File
I'm expecting the file selected in load file to come into my main windows but its not happening and the windows also not getting closed.
I have an app with two buttons start and end. The start button will start a thread, which runs the audio recording function. This function is written using sounddevice and soundfile libraries. The audio recording can take place for an arbitary duration and the user can stop anytime by pressing ctrl+c.
So, now I want to implement a function for the end button to stop the thread which started by pressing start button or the function can send ctrl+c signal to the thread. So, that the current recording will be stopped. I am not sure how to achieve this. Any help is appreciated.
The code consisting in two .py is as it follows:
audio_record.py
import os
import signal
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import time
import queue
from PyQt5 import QtCore, QtGui, QtWidgets
import soundfile as sf
import sounddevice as sd
import mythreading
class Ui_MainWindow(object):
def __init__(self):
self.threadpool = QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(280, 190, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton.clicked.connect(self.start_button_func)
self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_1.setGeometry(QtCore.QRect(380, 190, 75, 23))
self.pushButton_1.setObjectName("pushButton")
self.pushButton_1.clicked.connect(self.end_button_func)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 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"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.pushButton_1.setText(_translate("MainWindow", "End"))
def record(self):
self.pid = os.getpid()
self.q = queue.Queue()
self.s = sd.InputStream(samplerate=48000, channels=2, callback=self.callback)
try:
# Make sure the file is open before recording begins
with sf.SoundFile('check.wav', mode='x', samplerate=48000, channels=2, subtype="PCM_16") as file:
with self.s:
# 1 second silence before the recording begins
time.sleep(1)
print('START')
print('#' * 80)
print('press Ctrl+C to stop the recording')
while True:
file.write(self.q.get())
except OSError:
print('The file to be recorded already exists.')
sys.exit(1)
def callback(self, indata, frames, time, status):
"""
This function is called for each audio block from the record function.
"""
if status:
print(status, file=sys.stderr)
self.q.put(indata.copy())
def start_button_func(self):
self.worker = mythreading.Worker(self.record)
self.threadpool.start(self.worker)
def end_button_func(self):
print('how to stop?')
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_())
mythreading.py is as follows:
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
class Worker(QRunnable):
def __init__(self, fn, *args, **kwargs):
super(Worker, self).__init__()
self.fn = fn
#pyqtSlot()
def run(self):
self.fn()
You have to use a flag, in this case threading.Event() to indicate that the thread should no longer be executed. For the case of Ctrl + C you must use QShortcut
import os
import queue
from PyQt5 import QtCore, QtGui, QtWidgets
import soundfile as sf
import sounddevice as sd
import mythreading
import threading
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(640, 480)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton(self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(280, 190, 75, 23))
self.pushButton.setObjectName("pushButton")
self.pushButton_1 = QtWidgets.QPushButton(self.centralwidget)
self.pushButton_1.setGeometry(QtCore.QRect(380, 190, 75, 23))
self.pushButton_1.setObjectName("pushButton")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 640, 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"))
self.pushButton.setText(_translate("MainWindow", "Start"))
self.pushButton_1.setText(_translate("MainWindow", "End"))
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
self.setupUi(self)
self.threadpool = QtCore.QThreadPool()
print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount())
self.pushButton.clicked.connect(self.start_button_func)
self.pushButton_1.clicked.connect(self.end_button_func)
self.event_stop = threading.Event()
QtWidgets.QShortcut("Ctrl+C", self, activated=self.end_button_func)
def record(self):
self.pid = os.getpid()
self.q = queue.Queue()
self.s = sd.InputStream(samplerate=48000, channels=2, callback=self.callback)
try:
# Make sure the file is open before recording begins
with sf.SoundFile('check.wav', mode='x', samplerate=48000, channels=2, subtype="PCM_16") as file:
with self.s:
# 1 second silence before the recording begins
QtCore.QThread.sleep(1)
print('START')
print('#' * 80)
print('press Ctrl+C to stop the recording')
while not self.event_stop.is_set():
file.write(self.q.get())
print("STOP")
except OSError:
print('The file to be recorded already exists.')
sys.exit(1)
def callback(self, indata, frames, time, status):
if status:
print(status, file=sys.stderr)
self.q.put(indata.copy())
#QtCore.pyqtSlot()
def start_button_func(self):
print("start")
self.worker = mythreading.Worker(self.record)
self.threadpool.start(self.worker)
#QtCore.pyqtSlot()
def end_button_func(self):
print('how to stop?')
self.event_stop.set()
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
I have a problem with interfacing the Arduino. I can communicate with the Arduino with a simple program like reading the data and writing them. I have created an interface using PyQt5 to control a servo motor and I get the error:
'Ui_MainWindow' object has no attribute 'ser'
The code I used is:
from PyQt5 import QtCore, QtGui, QtWidgets
import serial
import time
import sys
class Ui_MainWindow(object):
def setupUi(self, MainWindow, ser):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(318, 309)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.pushButton = QtWidgets.QPushButton("pushButton", self.centralwidget)
self.pushButton.setGeometry(QtCore.QRect(120, 40, 85, 27))
self.pushButton.clicked.connect(self.OpenShutter)
self.pushButton_2 = QtWidgets.QPushButton("pushButton_2", self.centralwidget)
self.pushButton_2.setGeometry(QtCore.QRect(120, 150, 85, 27))
self.pushButton_2.clicked.connect(self.CloseShutter)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 318, 20))
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"))
self.pushButton.setText(_translate("MainWindow", "Open"))
self.pushButton_2.setText(_translate("MainWindow", "Close"))
def CloseShutter(self):
print("Shutter Closed")
self.ser.write(int(0))
def OpenShutter(self):
print("Shutter Opened")
self.ser.write(int(77))
if __name__ == "__main__":
ser = serial.Serial()
ser.port = '/dev/ttyACM0'
ser.timeout = 1
ser.baudrate = 9600
if ser.isOpen() == False:
ser.open()
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow, ser)
MainWindow.show()
sys.exit(app.exec_())
The problem is that ser is not a member of the class so it will only exist in the context of the method, not in the context of the class.
The most recommended is not to modify the design and create a class that implements the logic, and in that class make a member of the class to the serial object. So I recommend not to modify the Ui_MainWindow class and restore it to the initial state.
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtWidgets.QMainWindow.__init__(self, parent)
self.setupUi(self)
self.ser = serial.Serial()
self.ser.port = '/dev/ttyACM0'
self.ser.timeout = 1
self.ser.baudrate = 9600
if self.ser.isOpen() == False:
self.ser.open()
def CloseShutter(self):
print("Shutter Closed")
self.ser.write(int(0))
def OpenShutter(self):
print("Shutter Opened")
self.ser.write(int(77))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
so basically i have programs that are meant to show the progress of reading an excel file line by line in the background. So far i have the following code:
excelresult.py:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import Qt, QBasicTimer
import os, sys, xlrd, threading, time, pythoncom
import win32com.client
from time import sleep
from test import MyGlobals
class ExcelCheck(threading.Thread):
progPercent = 0
def __init__(self):
threading.Thread.__init__(self)
self.event = threading.Event()
def run(self):
pythoncom.CoInitialize()
try:
while not self.event.is_set():
excel = win32com.client.Dispatch("Excel.Application")
wb = excel.ActiveWorkbook
ws = wb.Worksheets("TC")
va_title = ws.Range(ws.Range('I7'), ws.Range('I700'))
i = 0
for r in va_title.Cells:
if r.Text != '':
i = i + 1
# print(r.Text)
# print(i)
# print(round(i / 178.0 * 100,0))
# rounding off
progPercent = round(i / 178.0 * 100.0)
MyGlobals.x=progPercent
print(progPercent)
return progPercent
except:
print('Excel is not executed')
# sleep(1)
# self.event.wait()
def stop(self):
self.event.set()
scm.py
# -*- coding: utf-8 -*-
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import QObject, pyqtSignal
from PyQt5.QtCore import Qt, QBasicTimer
import os, sys, xlrd, win32com.client, xlwt, threading, time
from time import sleep
from ExcelResult import *
from test import MyGlobals
import threading
class Ui_MainWindow(object):
def __init__(self):
super().__init__()
self.btn_active = False
print('init_false')
def startBtnClicked(self):
self.btnStart.setText('start!')
self.btn_active = True
print(self.btn_active)
tmr = ExcelCheck()
tmr.start()
while(MyGlobals.x<=100):
#print (MyGlobals.x)
self.progressBar.setValue(MyGlobals.x)
# self.progressBar.minimum = 1
# self.progressBar.maximum = 100
# for progPercent in range(1, 101):
# self.progressBar.setValue(progPercent)
# time.sleep(1)
def exitBtnClicked(self):
# self.ExcelCheck()
self.btn_active = False
print(self.btn_active)
# os.system("taskkill /f /im Scm21.Client.exe")
# self.close()
# Stop the progress of python
self.sys.exit()
tmr = ExcelCheck()
tmr.stop()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(446, 207)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(40, 70, 381, 23))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.btnStart = QtWidgets.QPushButton(self.centralwidget)
self.btnStart.setGeometry(QtCore.QRect(110, 110, 75, 23))
self.btnStart.setObjectName("btnStart")
self.btnStart.clicked.connect(self.startBtnClicked)
self.btnExit = QtWidgets.QPushButton(self.centralwidget)
self.btnExit.setGeometry(QtCore.QRect(260, 110, 75, 23))
self.btnExit.setObjectName("btnExit")
self.btnExit.clicked.connect(self.exitBtnClicked)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 446, 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", "SCM21"))
self.btnStart.setText(_translate("MainWindow", "Start"))
self.btnExit.setText(_translate("MainWindow", "Exit"))
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_())
and, test.py
class MyGlobals(object):
x = 0
So, i am able to get the value of the ProgPercent from the ExcelResult.py into the scm.py using the test.py but completely not aware how would i update the progressbar value.
I tried using a loop but it hangs the GUI.
Thanks.
Use Qthread:
import time
from PyQt5 import QtCore
from PyQt5 import QtWidgets
class ExcelCheck(QtCore.QThread):
updated = QtCore.pyqtSignal(int)
running = False
def __init__(self, parent=None):
super(ExcelCheck, self).__init__(parent)
self.progPercent = 0
self.running = True
def run(self):
while self.running:
self.progPercent += 1
self.progPercent %= 100
self.updated.emit(int(self.progPercent))
time.sleep(0.1)
def stop(self):
self.running = False
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent=parent)
self.setupUi(self)
self.btn_active = False
def startBtnClicked(self):
self.btnStart.setText('start!')
self.btn_active = True
self.tmr = ExcelCheck(self)
self.tmr.updated.connect(self.updateValue)
self.tmr.start()
def updateValue(self, data):
self.progressBar.setValue(data)
def exitBtnClicked(self):
# self.ExcelCheck()
self.btn_active = False
self.tmr.stop()
self.sys.exit()
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(446, 207)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.progressBar = QtWidgets.QProgressBar(self.centralwidget)
self.progressBar.setGeometry(QtCore.QRect(40, 70, 381, 23))
self.progressBar.setProperty("value", 0)
self.progressBar.setObjectName("progressBar")
self.btnStart = QtWidgets.QPushButton(self.centralwidget)
self.btnStart.setGeometry(QtCore.QRect(110, 110, 75, 23))
self.btnStart.setObjectName("btnStart")
self.btnStart.clicked.connect(self.startBtnClicked)
self.btnExit = QtWidgets.QPushButton(self.centralwidget)
self.btnExit.setGeometry(QtCore.QRect(260, 110, 75, 23))
self.btnExit.setObjectName("btnExit")
self.btnExit.clicked.connect(self.exitBtnClicked)
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 446, 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", "SCM21"))
self.btnStart.setText(_translate("MainWindow", "Start"))
self.btnExit.setText(_translate("MainWindow", "Exit"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())