Python Forum
[WxPython] Using thread in the wxPython - Printable Version

+- Python Forum (https://python-forum.io)
+-- Forum: Python Coding (https://python-forum.io/Forum-Python-Coding)
+--- Forum: GUI (https://python-forum.io/Forum-GUI)
+--- Thread: [WxPython] Using thread in the wxPython (/Thread-WxPython-Using-thread-in-the-wxPython)



Using thread in the wxPython - hildogjr - Aug-07-2018

I am one of the developer of a python2/3 package available on https://github.com/hildogjr/KiCost/
I am developing a GUI on wxPython 4.0.3 to call the CLI program part (kicost/kicost_gui.py file).

The call is made by a thread the execute the CLI function kicost(foo) inside the run(self), but in the thread have to update some GUI controls (process bars, text infos, log...). The GUI change parameters (text, label, process perceptual) work fine (or was before some changes on me code and update from wxPy4.0.1 to 4.0.3), now is returning this error:

Error:
[xcb] Unknown sequence number while processing queue [xcb] Most likely this is a multi-threaded client and XInitThreads has not been called [xcb] Aborting, sorry about that. python3: ../../src/xcb_io.c:274: poll_for_event: Assertion `!xcb_xlib_threads_sequence_lost' failed. Aborted (core dumped)
I think that is a bad configuration and call of the threading as I coded (bellow). Someone have some tips?

    def button_run(self, event):
        ''' @brief Call to run KiCost.'''
        event.Skip()
        def run_kicost_guide():
            '''Run the as a Thread out of the box wxPython'''
            self.m_gauge_process.SetValue(0)
            self.m_button_run.Disable()
            self.save_properties() # Save the current graphical configuration before call the KiCost motor.
            logger.log(DEBUG_OVERVIEW, 'Starting the KiCost scrape process.')
            self.run() # Run KiCost.
            init_distributor_dict() # Restore distributors removed during the execution of KiCost motor.
            self.m_button_run.Enable()
        def run_kicost_guide_action(): # Necessary to not freeze the GUI application during the scrapes.
            kicost_motor_thread = threading.Thread(target=run_kicost_guide)
            #kicost_motor_thread.setDaemon(1)
            kicost_motor_thread.start()
        wx.CallLater(10, run_kicost_guide_action) # Necessary to not '(core dumped)' with wxPython.



RE: Using thread in the wxPython - Gribouillis - Aug-07-2018

It's been a long time since I last used wxpython, but you could perhaps use the module wxanythread from pypi. It defines a decorator @anythread which you can use to decorate methods interacting with the GUI that you want to call safely from any thread. The module is old, but its code is very short.


RE: Using thread in the wxPython - hildogjr - Aug-08-2018

I tested, unfortunately wxAnyThread is a Py2 code do wxPy3. I need a solution that works (also) in Py3 using wxPy4, since this code have to be long time supported and available to to P2/3.


RE: Using thread in the wxPython - Gribouillis - Aug-08-2018

If you look in wxAnyThread, you'll see that, ignoring docstrings, it is only 60 meaningful lines of python in __init__.py. Don't you think you can adapt these 60 lines to work with Py3 and wxPy4?


RE: Using thread in the wxPython - hildogjr - Aug-08-2018

Yes, I think so. trying right now, the Py3 part is easy, but:

Error:
AttributeError: module 'wx' has no attribute 'Thread_IsMain'
Changing the attribute as in https://wxpython.org/Phoenix/docs/html/classic_vs_phoenix.html I am getting a freeze GUI now.

    def button_run(self, event):
        ''' @brief Call to run KiCost.'''
        event.Skip()
        self.run_kicost_guide()

    @anythread
    def run_kicost_guide(self):
        '''Run the as a Thread out of the box wxPython'''
        self.m_gauge_process.SetValue(0)
        self.m_button_run.Disable()
        self.save_properties() # Save the current graphical configuration before call the KiCost motor.
        logger.log(DEBUG_OVERVIEW, 'Starting the KiCost scrape process.')
        self.run() # Run KiCost.
        init_distributor_dict() # Restore distributors removed during the execution of KiCost motor.
        self.m_button_run.Enable()
Is here some mistake mine on the call?


RE: Using thread in the wxPython - Gribouillis - Aug-08-2018

It seems to me that your thread's main action is the self.run() and that this call does not use the wxpython GUI (tell me if I'm wrong). This main task of the thread must not go under anythread. The decorator is used to wrap parts that update the GUI. You could perhaps cut this in
def button_run(self, event):
    ''' @brief Call to run KiCost.'''
    event.Skip()
    self.run_kicost_guide()
 
@anythread
def foo(self):
    self.m_gauge_process.SetValue(0)
    self.m_button_run.Disable()
    self.save_properties() # Save the current graphical configuration before call the KiCost motor.
    logger.log(DEBUG_OVERVIEW, 'Starting the KiCost scrape process.')

def run_kicost_guide(self):
    '''Run the as a Thread out of the box wxPython'''
    self.foo()
    self.run() # Run KiCost.
    self.bar()

@anythread
def bar(self):
    init_distributor_dict() # Restore distributors removed during the execution of KiCost motor.
    self.m_button_run.Enable()



RE: Using thread in the wxPython - hildogjr - Aug-09-2018

Really in self.run() there are some GUI control read and update the GUI controls. So, I summarize all the code to it function and call as:

    def button_run(self, event):
        ''' @brief Call to run KiCost.'''
        event.Skip()
        self.run()
        #wx.CallLater(10, self.run) # Necessary to not '(core dumped)' with wxPython.

    @anythread
    def run(self):
        ''' @brief Run KiCost.'''
Also updated the wxAnyThread file (both available in https://github.com/hildogjr/KiCost/blob/master/kicost/kicost_gui.py).
The GUI and the process works, but during the process o the CLI (the GUI is used to run a command line based software), the GUI still freezing. About remove the main code/functionality out of the anythread: I changed the sys.out to output the log of the CLI program in a textControl so, even the CLI program start to interact with the GUI.


RE: Using thread in the wxPython - Gribouillis - Aug-09-2018

(Aug-09-2018, 07:52 PM)hildogjr Wrote: but during the process o the CLI (the GUI is used to run a command line based software), the GUI still freezing
I think the GUI will stop freezing if you remove the call to the CLI program from the anythread context.


RE: Using thread in the wxPython - hildogjr - Aug-11-2018

Tried:

    def button_run(self, event):
        ''' @brief Call to run KiCost.'''
        event.Skip()
        def run_guide():
            args = self.run_before()
            cli_run(args)
            self.run_after(args.file_output)

@anythread
def self.run_before():
    ....
    return args
@anythread
def self.run_after(args):
Same behavior. Making something wrong here? (is because the args?)