Creating the textwave for a ListBox
Nasser
I'd like to display a listBox in the GUI I'm developping, in order to help the user to select the measurements to be plotted.
A measurement consists of several waves. Every time the user open a new measurement, a new datafolder is created.
I think that the fact that a measurement consists of many waves doesn't allow me to use the wave selection widget.
That's why I'm trying to do it by myself. I'v just begun to write the code, and I have have to afford a syntax problem ! I can't compile this portion, which is intended to update the List Wave :
(this function will be located in a loop, in order to browse all the datafolders. The datafolders contain a string called "FileName")
Function AddTo_ListWave(LIST, FileName)
string LIST
string FileName
$LIST[numpnts(LIST)-1] = $FileName
End
string LIST
string FileName
$LIST[numpnts(LIST)-1] = $FileName
End
Would you have some advice about that please ?
Thank you !
Regards
I don't think I understand what you want to achieve. However, there some issues with the example code you're posting:
Your use of
$fileName
is incorrect and should be replaced by justfileName
. This is explained inThe '$' operator can be confusing. However, just remember that you use $ only when Igor expects a name for some object (a wave, a window, a control, etc.), and that name is contained in the string. If Igor expects a string then you never use '$'.
Your function specification has the type of list as a string. However, your code then interprets list as the name of a text wave. I would either make list into a wave, so that you pass the wave to this function directly, or I would modify your code as follows:
listWave[numpnts(listWave) - 1] = fileName
Lastly, the name of your function leads me to believe that you want to append an element to the list instead of replacing the last element. For that you have to remember to enlarge the wave, e.g.
Redimension /N=(DimSize(listWave, 0) + 1) listWave
listWave[DimSize(listWave, 0) - 1] = fileName
Where I've also replaced
numpnts
withDimSize
as it is a more capable replacement.April 26, 2011 at 10:10 am - Permalink
The WaveSelectorWidget procedure file supports multiple selections. In the function MakeListIntoWaveSelector, set selectionMode to either WMWS_SelectionNonContiguous or WMWS_SelectionContiguous as appropriate.
The WaveSelectorWidget procedure file has some might complicated code. Such a project is probably not a great one for learning basic Igor programming!
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
April 26, 2011 at 10:57 am - Permalink
741 : Thank you, now it compiles, but I still have to solve some little issues.
John :
Thank you,
As you can see on the attached screenshot, a measurement consists of : 2 matrixes, 4 line profiles, plus other waveforms which are not yet displayed. These data, belonging to the same dataset, are gathered in the same data folder. What I'd like to achieve, is to select the datasets ((the 2 matrixes + the 4 line profiles)*number of selected datasets) that I want to view.
I think that the widget enables me to select only the waves, not the whole dataset. Would you have an idea ?
Best Regards
April 26, 2011 at 01:38 pm - Permalink
Instead of having the user select a bunch of waves, how about having the user select the datafolder instead? I assume that, given a datafolder, you can extract the waves you need automatically and append them to the relevant graphs.
I think you could do that fairly straightforwardly using the WaveSelectorWidget. Try passing "WMWS_DataFolders" as the content parameter to MakeListIntoWaveSelector.
April 26, 2011 at 02:08 pm - Permalink
Regards
April 26, 2011 at 02:44 pm - Permalink
you will get a selector widget that shows just the data folders, and allows you to select them.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
April 26, 2011 at 04:51 pm - Permalink
Do you mean you want to select a string variable? Or do you mean that you will arrange to have a string variable in the folder, and when you select a folder it should display the contents of that string?
WaveSelectorWidget can be told to show string variables, but not to display the contents.
John Weeks
WaveMetrics, Inc.
support@wavemetrics.com
April 26, 2011 at 04:54 pm - Permalink
I mean that I'd like to select the content of a string variable ('filename' or 'Nom_fichier' in the screenshot ) from the list box.
This string is supposed to identify the dataset (consisting of many matrixes and traces) that I want to plot or to remove from the graph windows.
EDIT : Code updated
Function UpdateDisplay_ListBox(Host, L,T,R,B, NbElements, LISTwave, SELwave)
string Host, LISTwave, SELwave
variable L,T,R,B, NbElements
string dfSav = GetDataFolder(1)
SetDataFolder ::
Make/O/T/N=(NbElements) $LISTwave
Make/O/B/N=(NbElements) $SELwave
ListBox lb1, win=$Host, pos={L,T}, size={R-L,B-T}, listWave=$LISTwave, selWave=$SELwave, mode= 4, proc=Proc_ListBox_SelectDataset
SetDataFolder dfSav
End
//----------------------------------------------------------------------------------
Function AddTo_ListWave(listWave, Nom_fichier, selWave)
string listWave
string Nom_fichier
string selWave
WAVE /T LISTE = root:$listWave
WAVE /B SEL = root:$selWave
NVAR Runs = root:Runs
Redimension /N=(DimSize(SEL, 0) + 1) SEL
SEL[DimSize(SEL, 0) - 1] = 0x20 // Spécifier la checkbox
Redimension /N=(DimSize(LISTE, 0) + 1) LISTE
LISTE[DimSize(LISTE, 0) - 1] = Nom_fichier
End
These functions are called every time we open import a new dataset, while the current datafolder is 0, 1, 2... (where the datasets are stored):
AddTo_ListWave("LISTE", Nom_fichier)
Runs += 1
Now we have to retrieve the datafolder(s) corresponding to the selected dataset(s). Provided that the order is not changed in the listbox, the row number may be sufficient.
Is there any detail that I missed ? Am I on the good way, or should I focus on the WaveSelectorWidget ? (which seems really hard to fully understand).
Thank you
April 27, 2011 at 05:47 am - Permalink
What I would do in this case is to populate the listbox with all the strings the moment it is created, but to create a link between string contents and datafolder name beforehand. So you need to have all the string variables for the list box, and then you need a way to map between from those contents to the datafolder. (side note: with this strategy you need to be able to guarantee that the contents of each stringvariable are unique.)
Here's a possible strategy:
- For establishing the connection between string contents and datafolder name, I would create a 2D text wave, where the first column is the contents of the string and the second column is the name of the datafolder. Once the user makes a selection you look for the string (= the key) in the first column and then take the second column as the datafolder. You could get away with using the index of the selection, too, but I like to look for content in case it becomes possible for the user to drag around the listbox entries in future versions of Igor.
- To make this 2D wave, you make a specific function. The outline of this function could be as follows:
DFREF savDF = GetDataFolderDFR()
DFREF myDataFolder = // some data folder where you store the measurement folders
Make /T /N=(0,2) M_myMap
string currentFolder
for (i = 0;; i += 1)
currentFolder = GetIndexedObjNameDFR(myDataFolder, 4, i)
if (strlen(currentFolder) == 0)
// no more folders remaining
break
endif
SVAR myString = $(currentFolder + "nameOfTheStringVariable")
Redimension /N=(DimSize(M_myMap, 0) + 1, -1) M_myMap
M_myMap[DimSize(myMap, 0) - 1][0] = myString
M_myMap[DimSize(myMap, 1) - 1][1] = currentFolder
endfor
SetDataFolder savDF
return 0
End
This can become a bit more complex if you the data folders can be nested, but that can be sorted out using recursion.
Basically what you're doing here is making a map from key to content, where both types are strings. This is a very common data structure, and in Igor you can do this either with a text wave (when both key and content are strings), or with a string list. In the latter case you would use a global string variable instead of the wave, and access it using e.g.
StringByKey
. The advantage is that this carries over to numbers sinceNumberByKey
exists, too.- Next you make the listbox. The selectionwave for the listbox can be made using
Make /N=(DimSize(myMap, 0)) W_listWave
W_listWave = M_myMap[p][0]
- Then, when the user makes a selection, you take the selected text and look that up in the first column of M_myMap. The second column in the row with the matching index gets you the dataFolder.
April 27, 2011 at 08:26 am - Permalink
Thank you for your reply. For the moment I am using the row index of the listbox in order to retrieve the filename string content. This index corresponds to the datafolder name. Indeed, as you can see on the previous screenshot, I've chosen to name the datafolders '0', '1', '2' and so on.
Your solution would require some changes, since a lot of imported datasets will have the same name (e.g. matrix1.asc).
The "junction" table used to make this kind of relational database would then require an additionnal column : the filepath. Thus, we are sure that the identifier formed by the path + the file name is unique.
Anyway, thank you for this idea, I may need it if I decide to sort the files names in the listbox.
For the moment, I don't think that's crucial... but we never know, maybe I will encounter an unexpected behaviour which will force me to create this look-up table...(for instance, if I want to detect a dataset which is already imported, or if I want to remove it from the listbox)
Best Regards
April 28, 2011 at 12:41 am - Permalink