Avoid pressing a pushbutton more than once

Hello everyone
Xojo

I have a PushButton in a window, in a desktop system.
When the user clicks on the Pushbutton, he executes a process that takes a certain time.
How to prevent the user from clicking again on the pushbutton, while executing the process?

Any comment is very appreciated

Cordilantly,

Raúl Juárez Pulache

Maybe you can disable the button when the process start and activate again when it ends if needed?

Without testing, that might preserve and process the click when the process is done.

Suggestion: disable the button and start a thread that performs the action. When it’s done, have it start a Timer that enables the button.

Thank you so much
Alberto De Poo
Kem Tekinay

With your valuable help, I was able to solve the problem

regards

Raul Juarez Pulache

Kem, now I need to learn about threads and timers. Will I ever finish learning? :wink:

I hope not. :slight_smile:

That statement surprised me, since I anticipated that once you disabled the button, additional clicks would not queue up and process later. But I tested it in a small project and you are right. Possibly because the button disable was within the same event loop cycle as the long running process?

Whatever the reason, here is what I tested:

  • Create new desktop project
  • Drag a generic button and listbox to window
  • Insert this code in button action event:
dim now as new Date
Listbox1.addrow now.LongTime
Listbox1.Refresh
me.Enabled = false
me.Refresh
dim resumeTicks as integer = Ticks + 300
while ticks < resumeTicks
    ' long running process
wend
me.Enabled = true

With each button press it adds the current time to the listbox, then does a tight loop for 5 seconds to mimic a long running process, then enables the button again. I added the .Refresh events so you can see the controls update immediately. Experiment with clicking even while button appears disabled and you can see the click is in fact preserved and processed later.

Not what I expected.

Douglas, thank you for testing and posting the information. At first I didn’t understand exactly what Kem said, but after I read your information now is clear.

You can always disable the button itself in the Action event, so it could not be pushed twice.

Me.enabled = False

Then you do need to re-enable it later when it is needed.

PushButton1.enabled = True

That is exactly what Kem was suggesting might not work. Which surprised me, so I tested and found he was right. Try for yourself the code I posted a couple replies above this.

I should clarify what does not work is disabling in the action code, doing a long running process, and enabling again in the same action code block

The reason it doesn’t work is because you are blocking the main thread, so the OS messages from the mouse driver queue up. Once your process finishes, the main event loop processes the next message, which is a mouse click, but by now you have already enabled the button again. By putting the long process in a thread, you allow the main thread to process the mouse click messages while the button is still disabled.

You can make global variable as any pointer flag which will tells your app that process is up and running.
By checking value of that global variable on click event of button you can then make process to start or not.
Also, by completing a process you should then also update that global value if user want again to start such process.
With this then you get much clear code and which isn’t tight to GUI.

Yeah, I get this when I stop to think about it. Just didn’t seem intuitive at the time, but I can see why it needs to work that way.

[quote=369926:@Bogdan Pavlovic]You can make global variable as any pointer flag which will tells your app that process is up and running.
By checking value of that global variable on click event of button you can then make process to start or not.
Also, by completing a process you should then also update that global value if user want again to start such process.
With this then you get much clear code and which isn’t tight to GUI.[/quote]
Only if you put your long process in a thread, which you didn’t mention, but I think you meant.

I was surprised to learn this, too. I’ve never had the scenario come up because I’ve always used threads for long processes.

Thanks to Kem for the info, Douglas for the working example, and Tim for explaining the “why”. Considering how often buttons are used, this is definitely an important piece of information, IMHO.

Y[quote=369918:@Douglas Handy]That is exactly what Kem was suggesting might not work. Which surprised me, so I tested and found he was right. Try for yourself the code I posted a couple replies above this.[/quote]

If you do the long running process in the action event, that makes sense.

I thought of another way to deal with this. Create a Pushbutton subclass that raises an Action event. After the event, if the button is enabled, disable it and start a Timer with a short Period to re-enable it. Use that subclass in your Windows. That should eat any extra clicks and be hardly noticeable by the user.

@Tim Hare and @Kem Tekinay
No need to use threads. Just global variable or even create a class with complete process and call function of it from push button or so… On click event first what your code should do is to use IF statement to check global value or property value of class object instance OR even you can put that checking in class object of function which is doing a long term process and then use self made status event which will post back return code (started, running, not started, error) and so on.
Setting enabled/disabled property of any control can be then controlled by raised event from dim. class object and it’s any option.
With this above your getting GUI and non-GUI ready code.

There is a way to disable the button without using a thread indeed. Disable the button, then start a timer, and in the timer, put the rest of the code presently in the button Action event.

Problem is, if the process is real long and with tight loops, it will freeze the UI, which a thread would not do.

The thread is probably a much better option for long processes.