Saving input values from a panel into a text file

Hello, 

I have written a software in Igor. It has several panels with input values for parameters that it requires to start up. Since different people are going to use it with personalized input settings, I want to be able to save all inputs in a text file with a single click of a button. 

I would be thankful if I could get some advice on how to accomplish this. For example, how to save parameters x and y from panel1 into a text file. The parameters x and y are actually 1D single cell waves which I have put into the panel with the set variable function. 

Then I want to be able to upload the text file back into my software and it would automatically repopulate the appropriate parameters. 

Thanks a ton in advance!  

Try

DisplayHelpTopic "Saving Package Preferences"

You might also have a look at how others have accomplished similar things in the projects here on IgorExchange. Some packages have a button to set default values for preferences; tack the file-loading part on to the front and it does what you need.

There are several different strategies for how to save values that appear in controls, so there are potentially many different ways to achieve your goal. If you have a mixture of numerical and text data to save in a single file, you might consider placing the data in waves and saving the waves to disk as a single igor text format (itx) file. Do the same thing in reverse - load the itx file into your package directory - to recover the values.

Thanks a lot for these suggestions, Tony! I very much appreciate them. I will try to apply these ideas and see what works best for my situation. 

One approach to accomplish what you want is to create, populate, and save STRUCTURES. Here is an example from one of my packages for the create and populate steps.

// structure for maskop parameters
Static Structure S_MaskOPParams
    variable how
    variable level
    variable value
EndStructure

// function to get maskop parameters
Function S_GetMaskOPParams(mop)
    STRUCT S_MaskOPParams &mop
   
    ControlInfo/W=$k_fullPanel popupMaskOPHow_tab23
    mop.how = v_value
    ControlInfo/W=$k_fullPanel popupMaskOPLevel_tab23
    mop.level = v_value
    ControlInfo/W=$k_fullPanel setvarMaskOPLevel_tab23
    mop.value = v_value
    return 0
end

One warning about using structures: Structures are mainly meant for passing structured data between functions and not really for saving stuff for later. Saving a structure (via StructPut) supports only numerical data, which will also be saved in a binary way. I cannot recommend this approach to save settings etc. You would need to prepare a specialized structure for this and avoid having any string or other non-numerical fields in it.

If tony's approach of using Package Preferences is a bit to advanced for now (it has its difficulties), you could also use a good old string list written to a text file. I use this approach with great success. You only need Open, Close, FReadLine and fprintf. Of course, you may use a structure to first accumulate the data from your panel in a formatted way (I again use such an approach).

The advantage of using an itx file for storing settings is that you don't need to worry about creating a structured text file, nor do you need file handling operations like open, close, etc. You just have to make sure that all of the current settings are saved in waves, and save a username.itx file. To restore settings you load the itx file, overwriting the waves, and unpack the settings from the loaded waves. You might have one wave for variables, one for text, and an integer wave to record the state of checkboxes or popup selections.

// To switch users:

// set data folder to package folder
// save settings in waves

Save/O/T/M="\n"/P=UserFolderPath wVariables,wStrings,wCheckboxes as "username1.itx"

LoadWave/O/T/P=UserFolderPath "username2.itx"

// extract settings from waves (if needed)
// reset data folder

 

I also recommend the use of an itx file. A text wave as source is flexible to store text and numeric data, just use num2str() and str2num(), but be aware of issues with numerical precision. Consider using Dimension Labels to tag the entries. That makes editing and customization very comfortable.

In reply to by ChrLie

In the past I have used a scheme whereby all preferences data associated with a particular package were in a data folder such as root:Packages:[package name]:Preferences: and I used SaveData/O/L=7 (and LoadData) to save everything in that data folder into a .pxp file, located on the computer in the folder given by SpecialDirPath("Packages",0,0,0) which is specific for each user. Whist one has to be very careful about managing data folders and check for the existence of the preferences file (and create default data if not present), it has the potential advantage of being agnostic as to the names, types and number of waves and globals in that data folder.

 

> @chozo said ... One warning about using structures: Structures are mainly meant for passing structured data between functions and not really for saving stuff for later. Saving a structure (via StructPut) supports only numerical data, which will also be saved in a binary way. I cannot recommend this approach to save settings etc. You would need to prepare a specialized structure for this and avoid having any string or other non-numerical fields in it.

I had forgotten about the full extent of these limitations, eventually also on StructPut and StructGet. The one benefit I would offer though by using structures to store, recover, and even reset values on control panels is the ease afforded in maintenance as the code associated with the control panel is changed. For example, adding a new control input on the panel and linking it to the associated function is as simple as adding a new variable in the structure, adding a new ControlInfo statement in the getPanelInputs function, and linking the resulting structure variable with the local variable in the function that needs it (or should reset it on the panel).

In this regard then, I would agree that StructPut/StructGet are not the proper tools to store and load preferences. Instead, create an additional function that uses the STRUCTURE to get the values from the panel, translates them appropriately, and stores them (or loads them).

// function to store maskop values
Function S_StoreMaskOPParams()

    STRUCT S_MaskOPParams mop
    S_GetMaskOPParams(mop)
   
    make/FREE/N=3/T wVariables
   
    wVariables[0] = num2str(mop.how)
    wVariables[1] = num2str(mop.level)
    wVariables[2] = num2str(mop.value)
   
    // save
    ...
   
    return 0
end

Again, I suggest that this approach has its greatest advantage in the ease that one has to maintain consistency in five closely-related functions (the panel control storage structure, the S_Get... function, an S_Put... function as needed, an S_Store... function as needed, and an S_Load... function as needed), especially as one continues to develop new input controls or change existing controls on the panel itself.

In case it's not clear, even though an itx file is a text file, the waves that you save in the file can be a mixture of numerical and text formats. So there's no need for num2str or str2num conversions, that's taken care of in the loading and unloading (if you go the itx route). Using control names as dimension labels is, as others have suggested, very helpful for keeping things organised.