Using checkboxes and buttons to control different functions

Hello,

I have been trying to create a toolkit to work out a scientific data set. I am really confused about the usage of checkboxes and buttons to control some functions. What I am trying to do is, using checkboxes to define what kind of analysis I want to do (for each type of analysis there is a specific function). To save some time I want to analyse the data in a way that I am going to use only the functions that I need for a specifid type of analysis.

My question is:

How can I use checkboxes to specify that a function is going to be called by a button.

if(checked)
    // "functionA" will be used
endif


I attached an example of the panel that I am going to use. Each time, "perform analysis" button will be used to call needed function. Any ideas?

Thank you.
Example.pxp
Hi,

You will need to check the state of boxes in the function that gets called by the perform analysis. You call a controlinfo with name of the checkbox

such as:
controlinfo check0_tab0

that will produce a variable, V_Value, with the checked state, 1 being checked and 0 for unchecked.

Then in your code

if (V_Value)
// do what you will
endif

Repeat for the rest of the check boxes. Note that V_Flag will hold the value of the last controlinfo so if you want to check the status of all your checkboxes before any function you will need to store the values separately.

Andy

Based on how you have named your controls, this might be a starting point. You would have functions such as MyFunctionforINCD() and MyFunctionforCA() already defined.

Function DoAnalysisFromTab()

    string pname = "Panel0" // the name of your panel here
    string tname = "tab0" // the name of your tab here
    string fname = ""
    variable nc = 4 // the number of controls here
    variable ic, nt = 0
   
    make/N=(nc)/FREE doit = 0
    make/N=(nc)/FREE/T dowhat = {"INCD,AFA,FIA,CA"}

    // collect all control states
       
    for (ic=0;ic<nc;ic+=1)
        sprintf cname, "check%d_%s", ic, tname
        ControlInfo/W=$pname $cname
        doit[ic] = v_value
        nt += v_value
    endfor
   
    if (nt == 0)
        DoAlert 0, "No analysis selected!"
        return 0
    endif
   
    // run selected functions
   
    for (ic=0;ic<nc;ic+=1)
        if (doit[ic])
            sprintf fname, "MyFunctionfor%s()", dowhat[ic]
            Execute/Q fname
        endif
    endfor

    return 0
end


A more elegant solution may exist without the Execute statement, and a more complex method may be needed depending on what you are intending to pass to any given function (the same thing, a wave, a set of parameters, nothing ...).

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville
Hello,

Thank you so much for the nice advices. After a tiny correction, it works great. I just needed to correct one line where a free is used to store the names of suffixes and declare the string "cname" . i.e. MyFunctionforINCD() will be executed not MyFunctionforINCD,AFA,FIA,CA()

Function DoAnalysisFromTab()
 
    string pname = "Panel0" // the name of your panel here
    string tname = "tab0" // the name of your tab here
    string fname = ""
    variable nc = 4 // the number of controls here
    variable ic, nt = 0
        string cname
 
    make/N=(nc)/FREE doit = 0
    make/N=(nc)/FREE/T dowhat = {"INCD","AFA","FIA","CA"}   // Text wave stores suffixes for each function.
 
    // collect all control states
 
    for (ic=0;ic<nc;ic+=1)
        sprintf cname, "check%d_%s", ic, tname
        ControlInfo/W=$pname $cname
        doit[ic] = v_value
        nt += v_value
    endfor
 
    if (nt == 0)
        DoAlert 0, "No analysis selected!"
        return 0
    endif
 
    // run selected functions
 
    for (ic=0;ic<nc;ic+=1)
        if (doit[ic])
            sprintf fname, "MyFunctionfor%s()", dowhat[ic]
            Execute/Q fname
        endif
    endfor
 
    return 0
end

The first tip, more of an essential rule , when doing any programming is separate the GUI code from the code that does the processing analysis.
In other words, write code that does the analysis, that you can call from the command line, but has no GUI interaction or dependencies on any GUI whatsoever (possibly to the extent where it doesn't rely on preexisting global variables/waves).
I wish I had known this when I started programming, it would've saved me countless hours of wasted time.

Get the analysis working well first, then test it. Have specific test cases for the analysis, so you can reassure yourself that the analysis works. Add the test cases to a simple function you can call.

Once the analysis works well, then build the GUI on top. If you've designed the analysis functions well, the two should be relatively orthogonal.

Another perspective on the answers already offered here is to collect GUI state as you go along. Have a GUI function for all the checkboxes, when a checkbox is ticked, then it could set an entry in a wave stored somewhere. In the analysis function you then don't need to query all the checkboxes to see if they are checked or not, you just check the wave. You could even pass that wave to the analysis function (see separation of GUI and analysis above). The same thing goes for other types of GUI widgets.

Designing GUI's are hard. Another suggestion could be to collect the different types of analysis method (on the first tab) into a listbox. Listboxes can hold checkboxes. Listboxes have the advantage that they can scroll, etc. THe selection wave for the listbox holds it's state, so you only have to check that wave to query all the checkbox states.

Also, really recommended is creating a datafolder root:packages:, to hold all the guff associated with the program. In that way the root datafolder stays uncluttered. Also, create different folders to store different datasets that you are analysing, makes things clear.
andyfaff wrote:
The first tip ... write code that does the analysis, that you can call from the command line, but has no GUI interaction or dependencies on any GUI whatsoever ... Once the analysis works well, then build the GUI on top.


I second this absolutely! (... or at least wait until you reach User Level 5 in Igor Pro Coding to attempt both at the same time :-) )

andyfaff wrote:
Another perspective on the answers already offered here is to collect GUI state as you go along. ... In the analysis function you then don't need to query all the checkboxes to see if they are checked or not, you just check the wave.


Or, if I might suggest otherwise, you can still check the GUI panel, but the code to do this is separate from the code that does the analysis. It is a difference in two approaches. One method has the controls set globals (in root:Packages as Andy suggests) immediately as the controls are altered by the user. The other queries the state of the panel controls only when needed. Having coded with both approaches, I can say the former has overhead that can quickly become akin to clutter (e.g. lots of NVAR, SVAR, and WAVE declarations throughout the code), and the latter requires careful consideration of where the user may be at run-time versus where the queries are to be directed at that same instant (e.g. because the user could be focused on some other window that has none of the controls of interest).

andyfaff wrote:
Designing GUI's are hard.


But can be fun too :-)

In all seriousness though, the ability to create well-designed GUI elements in Igor Pro is a clear advantage it has over many other "analysis" software IMO.

@tooprock: Thanks for the correction to setting the list string.

--
J. J. Weimer
Chemistry / Chemical & Materials Engineering, UAHuntsville