Ignore KeyboardInterrupt after closing a QProcess with a CTRL_C_EVENT - python

How can I ignore a KeyboardInterrupt after I used a CTRL_C_EVENT in Python? I only need CTRL_C_EVENT to close the Qprocess and not the PyQt5 window. I tried making an exception for KeyboardInterrupt but I still get the error.
I understand that CTRL_C_EVENT isn't the best option, if you want to keep PyQt5 running, however, the QProcess .exe only responds to that command. Can you help me? I made a sample code below:
import sys
import os
from PyQt5.QtWidgets import QMainWindow, QApplication, QHBoxLayout, QPushButton
from PyQt5.QtCore import QProcess
from signal import CTRL_C_EVENT
class main(QMainWindow):
def __init__(self):
super(main, self).__init__()
self.resize(1000, 800)
self.hLayout = QHBoxLayout(self)
self.process = QProcess()
self.stop_btn = QPushButton('stop process')
self.stop_btn.clicked.connect(self.finishProcess)
self.hLayout.addWidget(self.stop_btn )
self.setLayout(self.hLayout)
path = 'C:\...\.exe'
self.processOffline.start(path)
self.pid = self.processOffline.processId()
def finishProcess(self):
os.kill(self.pid, CTRL_C_EVENT)
try:
self.processOffline.waitForFinished()
except KeyboardInterrupt:
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
w = main()
w.show()
sys.exit(app.exec_())

Related

PyQt5, asyncqt | asyncSlot() still freezes the event loop

The problem is that even though I put the function in a separate thread, the window still does not respond to actions until it is fully executed. What is the problem? Just ctrl+c, ctrl+v the code below, you will see what i mean. If you have any questions, feel free to ask
import sys
import asyncio
from asyncqt import QEventLoop, asyncSlot
from pytube import YouTube
import time
from PyQt5.QtWidgets import (
QApplication, QWidget, QLabel, QLineEdit, QTextEdit, QPushButton,
QVBoxLayout)
class MainWindow(QWidget):
def __init__(self):
super().__init__()
self.setLayout(QVBoxLayout())
self.lblStatus = QLabel('Idle', self)
self.layout().addWidget(self.lblStatus)
self.editUrl = QLineEdit('Hi!', self)
self.layout().addWidget(self.editUrl)
self.editResponse = QTextEdit('', self)
self.layout().addWidget(self.editResponse)
self.btnFetch = QPushButton('Fetch', self)
self.btnFetch.clicked.connect(self.on_btnFetch_clicked)
self.layout().addWidget(self.btnFetch)
#asyncSlot()
async def on_btnFetch_clicked(self):
self.lblStatus.setText('downloading...')
yt = YouTube('https://www.youtube.com/watch?v=zG4uYN3n8zs')
yt.streams.filter(resolution='720p').first().download('C:/Users/Andrew/Desktop')
self.lblStatus.setText('downloaded!')
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
loop = QEventLoop(app)
asyncio.set_event_loop(loop)
with loop:
sys.exit(loop.run_forever())
Function time.sleep(5) is blocking, and await asyncio.sleep(5) is non-blocking.

Restarting PyQt app in PyCharm with QProcess

Button click starts a new detached process of the same app. However, when launched from PyCharm, it crashes on second restart. Print is no longer visible after restart as well.
I want my app to be able to restart many times when launched from either PyCharm or cmd.
import sys, os
from PyQt5.QtCore import QProcess
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
button = QPushButton("Restart")
button.clicked.connect(self.restart)
self.setCentralWidget(button)
def restart(self):
print("Restart")
self.close()
proc = QProcess()
proc.startDetached(sys.executable, sys.argv)
def main():
app = QApplication(sys.argv)
window = MainWindow()
window.show()
app.exec()
if __name__ == "__main__":
main()

Script is still running after closing pyqt5 window

import sys
import requests
from PyQt5.uic import loadUi
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QDialog, QApplication
class MainWindow(QDialog):
def __init__(self):
super(MainWindow, self).__init__()
loadUi("tabletutorial.ui",self)
self.request_function()
def request_function(self):
for i in range(0,100):
resp=requests.get("https://www.google.com")
print(resp.status_code)
# main
app = QApplication(sys.argv)
mainwindow = MainWindow()
widget = QtWidgets.QStackedWidget()
widget.addWidget(mainwindow)
widget.setFixedHeight(850)
widget.setFixedWidth(1120)
widget.show()
try:
sys.exit(app.exec_())
except:
print("Exiting")
This window is created by another main window.
Now the problem is when i quit the pyqt5 window the script is still running and i am getting the status code .I am running a big application with a bunch of requests.Anyone with relatable solution please ?
I TRIED:
self.close() not worked for me. #QtCore.pyqtSlot() also not worked.
I am new to here . Please ignore mistakes and kind answer are appriciated.

How to keep PyQt5 responsive when calling gnuplot?

I am trying to create plots with a Python GUI and gnuplot.
I am generating the code in Python and send it to gnuplot.
This basically works with piping data to gnuplot, but:
Disadvantages:
the Python program is blocked until you close gnuplot
you have to load/start gnuplot again and again everytime you're making a plot which seems to take annoying extra time (on slow computers)
My questions:
how to keep the Python program responsive?
is there a way to start gnuplot once and keep it running?
how to just update the gnuplot terminal if there is a new plot?
Thank you for hints and links.
Here is my code:
import sys
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPlainTextEdit, QPushButton
import subprocess
class MyWindow(QWidget):
def __init__(self):
super(MyWindow,self).__init__()
self.setGeometry(100,100,400,200)
self.myTextEdit = QPlainTextEdit()
self.myTextEdit.setPlainText("plot sin(x)")
self.button = QPushButton('Plot code',self)
self.button.clicked.connect(self.on_button_click)
vbox = QVBoxLayout(self)
vbox.addWidget(self.myTextEdit)
vbox.addWidget(self.button)
self.setLayout(vbox)
#pyqtSlot()
def on_button_click(self):
gnuplot_str = self.myTextEdit.document().toPlainText() + "\n"
gnuplot_path = r'C:\Programs\gnuplot\bin\gnuplot.exe'
plot = subprocess.Popen([gnuplot_path,'-p'],stdin=subprocess.PIPE)
plot.communicate(gnuplot_str.encode())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
Instead of using subprocess you must use QProcess which is friendly to the Qt event loop as I show below:
import sys
from PyQt5.QtCore import QProcess, pyqtSlot
from PyQt5.QtWidgets import QApplication, QWidget, QVBoxLayout, QPlainTextEdit, QPushButton
class MyWindow(QWidget):
def __init__(self):
super(MyWindow,self).__init__()
self.setGeometry(100,100,400,200)
self.myTextEdit = QPlainTextEdit()
self.myTextEdit.setPlainText("plot sin(x)")
self.button = QPushButton('Plot code',self)
self.button.clicked.connect(self.on_button_click)
vbox = QVBoxLayout(self)
vbox.addWidget(self.myTextEdit)
vbox.addWidget(self.button)
gnuplot_path = r'C:\Programs\gnuplot\bin\gnuplot.exe'
self.process = QProcess(self)
self.process.start(gnuplot_path, ["-p"])
#pyqtSlot()
def on_button_click(self):
gnuplot_str = self.myTextEdit.document().toPlainText() + "\n"
self.process.write(gnuplot_str.encode())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())

How to can I add threading to PyQt5 GUI?

So I have created a GUI using QT Designer. It works pretty well, but on more complex calls it doesn't update the main window and locks up. I want to run my CustomComplexFunction() while updating a textEdit in the main window from constantly changing backend information, and I wanted it to run every 2 seconds. The following code seems right and runs without errors, but doesn't update the textEdit. Please note i'm importing a .ui file designed from QT Designer with a pushButton and textEdit and the code won't run without it.
Main.py
import sys
from PyQt5.QtWidgets import QDialog, QApplication, QPushButton, QVBoxLayout, QMainWindow
from PyQt5.QtCore import QCoreApplication, QObject, QRunnable, QThread, QThreadPool, pyqtSignal, pyqtSlot
from PyQt5 import uic, QtGui
class Worker(QObject):
newParams = pyqtSignal()
#pyqtSlot()
def paramUp(self):
x=1
for x in range(100):
time.sleep(2)
self.newParams.emit()
print ("sent new params")
x +=1
Ui_somewindow, _ = uic.loadUiType("mainwindow.ui") #the path to UI
class SomeWindow(QMainWindow, Ui_somewindow, QDialog):
def __init__(self):
QMainWindow.__init__(self)
Ui_somewindow.__init__(self)
self.setupUi(self)
# Start custom functions
self.params = {}
self.pushButton.clicked.connect(self.complex) #NumEvent
def complex(self):
self.work = Worker()
self.thread = QThread()
self.work.newParams.connect(self.changeTextEdit)
self.work.moveToThread(self.thread)
self.thread.start()
self.CustomComplexFunction()
def CustomComplexFunction(self):
self.params['City'] = 'Test'
def changeTextEdit(self):
try:
City = self.params['City']
self.textEdit_14.setPlainText(City)
except KeyError:
City = None
if __name__ == "__main__":
app = QApplication(sys.argv)
window = SomeWindow()
window.show()
sys.exit(app.exec_())
You can see the official docs for Signals and Slots here and this SO post was also very helpful, but it seems like I built it correctly. According to the docs, the emitter doesn't care if the signal is used. This might be why the code doesn't have errors but doesn't work either.
Any ideas on how to make it work? Or atleast some way to test the emitter and signals??
You have forgot to connect the thread to the worker object.
self.work = Worker()
self.thread = QThread()
self.thread.started.connect(self.worker.work) # <--new line, make sure work starts.
self.thread.start()
Good luck with the application :-)

Categories