SetVariable with string

Hi,
With the Prep4AnalyseGBC function, my aim is to allow the user to create the definition for a string variable (sID) which is then passed to a series of other routines that I have not shown. My problem is with the SetVariable operation. When I enter text into the control panel, my expectation is that this will become the definition for sID. The information that is available in the igor manual (page III-377) about using SetVariable in this way implies to me that the text entered to the control panel should be passed to the parameter varStr in my action procedure, Prep4AnalyseGBC_svWaveID.

However, this is not happening, because the procedure fails at run time and sID comes out as a null string. Can anyone elaborate a little on how SetVariable is supposed to work in this case or point me to a few pages in the manual where more information is available?




Structure strAnalyseGBC
	
	String sID 

EndStructure

Function Prep4AnalyseGBC()//(vVoltageAmplitude4TPParameters,  sFirstDF, sLastDF)

	//Variable vVoltageAmplitude4TPParameters
	//String sFirstDF, sLastDF
	
	
	NewDataFolder/O root:tmp_PauseforPrepDF
	String/G root:tmp_PauseforPrepDF:sID = ""
	
	//STRUCT strAnalyseGBC Prep4
	
	DoWindow/K tmp_PauseforPrep
	NewPanel/K=2 /W=(90,300,420,460)/N=tmp_PauseforPrep as "Enter wave info"	
	
	SetVariable svWaveID, title="Wave ID", fsize=14, pos={50,25}, size={150,50}, value=_STR:"", proc=Prep4AnalyseGBC_svWaveID
	
	PauseForUser tmp_PauseforPrep
	
	SVAR sID_G = root:tmp_PauseforPrep:sID
//sID receives an alternative designation as a global string variable. 
	String sID = sID_G
//sID as a global variable is copied to a local string. 

	KillDataFolder root:tmp_PauseforPrep

	//Print Prep4.sID
	Print sID
End	

Function Prep4AnalyseGBC_svWaveID (svWaveID, varNum, varStr, varName) : SetVariableControl
	
	String svWaveID, varStr, varName
	Variable varNum
	
	//STRUCT strAnalyseGBC Prep4_svWaveID
	
	String/G root:tmp_PauseforPrepDF:sID = varStr
	
	//Prep4_svWaveID.sID = varStr
	
	DoWindow/K tmp_PauseforPrep
End
You are using value=_STR in the SetVariable command. This means "store the value entered by the user variable in Igor internal storage". You can read that value using the ControlInfo operation when PauseForUser returns.

If you want to store the value in a global variable you need to write:
value=root:tmp_PauseforPrep:sID

However using the internal storage is better because it avoids the need to create a global variable.
I haven't looked too closely into your code, but here are two comments:
- You don't need an action procedure just to pass the value to some global string. You should tell
SetVariable
which string to use upon its creation and the variable control will always automatically update. That's what the
value
parameter is for.
- With the newer Igor versions it became even more unfavorable to use global variables for this. Better not hardcode these ugly things into your code and clutter your experiment. You can use
value=_STR:stuff
to attach this stuff directly to the particular control (i.e., its window- and even control-specific). Extract the value using
ControlInfo
only when needed (opposed to having the stuff lying around all the time.

Edit: Ooops, too slow this time ... OK, here's a bonus comment:
It seems that you are working with folders (a lot?). You might want to look into data folder references (DFREFs) before its too late to clean up all the clutter.
Thanks for your replies. I attempted to implement the the ControlInfo function in my routine, but the code posted below fails at runtime because s_value comes out as a null variable. As I understand it, S_value should take on the name of whatever sequence of alphabetical keyboard strokes follow _STR:

i.e. whatever is entered into the text box in the panel (tmp=PauseforPrep) that appears.


Structure strAnalyseGBC
	
	String sID 

EndStructure

Function Prep4AnalyseGBC()//(vVoltageAmplitude4TPParameters,  sFirstDF, sLastDF)

	//Variable vVoltageAmplitude4TPParameters
	//String sFirstDF, sLastDF
	
	
	NewDataFolder/O root:tmp_PauseforPrepDF
	//String/G root:tmp_PauseforPrepDF:sID 
	
	String sID
	
	//STRUCT strAnalyseGBC Prep4
	
	DoWindow/K tmp_PauseforPrep
	NewPanel/K=2 /W=(90,300,420,460)/N=tmp_PauseforPrep as "Enter wave info"	
	
	SetVariable svWaveID, title="Wave ID", fsize=14, pos={50,25}, size={150,50}, value=_STR:"", proc=Prep4AnalyseGBC_svWaveID
	
	PauseForUser tmp_PauseforPrep
	
	ControlInfo svWaveID
	
	sID = s_value 
	
	//SVAR sID_G = root:tmp_PauseforPrep:sID
//sID receives an alternative designation as a global string variable. 
	//String sID = sID_G
//sID as a global variable is copied to a local string. 

	KillDataFolder root:tmp_PauseforPrepDF
	
	//Print Prep4.sID
	Print sID
End	

Function Prep4AnalyseGBC_svWaveID (svWaveID, varNum, varStr, varName) : SetVariableControl
	
	String svWaveID, varStr, varName
	Variable varNum
	
	//STRUCT strAnalyseGBC Prep4_svWaveID
		
	//ControlInfo svWavelD 
	//print s_value
	
	//Prep4_svWaveID.sID = s_value
	//varStr = s_value
	//print varStr
	//String/G root:tmp_PauseforPrepDF:sID = varStr
	//print sID
	
	DoWindow/K tmp_PauseforPrep
End
but the code posted below fails at runtime because s_value comes out as a null variable.


That's because you are killing the SetVariable control, by killing the panel, before you call ControlInfo.

Here is a way to achieve what you want.


Function ContinueButtonProc(ba) : ButtonControl
	STRUCT WMButtonAction &ba

	switch(ba.eventCode)
		case 2:					// mouse up
			ControlInfo/W=tmp_PauseforPrep svWaveID
			String/G root:gPauseForUserOutput = S_value   // Create global variable to store output
			KillWindow tmp_PauseforPrep
			break
	endswitch

	return 0
End

Function CreatePanel()
	NewPanel /N=tmp_PauseforPrep /K=2 /W=(90,300,420,460) as "Enter wave info"
	SetVariable svWaveID, title="Wave ID", fsize=14, pos={50,25}, size={150,50}, value=_STR:""
	Button ContinueButton,pos={120,121},size={70,20},proc=ContinueButtonProc,title="Continue"
EndMacro

Function Demo()
	CreatePanel()
	PauseForUser tmp_PauseforPrep
	SVAR output = root:gPauseForUserOutput    // Access global variable to get output
	Print output
End

Thanks for the code. It certainly works! One remaining issue is that I do not really understand what the 'ba' (in the action procedure) variable represents. There are numerous examples in the manual of code with a format similar to the one you posted, but I could not find an explanation for what the variable (sometimes denoted: 'ctrlName') means. Please can you explain?
It's the name of a parameter that Igor passes to a control action procedure. The type of the parameter is "reference to WMButtonAction structure". For details read the Details section of the documentation for Button.

There are two forms for the action procedure. The form that takes a ctrlName parameter is antiquated. The form that takes a reference to a structure is recommended.
Thanks for the hint. The form which takes the in-built structure WMButtonAction seems neater. I modified this code to do something else. It works, except that for some reason igor skips the printf function at the bottom. I had expected V_Flag = 1 if the button was clicked and V_Flag = 0 if the button was not clicked. Because this is not the case I used the two conditional statements in the two action procedures. Is this really how you would do it? Or is there a neater way?


#pragma rtGlobals=3		// Use modern global access method and strict wave access.

Function Readjust_4Area(ba1) : ButtonControl
	STRUCT WMButtonAction &ba1
	
		switch(ba1.eventCode)
		case 2:					// mouse up

			ControlInfo/W=PauseforReadjustment vMeasureArea
			if (V_Flag == 0)
				Variable/G root:gPauseForUserReadjust1 = 1
				Variable/G root:gPauseForUserReadjust2 = 0
			endif
			KillWindow PauseforReadjustment
			break
	endswitch
 
	//return 0
End
 
 Function Readjust_4NoArea(ba2) : ButtonControl
	STRUCT WMButtonAction &ba2

		switch(ba2.eventCode)
		case 2:					// mouse up
		
 			ControlInfo/W=PauseforReadjustment vDoNotMeasureArea
			if (V_Flag == 0)
				Variable/G root:gPauseForUserReadjust2 = 2
				Variable/G root:gPauseForUserReadjust1 = 0 
			endif
			KillWindow PauseforReadjustment
			break
	endswitch
 
	//return 0
End
 
Function CreateReadjustPanel(sGraphName)

	String sGraphName
	
	NewPanel/N=PauseforReadjustment/K=2 /W=(90,300,420,460) as "Cursor B readjustment panel"
	DoWindow/C PauseforReadjustment
	AutoPositionWindow/E/M=1/R=$sGraphName 
	
	DrawText 21,20,"Adjust cursor B for best area measurement"

	
	Button button1,pos={65,35},size={220,10}, proc=Readjust_4Area,title= "Cursor B ready"
	Button button2,pos={65,60},size={220,10},proc= Readjust_4NoArea, title= "Don't measure area"
	
EndMacro
 
Function Readjust_vReturn2BaseLoc (sGraphName)
	
	String sGraphName
	
	CreateReadjustPanel(sGraphName)
	PauseForUser PauseforReadjustment, $sGraphName	

	NVAR vMeasureArea = root:gPauseForUserReadjust1 
	NVAR vDoNotMeasureArea = root:gPauseForUserReadjust2
	
	if (vMeasureArea == 1)
		return vMeasureArea
		
	elseif (vDoNotMeasureArea == 2)
		return vDoNotMeasureArea
	
	endif
	
	Printf "Results = %g\r and %g\r", vMeasureArea, vDoNotMeasureArea
	
End
<\igor>
It works, except that for some reason igor skips the printf function at the bottom.


That's because your function returns before the Printf statement.


This statement makes no sense because you have no control named vDoNotMeasureArea:

ControlInfo/W=PauseforReadjustment vDoNotMeasureArea

Same for vMeasureArea.

You don't need to call ControlInfo for a button. The mere fact that your button action procedure was called means that the button was clicked.
Ah yes, I had forgotten that the return statement stops execution of the code. I had thought the modifications I made below would work but, with this code, if I click on the window sGraphName, then I can no longer click on the PauseForReadjustment panel. I didn't seem to have this problem before. Any ideas what's gone wrong?


Function Readjust_4Area(ba1) : ButtonControl
	STRUCT WMButtonAction &ba1
	
		switch(ba1.eventCode)
		case 2:					// mouse up

			Variable/G root:gPauseForUserReadjust1 = 1
			Variable/G root:gPauseForUserReadjust2 = 0
			
			KillWindow PauseforReadjustment
			break
	endswitch
 
	return 0
End
 
 Function Readjust_4NoArea(ba2) : ButtonControl
	STRUCT WMButtonAction &ba2

		switch(ba2.eventCode)
		case 2:					// mouse up
		
 		
			Variable/G root:gPauseForUserReadjust2 = 2
			Variable/G root:gPauseForUserReadjust1 = 0 
			
			KillWindow PauseforReadjustment
			break
	endswitch
 
	return 0
End
 
Function CreateReadjustPanel(sGraphName)

	String sGraphName
	
	NewPanel/N=PauseforReadjustment/K=2 /W=(90,300,420,460) as "Cursor B readjustment panel"
	DoWindow/C PauseforReadjustment
	AutoPositionWindow/E/M=1/R=$sGraphName 
	
	DrawText 21,20,"Adjust cursor B for best area measurement"

	
	Button button1,pos={65,35},size={220,10}, proc=Readjust_4Area,title= "Cursor B ready"
	Button button2,pos={65,60},size={220,10},proc= Readjust_4NoArea, title= "Don't measure area"
	
EndMacro
 
Function Readjust_vReturn2BaseLoc (sGraphName)
	
	String sGraphName
	
	CreateReadjustPanel(sGraphName)
	PauseForUser PauseforReadjustment, $sGraphName	

	NVAR vMeasureArea = root:gPauseForUserReadjust1 
	NVAR vDoNotMeasureArea = root:gPauseForUserReadjust2
	
	//Printf "Results = %g\r and %g\r", vMeasureArea, vDoNotMeasureArea
	
End
<\igor>
That's most probably because of your
PauseForUser
statement. You are using sGraphName as the target, and to cite the manual

During execution of PauseForUser, only mouse and keyboard activity directed toward either mainWindowName or targetWindowName is allowed.
chozo wrote: That's most probably because of your
PauseForUser
statement. You are using sGraphName as the target, and to cite the manual

During execution of PauseForUser, only mouse and keyboard activity directed toward either mainWindowName or targetWindowName is allowed.


But I should be able to click between the two windows without a problem - that is what is implied by the statement you cite from the manual. What happens now is that I can click on either window once execution pauses, but as soon as I click on the 'target window' I get stuck on it and cannot click on the panel (which seems to be locked in the background).
Problem solved! Not having a return statement for vMeasureArea and vDoNotMeasureArea seemed to be causing the problem. I needed this anyway, of course, but I did not spot it immediately because I thought something else must be causing the problem I was experiencing.