adeelz92
adeelz92

Reputation: 489

Disabled button still catching clicks during long tasks wxpython

Disabled button still catch clicks during the long task. During the long tasks the button is grayed out but if you click it during the long task, click event fires after the long task has finished. e.g.

def onClick(self, evt):
    self.btn.Disable()
    for i in range (1000):
        print i
    self.btn.Enable()

Button disables itself before executing the long for loop, but if we click the button during for loop, it starts the for loop again, because it calls the onClick function again, after the for loop finishes.

Any idea how to disable the click event as well ?

Upvotes: 1

Views: 332

Answers (3)

Rolf of Saxony
Rolf of Saxony

Reputation: 22443

In fact it's easier than my first answer suggested. There is no reason to UnBind, simply using Yield before re-enabling the button will suffice:

import wx
import time

class ButtonFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None,-1,"Disable Button Events")
        panel = wx.Panel(self, -1)
        self.btn = wx.Button(panel, -1, "Click Me", pos=(10,10), size=(80,30))
        self.btn.Bind(wx.EVT_BUTTON, self.onClick)
        self.Show()

    def onClick(self, event):
        self.btn.Disable()
        for i in range (10):
            time.sleep(1)
            print("Long task running",i)
        wx.GetApp().Yield() # Yielding allows button events to be used up
        self.btn.Enable()
        print("Accepting clicks again")

if __name__ == "__main__":

    app = wx.App()
    ButtonFrame()
    app.MainLoop()

Upvotes: 0

Rolf of Saxony
Rolf of Saxony

Reputation: 22443

Although I have my doubts as to whether you should be coding your long running event this way, you can achieve what you want by using Unbind on the button click, perform the long running task, using Yield to use up any subsequent button clicks and then at the end of the task Bind to the button again. i.e.

import wx
import time

class ButtonFrame(wx.Frame):
    def __init__(self):
        wx.Frame.__init__(self,None)
        self.btn = wx.Button(self, -1, "Click Me")
        self.btn.Bind(wx.EVT_BUTTON, self.onClick)
        self.Centre()
        self.Show()

    def onClick(self, event):
        self.btn.Unbind(wx.EVT_BUTTON)
        for i in range (10):
            time.sleep(1)
            print( i )
        wx.GetApp().Yield() # Yielding allows button events to be used up
        self.btn.Bind(wx.EVT_BUTTON, self.onClick)
        print ("Accepting clicks again")

if __name__ == "__main__":

    app = wx.App()
    ButtonFrame()
    app.MainLoop()

Upvotes: 1

Carson Zhang
Carson Zhang

Reputation: 115

To be honest I didn't really get what you are asking.

Your code works as follows:

  1. When you click on the button, the button (i.e. self.btn) is disabled
  2. It will stayed disabled and execute the for loop
  3. Once done executing the for loop, the button goes back to live

If you would like to disable the button, you should do it outside of the onclick event. For example:

self.btn.Disable()  # This will grey out the button, you can't click it, so the following onClick function wouldn't be triggered
def onClick(self, evt):
    # do something

If you would like to use the button to trigger a task execution, and disable the button that triggers the task when the task is in the middle of execution, the best way is to use multi-thread. You can take a look at the following two links for more information:

http://www.blog.pythonlibrary.org/2010/05/22/wxpython-and-threads/ https://wiki.wxpython.org/LongRunningTasks

Upvotes: 0

Related Questions