How to start tkmessagebox from different class than main GUI? - multithreading

I have a class GUI, where I set up all my widgets etc. for my GUI. I use threading to start a process from another class. This works fine, as long that other process just runs through. In some cases, I need to wait for a user input to proceed. I used tkmessagebox for this, but the messagebox doesn't appear and blocks the GUI without any error message. (It works when not started through the GUI).
Here's part of my code:
GUI part
from Tkinter import *
import Tkinter as ttk
import ttk
from tkMessageBox import *
from GUI_reader import Commandline_Reader
import threading
import Queue
class GUI:
def __init__(self,master):
self.master = master
self.argString='ds'
## self.workerThread()
button = ttk.Button(text='start', command=self.go).grid()
...
def go(self):
self.thread = threading.Thread(target=self.workerThread)
self.thread.daemon = True
self.thread.start()
...
def workerThread(self):
...
reader = Commandline_Reader(master, self.argString)
if reader.connect():
print 'success'
reader.run()
print 'success'
if __name__ == '__main__':
root = Tk()
client = GUI(root)
root.mainloop()
class commandline_reader:
import tkMessageBox
...
class Commandline_Reader:
def __init__(self, master, argString='')
self.master = master
...
def connect(self)
...
def run(self):
...
tkMessageBox.askokcancel('Calibration', 'Hit ok to start calibration', parent= self.master)
...
if __name__ == '__main__':
reader = Commandline_Reader(self,master)
if not reader.connect():
exit(-1)
if not reader.run():
exit(-2)

Related

Why does the label show only the last set image? (PyQt5) [duplicate]

I have got this problem. I´m trying to set text on a lineEdit object on pyqt4, then wait for a few seconds and changing the text of the same lineEdit. For this I´m using the time.sleep() function given on the python Time module. But my problem is that instead of setting the text, then waiting and finally rewrite the text on the lineEdit, it just waits the time it´s supposed to sleep and only shows the final text. My code is as follows:
from PyQt4 import QtGui
from gui import *
class Ventana(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.button.clicked.connect(self.testSleep)
def testSleep(self):
import time
self.lineEdit.setText('Start')
time.sleep(2)
self.lineEdit.setText('Stop')
def mainLoop(self, app ):
sys.exit( app.exec_())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Ventana()
window.show()
sys.exit(app.exec_())
You can't use time.sleep here because that freezes the GUI thread, so the GUI will be completely frozen during this time.
You should probably use a QTimer and use it's timeout signal to schedule a signal for deferred delivery, or it's singleShot method.
For example (adapted your code to make it run without dependencies):
from PyQt4 import QtGui, QtCore
class Ventana(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setLayout(QtGui.QVBoxLayout())
self.lineEdit = QtGui.QLineEdit(self)
self.button = QtGui.QPushButton('clickme', self)
self.layout().addWidget(self.lineEdit)
self.layout().addWidget(self.button)
self.button.clicked.connect(self.testSleep)
def testSleep(self):
self.lineEdit.setText('Start')
QtCore.QTimer.singleShot(2000, lambda: self.lineEdit.setText('End'))
def mainLoop(self, app ):
sys.exit( app.exec_())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Ventana()
window.show()
sys.exit(app.exec_())
Also, take a look at the QThread sleep() function, it puts the current thread to sleep and allows other threads to run. https://doc.qt.io/qt-5/qthread.html#sleep
You can't use time.sleep here because that freezes the GUI thread, so the GUI will be completely frozen during this time.You can use QtTest module rather than time.sleep().
from PyQt4 import QtTest
QtTest.QTest.qWait(msecs)
So your code should look like:
from PyQt4 import QtGui,QtTest
from gui import *
class Ventana(QtGui.QMainWindow, Ui_MainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.setupUi(self)
self.button.clicked.connect(self.testSleep)
def testSleep(self):
import time
self.lineEdit.setText('Start')
QtTest.QTest.qWait(2000)
self.lineEdit.setText('Stop')
def mainLoop(self, app ):
sys.exit( app.exec_())
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
window = Ventana()
window.show()
sys.exit(app.exec_())

How Can I stop pytts3 connected with thread through a button in pyqt5?

I use pyttsx3 engine to convert text to speech. And when I click 'start' I create a thread with I target set to 'self.start' so the app doesn't freeze while speaking. And I want to STOP the thread and therefore the engine will stop automaticly. And I tried to rasie exception to kill the thread but it was so useless for my case...
The main qustion here is 'I want to kill the thread so I can stop the engine when clicking 'end' button'
my code:
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5 import QtCore
import sys
import time
import threading
import pyttsx3
class Main(QMainWindow):
def __init__(self):
super().__init__()
self.move(50, 220)
self.resize(500, 500)
self.btn = QPushButton('start', self)
self.btn.move(10, 250)
self.btn.clicked.connect(self.create_a_thread)
self.btn2 = QPushButton('end', self)
self.btn2.move(10, 290)
self.btn2.clicked.connect(self.end)
self.engine = pyttsx3.init()
self.rate = self.engine.getProperty('rate')
self.engine.setProperty('rate', 75)
def start(self):
self.engine.say('I want to stop this thread')
self.engine.runAndWait()
def create_a_thread(self):
thread = threading.Thread(target=self.start, daemon=True)
thread.start()
def end(self):
pass
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Main()
ex.show()
sys.exit(app.exec_())

How to enable threading with tkinter?

When I want to build a program like a clock on Python3,there is a problem about threading & tkinter.
my_code :
#!/usr/bin/python3
#-*-coding:utf-8-*-
import tkinter as tk,time,threading,queue
def update_time(in_q):
while True:
in_q.put(time.strftime('%Y-%m-%d %H:%M:%S',time.localtime()))
class App_gui:
def __init__(self,parent):
self.top_frame = tk.Frame(parent)
self.clock = tk.Label(self.top_frame)
self.clock.pack()
self.top_frame.pack()
self.begin_thread()
def begin_thread(self):
self.clock_q = queue.Queue()
self.clock_thread = threading.Thread(target=update_time(self.clock_q))
self.clock_thread.start()
self.listen()
def listen(self):
gate_time = self.clock_q.get()
self.clock.config(text=gate_time)
self.clock.after(200,self.listen)
if __name__ == '__main__':
root = tk.Tk()
my_app = App_gui(root)
root.mainloop()
when I run this code,there's nothing happen.
Well threading is not all that difficult however in this case threading is overkill for a simple time loop.
We can use after() to manage a label for time without having to use threading.
import tkinter as tk
from time import strftime
class AppGUI(tk.Tk):
def __init__(self):
super().__init__()
self.time_label = tk.Label(self)
self.time_label.pack()
self.track_time()
def track_time(self):
self.time_label.config(text="{}".format(strftime('%Y-%m-%d %H:%M:%S')))
self.time_label.after(1000, self.track_time)
if __name__ == '__main__':
AppGUI().mainloop()
solved
#!/usr/bin/env python3
#-*-coding:utf-8-*-
import threading,time,tkinter as tk
def clock_task():
global clock_time
while True:
clock_time = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime())
time_label.config(text=clock_time)
time.sleep(1)
clock_t = threading.Thread(target=clock_task)
clock_t.setDaemon(True)
root = tk.Tk()
time_label = tk.Label(root)
time_label.pack()
# start thread before mainloop
clock_t.start()
root.mainloop()

Pyqt lunch separate Qtapplications in separate process

So what i would like to do is from the main Qt application start a bunch of separate Qt applications each on separate processes ... do their job then report to the main application when finished.
Could you guys point me in the right direction . I tried with multiprocessing but i get stuck initializing the separate Qt applications
Thank you
Something like this ... which is wrong
import sys
import multiprocessing
from multiprocessing import Pool
from PyQt4 import QtCore, QtGui ,QtNetwork
from PyQt4 import QtWebKit
from PyQt4.QtCore import *
from PyQt4.QtWebKit import *
from PyQt4.QtGui import QApplication
class SimpleWin(QtGui.QWidget):
def __init__(self, parent=None):
super(SimpleWin, self).__init__(parent)
self.buton = QtGui.QPushButton("START")
self.buton.clicked.connect(self.RunJob)
hbox = QtGui.QHBoxLayout()
hbox.addWidget(self.buton)
self.setLayout(hbox)
def RunJob(self):
print "RUUN"
jobs = []
for i in range(5):
p = multiprocessing.Process(target=Render,)
print i
jobs.append(p)
p.start()
class Render(QWebView,multiprocessing.Process):
def __init__(self, prox ):
self.app = QApplication(sys.argv)
QWebPage.__init__(self)
# self.crawl()
self.load(QUrl("http://www.ip-score.com/"))
self.show()
self.app.exec_()
def main():
app = QtGui.QApplication(sys.argv)
browse = SimpleWin()
browse.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()

Why there is a pythonw window generated when mine QProgressDialog window was auto closed?

I am new to both pyqt and python so I'm sure that my question would seem stupid, so thank you for reading and answer it. It is really helpful.
Here is my source code
# -*- coding: utf-8 -*-
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
QTextCodec.setCodecForTr(QTextCodec.codecForName("utf8"))
class Prog(QDialog):
def __init__(self,parent=None):
super(Prog,self).__init__(parent)
self.start_P()
def start_P(self):
progressDialog=QProgressDialog(self)
progressDialog.setWindowModality(Qt.WindowModal)
progressDialog.setMinimumDuration(5)
progressDialog.setWindowTitle(self.tr("请等待"))
progressDialog.setLabelText(self.tr("拷贝..."))
progressDialog.setCancelButtonText(self.tr("取消"))
progressDialog.setRange(0,100)
progressDialog.setAutoClose(True)
for i in range(101):
progressDialog.setValue(i)
QThread.msleep(10)
if progressDialog.wasCanceled():
return
self.connect(progressDialog,SIGNAL("closed()"))
def main():
app = QApplication(sys.argv)
pp = Prog()
pp.show()
app.exec_()
if __name__ == '__main__':
main()
There are some Chinese characters, but it's irrelevant. The strange part is when I execute this program I would get a window of progress dialog, that is what I want. But when it is auto closed a pythonw window generated automatically.
I was curious about why this pythonw window was generated and want to know how to avoid it.
That's because you are creating your QProgressDialog as child of a QDialog, checkout the line that says progressDialog=QProgressDialog(self). Checkout how this example works:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
#---------
# IMPORT
#---------
from PyQt4 import QtGui, QtCore
#---------
# MAIN
#---------
class MyThread(QtCore.QThread):
progress = QtCore.pyqtSignal(int)
_stopped = False
def __init__(self, parent=None):
super(MyThread, self).__init__(parent)
def stop(self):
self._stopped = True
def start(self):
self._stopped = False
super(MyThread, self).start()
def run(self):
for progressNumber in range(101):
self.progress.emit(progressNumber)
self.msleep(22)
if self._stopped:
return
class MyWindow(QtGui.QProgressDialog):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.threadProgress = MyThread(self)
self.threadProgress.progress.connect(self.setValue)
def stop(self):
self.threadProgress.stop()
def start(self):
self.threadProgress.start()
def hideEvent(self, event):
self.close()
if __name__ == "__main__":
import sys
codec = QtCore.QTextCodec.codecForName("utf8")
QtCore.QTextCodec.setCodecForTr(codec)
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.setWindowTitle(main.tr("请等待"))
main.setLabelText(main.tr("拷贝..."))
main.setCancelButtonText(main.tr("取消"))
main.setRange(0,100)
main.canceled.connect(main.stop)
main.show()
main.start()
sys.exit(app.exec_())

Resources