Skip to content

How to correctly use multithreading or multiprocessing to update information on a form in real-time? #98

Open
@SHI1992

Description

@SHI1992

I have tried various methods, and all of them have various issues.

  1. Updating the main thread's form in a child thread, obviously, it failed.
from delphifmx import *
import threading
from pynput.mouse import Listener
import time

class GetMousePosition(threading.Thread):
    def __init__(self, form):
        super().__init__()
        self.form = form
    # mouseListener
    def on_move(self, x, y):
        print(f"Mouse is at: X={x}, Y={y}")
        self.position = (x, y)
        self.form.update_mouse_position(x, y)

    def run(self):
        with Listener(on_move=self.on_move) as listener:
            listener.join()

class MyForm(Form):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.prev_position = None
        self.mouse_thread = None
        self.button = Button(self)
        self.button.Text = 'Start Background Task'
        self.button.OnClick = self.onStartButtonClick
        self.label = Label(self)
        self.label.Text = 'Click the button to start the background task'
        self.button.Parent = self
        self.button.Align = "Top"
        self.label.Parent = self
        self.label.Align = "Top"

    def update_mouse_position(self, x, y):
        self.label.Text = f'Mouse Position: ({x}, {y})'
        
    def onStartButtonClick(self, sender):
        self.mouse_thread = GetMousePosition(self)
        self.mouse_thread.start()

if __name__ == '__main__':
    Application.Initialize()
    Application.Title = "Hello DelphiFMX"
    app = MyForm(Application)
    Application.MainForm = app
    app.Show()
    Application.Run()
    app.Destroy()

2.Return data in the child thread, and the main thread uses onTimer to periodically read and update the main thread's form. It works. However, dragging the main interface causes stuttering, and mouse movement seems to be unsmooth as well.

from delphifmx import *
import threading
from pynput.mouse import Listener
import time

class GetMousePosition(threading.Thread):
    def __init__(self):
        super().__init__()
        self.position = ()
        self.position_history = []

    def on_move(self, x, y):
        print(f"Mouse is at: X={x}, Y={y}")
        self.position = (x, y)

    def run(self):
        with Listener(on_move=self.on_move) as listener:
            listener.join()

class MyForm(Form):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.prev_position = None
        self.mouse_thread = None
        self.button = Button(self)
        self.button.Text = 'Start Background Task'
        self.button.OnClick = self.onStartButtonClick
        self.label = Label(self)
        self.label.Text = 'Click the button to start the background task'
        self.button.Parent = self
        self.button.Align = "Top"
        self.label.Parent = self
        self.label.Align = "Top"

        self.timer = Timer(self)
        self.timer.Interval = 1
        self.timer.OnTimer = self.update_ui

    def update_ui(self, sender):

        if self.mouse_thread:
            result = self.mouse_thread.position
            if result != self.prev_position:
                print("result:" + str(result))
                self.prev_position = result
                self.label.Text = f"Mouse Position: " + str(result)

    def onStartButtonClick(self, sender):
        self.mouse_thread = GetMousePosition()
        self.mouse_thread.start()


if __name__ == '__main__':
    Application.Initialize()
    Application.Title = "Hello DelphiFMX"
    app = MyForm(Application)
    Application.MainForm = app
    app.Show()
    Application.Run()
    app.Destroy()

2024-05-28_153207

  1. Using multiprocessing, data is stored in a queue within the child process, and the main thread uses onTimer to periodically read from and update the main thread's form. It also works. However, if the mouse keeps sliding, it will lead to a lot of data in the queue, and when the mouse stops, the form is still queuing to read data from the queue. It looks like the display of the form is somewhat lagging.
from delphifmx import *
from multiprocessing import Process, Queue
from pynput.mouse import Listener

class GetMousePosition(Process):
    def __init__(self,queue):
        super().__init__()
        self.queue = queue

    def on_move(self, x, y):
        print(f"Mouse is at: X={x}, Y={y}")
        self.queue.put([(x, y)])

    def run(self):
        with Listener(on_move=self.on_move) as listener:
            listener.join()

class MyForm(Form):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.queue = None
        self.mouse_thread = None
        self.prev_position = None  # 用于存储上一次的鼠标位置
        self.button = Button(self)
        self.button.Text = 'Start Background Task'
        self.button.OnClick = self.onStartButtonClick
        self.label = Label(self)
        self.label.Text = 'Click the button to start the background task'
        self.button.Parent = self
        self.button.Align = "Top"
        self.label.Parent = self
        self.label.Align = "Top"

        self.timer = Timer(self)
        self.timer.Interval = 1
        self.timer.OnTimer = self.read_process_output

    def onStartButtonClick(self, sender):
        self.queue = Queue()
        self.mouse_thread = GetMousePosition(self.queue)
        self.mouse_thread.start()

    def read_process_output(self, sender):
        if self.queue:
            result = self.queue.get()
            print(result)

            self.label.Text = f"Mouse Position: " + str(result)


if __name__ == '__main__':
    Application.Initialize()
    Application.Title = "Hello DelphiFMX"
    app = MyForm(Application)
    Application.MainForm = app
    app.Show()
    Application.Run()
    app.Destroy()

Animation2

What is the most correct way to use multithreading or multiprocessing in DelphiFMX4Python? Please let me know, thank you.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions