LabVIEW

cancel
Showing results for 
Search instead for 
Did you mean: 

When is producer/consumer not suitable for separating UI/Logic?

Solved!
Go to solution

So many times I read advice that people should implement producer/consumer architecture to decouple the UI/logic, with one of, if not the sole, reason for doing so is to keep the UI responsive for additional user input while earlier tasks are processing.

 

Literally, I can't recall ever reading an argument against it. However, as I think about a part of a project I'm doing, I feel this is not the behavior I want. But it feels like I must not be thinking right given all this prior reading.

 

I am interfacing with an external application via COM/ActiveX. There are quite a few properties/methods that can take 0.5seconds all the way up to 4-5seconds to return. I can't imagine wanting the desired behavior to be a user clicking around and queuing up a bunch of other commands while the first is still waiting to return. In fact, I'd worry that they'd think something wasn't right when their first click didn't immediately "result" in something and then just go clicking around "to see" if it will respond to any other buttons. So I've put these commands IN the event loop, and even set the cursor busy for some of the more lengthy ones.

 

Am I thinking about this all wrong?

 

0 Kudos
Message 1 of 16
(4,116 Views)

You're correct, there are times when you don't want the user to be queuing stuff up for the application to do. You can use the "set busy" and "unset busy" which will give the mouse cursor the appearance that something is happening (and doesn't let them click on UI elements).

Message 2 of 16
(4,095 Views)
Solution
Accepted by DoctorAutomatic

There are quite a few properties/methods that can take 0.5seconds all the way up to 4-5seconds to return. I can't imagine wanting the desired behavior to be a user clicking around and queuing up a bunch of other commands while the first is still waiting to return.

 

I never met a single case when a producer-consumer (any sort of) was not appropriate to fulfil my application requirements. I disagree that the "set busy", "unset busy" is a good method to use during a certain state is still running in your application. I only use these "busy" functions to indicate to the user that some sort of initialization step is running (like VISA init + device ID check, etc), and these usually do not take more than a couple of seconds. And be aware, there is a danger when you use the "busy" functions! Imagine, you put your "busy" function on the same error wire, and something triggers an error before the "unset busy"! Your "unset busy" will be not executed (default error in functionality), so your user will be doomed 🙂 So branch the error wire before the "unset busy", and put a "erase error" before it.

 

But as I said, I would never use the "busy" functions for longer running tasks! When I want to stop the user to "clicking around", and enqueue (or putting new msgs on the Channel wire) undesired commands, I just use property nodes to temporary disable those buttons which the user should not interact with! This gives you much more flexibility, since certain functions should be still accessible even during longer ongoing tasks! Like "abort" functions, or imagine multiple Consumer loops!

One of my most often used subVIs is an "enable/disable" one. You can select all your Boolean controls in your app, and create all their references at once. After this just bundle them up into a cluster wire, so you can get the required button refs anywhere in your code from a single wire, using "unbundle by name"! I often need to enable/disable multiple buttons in my application at once, then I like to use a subVI with control refnums as an array input:

 

enable_.png

 

EDIT: so I would say, if a step takes less than 2-3 seconds, I would go for the "busy" functions, and for any longer times, I would go for the property nodes (temporary disabled and grayed out)...

Message 3 of 16
(4,078 Views)

@Blokk wrote:

There are quite a few properties/methods that can take 0.5seconds all the way up to 4-5seconds to return. I can't imagine wanting the desired behavior to be a user clicking around and queuing up a bunch of other commands while the first is still waiting to return.

 

I never met a single case when a producer-consumer (any sort of) was not appropriate to fulfil my application requirements. I disagree that the "set busy", "unset busy" is a good method to use during a certain state is still running in your application. I only use these "busy" functions to indicate to the user that some sort of initialization step is running (like VISA init + device ID check, etc), and these usually do not take more than a couple of seconds. And be aware, there is a danger when you use the "busy" functions! Imagine, you put your "busy" function on the same error wire, and something triggers an error before the "unset busy"! Your "unset busy" will be not executed (default error in functionality), so your user will be doomed 🙂 So branch the error wire before the "unset busy", and put a "erase error" before it.

 

But as I said, I would never use the "busy" functions for longer running tasks! When I want to stop the user to "clicking around", and enqueue (or putting new msgs on the Channel wire) undesired commands, I just use property nodes to temporary disable those buttons which the user should not interact with! This gives you much more flexibility, since certain functions should be still accessible even during longer ongoing tasks! Like "abort" functions, or imagine multiple Consumer loops!

One of my most often used subVIs is an "enable/disable" one. You can select all your Boolean controls in your app, and create all their references at once. After this just bundle them up into a cluster wire, so you can get the required button refs anywhere in your code from a single wire, using "unbundle by name"! I often need to enable/disable multiple buttons in my application at once, then I like to use a subVI with control refnums as an array input:

 

enable_.png

 

EDIT: so I would say, if a step takes less than 2-3 seconds, I would go for the "busy" functions, and for any longer times, I would go for the property nodes (temporary disabled and grayed out)...


I am in agreement here.  If it's more than a few seconds, take the time to disable and grey out the controls you don't want the user to interact with.  If there are buttons that are commonly set together, you can make a subVI to enable or disable them at once.  This has the added flexibility of having a way of exiting that state or closing the application if something goes wrong.  My rule of thumb is, "always give the user an exit strategy."

Bill
CLD
(Mid-Level minion.)
My support system ensures that I don't look totally incompetent.
Proud to say that I've progressed beyond knowing just enough to be dangerous. I now know enough to know that I have no clue about anything at all.
Humble author of the CLAD Nugget.
0 Kudos
Message 4 of 16
(4,043 Views)

This may be overly simplistic but why not just flush the Queue when you return from your task.

 

Wouldn't that eliminate any impatient clicking on things that was queued up while waiting?

========================
=== Engineer Ambiguously ===
========================
0 Kudos
Message 5 of 16
(4,037 Views)

@RTSLVU wrote:

This may be overly simplistic but why not just flush the Queue when you return from your task.

 

Wouldn't that eliminate any impatient clicking on things that was queued up while waiting?


I feel this would be a "play with fire" 🙂 A slight mistake, and you face a disaster... I always read the advise in the forum: "keep the queue starving!"

0 Kudos
Message 6 of 16
(4,033 Views)

 Keeping the UI responsive isn't the only reason to decouple your UI from the rest of your application. Building powerful UIs requires a lot of code. It would be nice to reuse that code across multiple projects, which you can't easily do if the UI code is tied to the specifics of your application.

 

Even if you aren't building a complex UI, keeping business code and UI code separate makes for cleaner, easier to read and debug code. 

 

As for your specific problem, I don't see anything wrong with using the busy indicator to prevent the user from clicking more buttons while you process something. I prefer a popup loading splash screen for things that would take more than a second or two, but the idea is the same - its clear to the end user they need to wait while the application does something. Disabling buttons doesn't always have the same effect.  

0 Kudos
Message 7 of 16
(4,031 Views)

@Blokk wrote:

And be aware, there is a danger when you use the "busy" functions! Imagine, you put your "busy" function on the same error wire, and something triggers an error before the "unset busy"! Your "unset busy" will be not executed (default error in functionality), so your user will be doomed 🙂


Despite what the help file says, I've found this not to be true. Try running this VI to see for yourself.

Capture.PNG

 

0 Kudos
Message 8 of 16
(4,021 Views)

@Gregory wrote:

Despite what the help file says, I've found this not to be true. Try running this VI to see for yourself.


Something must have gotten updated because I remember being burned by that in LabVIEW 2012.  I currently don't have access to an older version to test.


GCentral
There are only two ways to tell somebody thanks: Kudos and Marked Solutions
Unofficial Forum Rules and Guidelines
"Not that we are sufficient in ourselves to claim anything as coming from us, but our sufficiency is from God" - 2 Corinthians 3:5
Message 9 of 16
(3,956 Views)

I do not have access to LV now, but if the help description and the functionality disagree, this should be reported.

Message 10 of 16
(3,950 Views)