Here is a bit of the scenario:
File A:
from fileb import StatusClass
class MainClass (tk.Tk):
#init
...
self.anotherclass = StatusClass(parent, controller)
#DOSOMESTUFF
self._startprgram()
File B:
class StatusClass (tk.Frame):
#init
...
self.anotherclass = StatusProcess
class StatusProcess (threading.Thread):
#init method
self.setDaemon(True)
def run():
while True:
#do stuff
What happens is that, depending on the run time in #DOSOMESTUFF in file A, the thread that is created stops.
If I have a few instructions it holds, but if I even add a time.sleep for a few seconds the thread also stops.
Any suggestion?
Related
I would like to divide my GUI into processes that are run when activated by a ProcessManager.
As the diagram below shows, the MainWindow would instantiate the ProcessManager, which instantiates the Processes.
Now let's say I want to interact with components of the GUI across threads (using signals and slots) -- as an example (also in the picture below):
Process2 has a method that reads out the QLineEdit foo_line_edit.text() and enters it to the QLabel via foo_label.setText().
If I have many processes, I would prefer if all the logic would be implement on the Process without having to add to much on the MainWindow, therefore:
Is there a way to define such a process without having to create any methods/slots in the MainWindow? If there isn't how can I create a process driven design with Qt?
Here is the simplest implementation that comes to my mind:
class Main(QMainWindow):
foo_line_edit = QLineEdit()
foo_label = QLabel()
def __init__(self):
self.process_manager = ProcessManager(self)
# I would like to have the logic of this line in the Process2 class
# (Not sure, but I think it needs to be defined in the main thread?)
self.process_manager.process2.change_label.connect(self.process2_specific_change_label)
# This is the functionality, I would like to define in the Process2 class
def process2_specific_change_label(text):
self.foo_label.setText(text)
class ProcessManager(QObject):
def __init__(self, main_gui):
self.main_gui = main_gui
self.process2 = Process2(self)
class Process(QObject):
def __init__(self, process_manager):
self.process_manager=process_manager
self.thread = QThread()
self.moveToThread(self.thread)
self.thread.start()
class Process2(Process):
change_label = pyqtSignal(str)
def run(self):
# I think this line works, although it already creates access across threads, right?
text = self.process_manager.main_gui.foo_line_edit.text()
# This line does not work because of threads:
self.process_manager.main_gui.foo_label.setText(text)
# This works, but requires the function to be defined in the main thread?
change_label.emit(text)
Rethinking my original requirement and processing musicamante's input, it came to my mind, that the Process Manager and the Processes should run directly in the main thread, calling processspecific workers in threads. This way, the logic is within the specific Process and not somewhere in the MainWindow.
I agree, that the word process is confusing here. It was not meant in a programmatical aspect, but in its application aspect (the gui will follow along a production process). Renaming Process to Step might be better.
This leaves us with the following architecture:
The signals and slots are defined in the Step and its Worker counterpart.
class Main(QMainWindow):
foo_line_edit = QLineEdit()
foo_label = QLabel()
def __init__(self):
self.step_manager = StepManager(self)
class StepManager(QObject):
def __init__(self, main_gui):
self.main_gui = main_gui
self.step2 = Step2(self)
# For example simplicity, the step is run directly:
self.step2.run()
class Step(QObject):
start_worker = pyqtSignal()
worker = Worker()
def __init__(self, step_manager):
self.step_manager=step_manager
self.start_worker.connect(self.worker.run)
def run(self):
self.start_worker.emit()
class Worker(QObject):
finished = pyqtSignal()
def __init__(self):
self.thread = QThread()
self.moveToThread(self.thread)
self.thread.start()
def run(self):
self.finished.emit()
class Step2(Step):
start_worker = pyqtSignal(str)
worker = Worker2()
def __init__(self, step):
super().__init__(step)
self.worker.finished.connect(self.change_label)
def run(self):
text = self.step_manager.main_gui.foo_line_edit.text()
self.start_worker.emit(text)
def change_label(self, text):
self.step_manager.main_gui.foo_label.setText(text)
class Worker2(Worker):
finished = pyqtSignal(str)
def run(self, text):
self.finished.emit(text)
Although 2 classes need to be managed for each step, the MainWindow is free from step specific logic.
Of course, I'm very open to suggestions.
Im trying to implement a gui for a script I have written.
The script itself runs perfectly fine but as soon as I try to run it using a thread, it will just freeze the whole process without any feedback.
The thread seems to not execute the function.
import Foo
from multiprocessing.pool import ThreadPool
class GUI():
def __init__(self, master):
self.file = "path/file"
self.key = "path/key"
# init GUI
...
def updateDev(self):
fib = Foo.foo()
pool = ThreadPool(processes=1)
async_res = pool.apply_async(fib.update, args=(self.file, self.key))
async_res.wait()
# the code freezes here
res = async_res.get()
...
Is there anything im missing?
fib.update(self.file, self.key) runs like this without any threads perfectly.
EDIT:
I solved it myself yesterday by adding a function that starts the thread.
import Foo
from threading import Thread
class GUI():
def __init__(self, master):
self.file = "path/file"
self.key = "path/key"
# init GUI
...
def startDev(self):
t = Thread(target = self.updateDev)
t.start()
def updateDev(self):
fib = Foo.foo()
fib.update(self.file, self.key)
...
Thanks for the help everyone!
Sorry but I don't understand what is the pourpose of the code. If I correctly understand, the code will never reach the async_res.wait() satement because it is recoursive. This row async_res = pool.apply_async(fib.update, args=(self.file, self.key)) will probably run again the "update" function
First of all, i'm a python newbie, and i hope you can help me with my problem.
My program (i'm using tkinter) is suppose to check if a process is running, if it's not running, i would like to run it myself.
I want to do run the function that checks the processes every N seconds, I also want my application not to 'freeze' while executing this function, so i decided to use thread, I've made a new class that creates my thread and running my function every interval.
Here's the class:
class TaskThread(threading.Thread):
"""Thread that executes a task every N seconds"""
def __init__(self, interval, callback):
threading.Thread.__init__(self)
self._finished = threading.Event()
self.setInterval(interval)
self.callback = callback
self.run()
def setInterval(self, interval):
"""Set the number of seconds we sleep between executing our task"""
self._interval = interval
def shutdown(self):
"""Stop this thread"""
self._finished.set()
def run(self):
while 1:
if self._finished.isSet(): return
self.callback()
# sleep for interval or until shutdown
self._finished.wait(self._interval)
Here's the function i'm calling from inside the class (a callback function):
def process_running(self):
"check if the process is running"
print("test")
def check_process():
"check if process is alive"
for process in psutil.process_iter():
if self.process_name == process.name():
self.process_id = process.pid
return True
return False
if not check_process():
self.process = subprocess.Popen([self.launcher_exe])
time.sleep(20.0) #let the notepad.exe to load completely
self.process_id = self.process.pid
self.hwnd = self.get_hwnds_for_pid(self.process_id) #get the window handle
and the init of the class is like so :
self.loop = TaskThread(10, self.process_running)
Now, when i'm starting my application, the program is running the check_process function but the application window is not responding, and i can't use the window at all.
I wonder if i did something wrong, hope you can help me.
I'm making a wxPython app that I need to update a value from the internet every 15 seconds. Is there any way I can have a function to set the value, and make it run in the background at this interval, without interrupting the program?
EDIT: Here's what I'm trying:
import thread
class UpdateThread(Thread):
def __init__(self):
self.stopped = False
UpdateThread.__init__(self)
def run(self):
while not self.stopped:
downloadValue()
time.sleep(15)
def downloadValue():
print x
UpdateThread.__init__()
What you want is to add a thread that runs your task at a specified pace.
You may have a look at this great answer here : https://stackoverflow.com/a/12435256/667433 to help you achieve this.
EDIT : Here is the code that should work for you :
import time
from threading import Thread # This is the right package name
class UpdateThread(Thread):
def __init__(self):
self.stopped = False
Thread.__init__(self) # Call the super construcor (Thread's one)
def run(self):
while not self.stopped:
self.downloadValue()
time.sleep(15)
def downloadValue(self):
print "Hello"
myThread = UpdateThread()
myThread.start()
for i in range(10):
print "MainThread"
time.sleep(2)
Hope it helps
I have made something similar to this:
-you need a thread to run in the background .
-And a define a 'custom' event , so that the tread can notify the UI when needed
Create the custom WX event
(MyEVENT_CHECKSERVER, EVT_MYEVENT_CHECKSERVER) =
wx.lib.newevent.NewEvent()
on UI "init" you can bind the event , and start the thread
# bind the custom event
self.Bind(EVT_MYEVENT_CHECKSERVER, self.foo)
# and start the worker thread
checkServerThread = threading.Thread(target=worker_checkServerStatus
,args=(self,) )
checkServerThread.daemon = True
checkServerThread.start()
the worker thread can be something like this ,ps. caller is the UI instance
def worker_checkServerStatus(caller):
while True:
# check the internet code here
evt = MyEVENT_CHECKSERVER(status='Some internet Status' ) #make a new event
wx.PostEvent(caller, evt) # send the event to the UI
time.sleep(15) #ZZZzz for a bit
Edit: miss read the question...
Another way to do that is with a timer:
import threading
stopNow = 0
def downloadValue():
print("Running downloadValue")
if not stopNow: threading.Timer(15,downloadValue).start()
downloadValue()
This is a classic pattern for repeating a function: the function itself adds a timed call to itself. To start the cycle, call the function (it returns immediately). To break the cycle set stopNow to 1.
I'm trying to create a kind of non-blocking class in python, but I'm not sure how.
I'd like a class to be a thread itself, detached from the main thread so other threads can interact with it.
In a little example:
#!/usr/bin/python2.4
import threading
import time
class Sample(threading.Thread):
def __init__(self):
super(Sample, self).__init__()
self.status = 1
self.stop = False
def run(self):
while not(self.stop):
pass
def getStatus(self):
return self.status
def setStatus(self, status):
self.status = status
def test(self):
while self.status != 0:
time.sleep(2)
#main
sample = Sample()
sample.start()
sample.test()
sample.setStatus(0)
sample.stop()
What I'd like is having the "sample" instance running as a separate thread (detached from the main one) so, in the example, when the main thread reaches sample.test(), sample (and only "sample") would go to sleep for 2 seconds. In the meanwhile, the main thread would continue its execution and set sample's status to 0. When after the 2 seconds "sample" wakes up it would see the status=0 and exit the while loop.
The problem is that if I do this, the line sample.setStatus(0) is never reached (creating an infinite loop). I have named the threads, and it turns out that by doing this, test() is run by the main thread.
I guess I don't get the threading in python that well...
Thank you in advance
The object's run() method is what executes in a separate thread. When you call sample.test(), that executes in the main thread, so you get your infinite loop.
Perhaps something like this?
import threading
import time
class Sample(threading.Thread):
def __init__(self):
super(Sample, self).__init__()
self.stop = False
def run(self):
while not(self.stop):
print('hi')
time.sleep(.1)
def test(self):
print('testing...')
time.sleep(2)
#main
sample = Sample()
sample.start() # Initiates second thread which calls sample.run()
sample.test() # Main thread calls sample.test
sample.stop=True # Main thread sets sample.stop
sample.join() # Main thread waits for second thread to finish