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.
January 12, 2023 at 09:19 am - Permalink
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.
January 12, 2023 at 12:27 pm - Permalink
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.
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
January 12, 2023 at 01:00 pm - Permalink
In reply to One approach to accomplish… by jjweimer
Thanks a lot, jjweimer! I haven't worked with Structures yet so this will be an awesome new learning. I will look into this.
January 13, 2023 at 01:26 am - Permalink
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).
January 13, 2023 at 01:50 am - Permalink
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.
// 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
January 13, 2023 at 02:18 am - Permalink
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.
January 13, 2023 at 05:08 am - Permalink
In reply to I also recommend the use of… 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.
January 13, 2023 at 06:01 am - Permalink
> @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 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.
January 13, 2023 at 07:33 am - Permalink
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.
January 13, 2023 at 08:07 am - Permalink
I return to this thread with a question. It seems to me that, for package folders that contain a mixture of strings, variables, and waves, the method proposed by @KurtB is far simpler than the approach to use .itx files. Essentially, one just needs two functions.
This approach avoids the need to convert strings and numbers into waves before storing and reconverting when reloaded from an .itx file. I can also foresee creating a package with default preferences, storing the default preferences in an .h5dxp file, and forgoing the need to recreate the entire package folder in an initialization routine ...
Other than the advantage that an .itx file is likely more transparent to being edited with a basic text editor, what is not to appreciate in ease of use with the SaveData + LoadData approach?
June 10, 2024 at 02:27 pm - Permalink