Accessing user-defined structures from controls (buttons, listbox...)
Nasser
I'd like to access the members of a structure which is selected from a ListBox (or a popup menu).
The challenge is that the event (e.g. Cell Selected) calls a procedure which can have only one parameter : the Control name, whereas I'd like to pass also a structure reference.
First, I tried to "encapsulate" the control into the structure, so that each instance of the structure has its own button (this button is aimed at changing the values of the structures data members) :
Structure class_VFA
string str_Analyte
variable RT
variable Vc_Mono
variable Vc_Dimer
variable Sdev_RT
variable Sdev_Vc_Mono
variable Sdev_Vc_Dimer
variable RTMin
variable RTMax
variable VcMin_Mono
variable VcMax_Mono
variable VcMin_Dimer
variable VcMax_Dimer
STRUCT WMButtonAction Button_RedefineCoords
EndStructure
//-----------------------------------------------------------------------------
//Fonction d'Initialisation
//------------------------------
Function Init_Analyte(str_Analyte,instance_locale,RT,Vc_Mono,Vc_Dimer,Sdev_RT,Sdev_Vc_Mono,Sdev_Vc_Dimer,RTMin,RTMax,VcMin_Mono,VcMax_Mono,VcMin_Dimer,VcMax_Dimer)
string str_Analyte
STRUCT class_VFA &instance_locale
variable RT,Vc_Mono,Vc_Dimer,Sdev_RT,Sdev_Vc_Mono,Sdev_Vc_Dimer,RTMin,RTMax,VcMin_Mono,VcMax_Mono,VcMin_Dimer,VcMax_Dimer
instance_locale.str_Analyte = str_Analyte
instance_locale.RT = RT
instance_locale.Vc_Mono = Vc_Mono
instance_locale.Vc_Dimer = Vc_Dimer
instance_locale.Sdev_RT = Sdev_RT
instance_locale.Sdev_Vc_Mono = Sdev_Vc_Mono
instance_locale.Sdev_Vc_Dimer = Sdev_Vc_Dimer
instance_locale.RTMin = RTMin
instance_locale.RTMax = RTMax
instance_locale.VcMin_Mono = VcMin_Mono
instance_locale.VcMax_Mono = VcMax_Mono
instance_locale.VcMin_Dimer = VcMin_Dimer
instance_locale.VcMax_Dimer = VcMax_Dimer
instance_locale.Button_RedefineCoords.ctrlName = "Button_Coords_"+str_Analyte
//------------------------------------------------------------------------------------------------------------------
Function Afficher_BtnRedefineCoords(instance_locale)
STRUCT class_VFA &instance_locale
Button $instance_locale.Button_RedefineCoords.ctrlName,pos={650,200},size={24,18},proc=ButtonProc_RedefineCoords,title="°",font="Wingdings",fSize=16,fColor=(0xFFFF,0xFFFF,0xFFFF)
End
string str_Analyte
variable RT
variable Vc_Mono
variable Vc_Dimer
variable Sdev_RT
variable Sdev_Vc_Mono
variable Sdev_Vc_Dimer
variable RTMin
variable RTMax
variable VcMin_Mono
variable VcMax_Mono
variable VcMin_Dimer
variable VcMax_Dimer
STRUCT WMButtonAction Button_RedefineCoords
EndStructure
//-----------------------------------------------------------------------------
//Fonction d'Initialisation
//------------------------------
Function Init_Analyte(str_Analyte,instance_locale,RT,Vc_Mono,Vc_Dimer,Sdev_RT,Sdev_Vc_Mono,Sdev_Vc_Dimer,RTMin,RTMax,VcMin_Mono,VcMax_Mono,VcMin_Dimer,VcMax_Dimer)
string str_Analyte
STRUCT class_VFA &instance_locale
variable RT,Vc_Mono,Vc_Dimer,Sdev_RT,Sdev_Vc_Mono,Sdev_Vc_Dimer,RTMin,RTMax,VcMin_Mono,VcMax_Mono,VcMin_Dimer,VcMax_Dimer
instance_locale.str_Analyte = str_Analyte
instance_locale.RT = RT
instance_locale.Vc_Mono = Vc_Mono
instance_locale.Vc_Dimer = Vc_Dimer
instance_locale.Sdev_RT = Sdev_RT
instance_locale.Sdev_Vc_Mono = Sdev_Vc_Mono
instance_locale.Sdev_Vc_Dimer = Sdev_Vc_Dimer
instance_locale.RTMin = RTMin
instance_locale.RTMax = RTMax
instance_locale.VcMin_Mono = VcMin_Mono
instance_locale.VcMax_Mono = VcMax_Mono
instance_locale.VcMin_Dimer = VcMin_Dimer
instance_locale.VcMax_Dimer = VcMax_Dimer
instance_locale.Button_RedefineCoords.ctrlName = "Button_Coords_"+str_Analyte
//------------------------------------------------------------------------------------------------------------------
Function Afficher_BtnRedefineCoords(instance_locale)
STRUCT class_VFA &instance_locale
Button $instance_locale.Button_RedefineCoords.ctrlName,pos={650,200},size={24,18},proc=ButtonProc_RedefineCoords,title="°",font="Wingdings",fSize=16,fColor=(0xFFFF,0xFFFF,0xFFFF)
End
It didn't work since i don't know how to access the members of the structure containing the button instance.
Then I decided to suppress the buttons, and to create a listbox or a popup menu (actually I don't know which solution (1 button per instance, 1 listbox, 1 popup menu...) is the cleanest from a software-engineering point of view)
The main issue is still there : how to refer to a structure from a control (button in the 1st case, item number for the listbox)
I hope I've been clear, I would understand if the description of my problem was confusing. If so, please do not hesitate to ask me.
Thanks in advance!
Best Regards.
Nasser
The only way you can get a filled in structure for a control in Igor is if you set the control's action procedure to a structure based action procedure for that control type. Otherwise, you can use one of the predefined control structures in your code (eg. WMButtonAction), but your code has to fill out all of the values in the structure that are necessary to get your code to work. You could use ControlInfo to get some of the information about the control and put those values into the structure.
January 17, 2011 at 08:25 am - Permalink
To get back a copy of the structure, use GetStruct (again with /S if you are using a string).
The reason a string is most convenient is that it can be stored inside a control using the the control's userdata keyword. In the action procedure, you would use something like
STRUCT class_VFA myVFA
StuctGet/S myVFA, userdata
(code not tested, I may have made some stupid mistake...)
Note that there are restrictions on what kind of members you can have in a structure that you store via StructPut. Your structure contains a String member, which is not allowed. You can use a char array, and it will have almost the same functionality. The Variable members are OK.
The STRUCT WMButtonAction member will not be useful, however, as you have found.
The Scatter Plot Matrix package uses StructPut/StructGet to store information into the generated graph window. See File->Example Experiments->Graphing Techniques->Scatter Plot Matrix Demo.
Another example of the use of StructPut/StructGet is the WaveSelectorWidget module. See File->Example Experiments->Programming->WaveSelectorWidgetExample.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
January 17, 2011 at 10:12 am - Permalink
First, I have created a structure, which consists of a string (the name of the chemical), and coordinates (in order to locate the peak corresponding to that chemical, on a spectrum image). The reason why I have defined a structure is that there will be less arguments to be passed in functions, for instance, to quantify the peak. This is working.
Then, my aim is to access the fields of a structure from a control (most likely an item in a listbox).
Here is how I'd like to do it :
> I'd like to re-define the coordinqtes of a peak.
> I choose it from a listbox (I select its name, corresponding to the field "str_Analyte" in the user-defined structure)
> I use the GetMarquee function in order to get the 4 new coordinates values (top left, top right, bottom left, bottom right)
> I affect these values to the Vcmin, VcMax, RTmin, RTmax fields, in the structure instance corresponding to the peak I've choosen in the ListBox.
> I'm happy
Do you know what I mean ?
Best Regards
January 18, 2011 at 05:19 am - Permalink
I don't wish these structure instances to be static. I'd like to be able to redefine the coordinates (for instance).
To be honest, I don't realy know what you mean by "freeze-dried".
Thanks for the info. In the documentation it's written "The structure to be exported must contain only numeric data", fortunately char arrays are supported !
The aim was to create one button per structure instance, so as to directly access the "parent structure" instance fields (e.g. the coordinates of the chemical's peak). Now I'm trying to do the same using an item choosen in a ListBox : How to retrieve the structure instance corresponding to the selected item, in order to access its fields ?
I'll have a look to these examples, to check if their purpose answer my question.
Thank you
Best Regards
January 18, 2011 at 04:01 am - Permalink
I don't mean static in the sense that they can't change, but static in the programmer's sense that they are not local variables that disappear when the function finishes.
Sorry- that's very colloquial American English :) It refers to the process by which food can be dried and made very lightweight for use by hikers or astronauts. In this case, it is intended to mean that the structures are stored away in a special encoding that allows you to re-make the structure later. Just like the hiker or astronaut can re-introduce water to freeze-dried food during cooking to make an edible meal.
And you're trying to coerce Igor's language to look more object-oriented, which you will most likely achieve with only limited success. In the case of a structure for each button, you clearly can use StructPut to store one structure in the control. But with a structure for each row of a ListBox, you have only one control and a number of structures. You might be able to store a structure with an array of structures, but I think that will get cumbersome. Another possibility would be to use multiple named userdata strings to store multiple structures. The structure for row 1 might be stored using userdata(MyStruct1)=... and recovered via GetUserData(panelname, listboxname, "MyStruct"+num2str(rownum)).
Another technique I have used for storing per-row data in a listbox is to use a three-dimensional matrix for the listbox selwave. I then use the extra layers of the selwave (or the listwave- both work) to store private data relating to the rows and columns in the list.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
January 18, 2011 at 09:02 am - Permalink
Thank you for your prompt answer and all those explanations.
You're right, I'm focusing on an Object-oriented programming :)
--> http://www.igorexchange.com/node/1965
I thought the code would be easier to maintain using an Object-Oriented approach.
Regarding your suggestions, I'm going to use the userData variables, that I don't know yet. The most important is that we can access a structure's members from a list's item.
Thank you very much.
Kind regards
January 20, 2011 at 04:50 am - Permalink
STRUCT class_VFA &instance_locale
variable y
string str_Button_RedefineCoords
string strStruct4UserData
str_Button_RedefineCoords = "Button_Coords_" + instance_locale.str_Analyte
StructPut /S instance_locale, strStruct4UserData //on sauvegarde l'instance de structure VOC dans une chaine de caract.
Button $str_Button_RedefineCoords,pos={612,460+20*y},size={24,18},proc=ButtonProc_RedefineCoords,title="°",font="Wingdings",fSize=16,fColor=(0xFFFF,0xFFFF,0xFFFF), userdata=strStruct4UserData
End
//------------------------------------------------------------------------------------------------
Function ButtonProc_RedefineCoords(ba) : ButtonControl
STRUCT WMButtonAction &ba
STRUCT class_VFA myVFA
switch( ba.eventCode )
case 2: // mouse up
StructGet/S myVFA, ba.userdata // written out to control
RedefineCoords(myVFA) // click code here
break
endswitch
return 0
End
Best Regards
January 20, 2011 at 04:42 am - Permalink