LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

multiple panels, single close callback?

Solved!
Go to solution

Basic question.  I'm trying to use a common Quit button across multiple panels in my project.  So with a single callback function, I a couple nested switch statements, the first of course checking for EVENT_COMMIT, and the next down checking for the active panel.  For instance:

 

	switch (panel)		   // TODO: this isn't working. panel variable doesn't seem to be changing
         {
	        case AUTOPANEL:
			printf("AUTOPANEL");
			HidePanel(autopanel);
	                DisplayPanel(frontpanel);
	                break;
	        case MANPANEL:
			printf("MANPANEL");
			HidePanel(manualpanel);
	                DisplayPanel(frontpanel);
	                break;
	        case PASSPANEL:
			printf("PASSPANEL");
			HidePanel(passpanel);
	                DisplayPanel(frontpanel);
	                break;
	            case FRONTPANEL:
			printf("FRONTPANEL");
			QuitUserInterface(0);
	                break;
            }

 

However, when I do this, I get very unpredictable behavior.  It would appear that the panel switch isn't what I think it should be in the callback.  The value of panel seems to not match the macro value for the respective panels that I'm in when I click their QUIT buttons.

0 Kudos
Message 1 of 12
(4,066 Views)

Are AUTOPANEL, MANPANEL,... the panel handles you obtained using LoadPanel () ?

0 Kudos
Message 2 of 12
(4,060 Views)

Keep in mind that you need to pass the panel handle to HidePanel function, while it appears you are passing the panel constant names. This cannot work correctly as those values are very different!

 

As far as I can see, you have several panels: a main one, whose Quit button terminates the program, ans several other panels each of them hase a Close button that hides its panel and shows the main one. If this is the case, the callback can simply hide the panel whose handle is passed as a parametet to the function. The only test to perform is to check that variable against the handle of the main panel (which you must have global to the project). Something like this:

 

int CVICALLBACK ButtonCbk (int panel, int control, int event,
		void *callbackData, int eventData1, int eventData2)
{
  switch (event) {
    case EVENT_COMMIT:
      if (panel == mainPanelHandle)
         QuitUserInterface (0);
      else {
         HidePanel (panel);
         DisplayPanel (mainPanelHandle);
      }
      break;
  }
  return 0;
}

 

 



Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
0 Kudos
Message 3 of 12
(4,061 Views)

In a callback the value of panel will match the value of the handle obtained when you called LoadPanel().

 

You need to use these handles as your cases.

 

switch (panel)		   // TODO: this isn't working. panel variable doesn't seem to be changing
         {
	        case autopanel:
			printf("AUTOPANEL");
			HidePanel(autopanel);
	                DisplayPanel(frontpanel);
	                break;
	        case manualpanel:
			printf("MANPANEL");
			HidePanel(manualpanel);
	                DisplayPanel(frontpanel);
	                break;
	        case passpanel:
			printf("PASSPANEL");
			HidePanel(passpanel);
	                DisplayPanel(frontpanel);
	                break;
	            case frontpanel:
			printf("FRONTPANEL");
			QuitUserInterface(0);
	                break;
            }
0 Kudos
Message 4 of 12
(4,060 Views)

RobertoBozzolo wrote:

Keep in mind that you need to pass the panel handle to HidePanel function, while it appears you are passing the panel constant names. This cannot work correctly as those values are very different!

 

As far as I can see, you have several panels: a main one, whose Quit button terminates the program, ans several other panels each of them hase a Close button that hides its panel and shows the main one.


You are correct.  I have four panels, one of which is the "main" panel.  The others are little sub-panels. 

 


Wolfgang wrote:

Are AUTOPANEL, MANPANEL,... the panel handles you obtained using LoadPanel () ?


That's correct.  I load all four in my main function like this:

 

//-----------------------------------
// module globals
//-----------------------------------
int frontpanel;		// main panel
int manualpanel;	// manual control panel
int autopanel;		// automatic control panel
int passpanel;		// password panel

....

	frontpanel = LoadPanel (0, "panels.uir", FRONTPANEL);
	manualpanel = LoadPanel (0, "panels.uir", MANPANEL);
	autopanel = LoadPanel (0, "panels.uir", AUTOPANEL);
	passpanel = LoadPanel (0, "panels.uir", PASSPANEL);

	if (frontpanel < 0 || 
		manualpanel < 0 ||
		autopanel < 0 ||
		passpanel < 0) return -1;

simonnj wrote:

In a callback the value of panel will match the value of the handle obtained when you called LoadPanel().

 

You need to use these handles as your cases.


Ok, I attempted this, but I got a compiler error, stating that the cases need to be constant.  But I can't just declare them as const int, because I assign value to each of them in the LoadPanel call.

 


RobertoBozzolo wrote:

Keep in mind that you need to pass the panel handle to HidePanel function, while it appears you are passing the panel constant names. This cannot work correctly as those values are very different!


I'm confused.  Why are these values different?  I see now that this is so as I step through code. But how come LabWindows doesn't assign the same value to my LoadPanel return, as it assigns to the macros for the panel name?  In other words, I think it would obviously be convenient for this:

 

autopanel = LoadPanel(0, "panels.uir", AUTOPANEL);

...to be equal to this:

 

#define  AUTOPANEL    1

 

0 Kudos
Message 5 of 12
(4,052 Views)

I think you're a bit confused Smiley Wink Fortunately, it is possible to resolve it easily:

 

panel_handle = LoadPanel ( 0, file_name, panel_resource_id )

 

As you can see, panel_handle is the return value of the function call, while you have used the resource id. Or, citing the help: The function returns a panel handle that you use in subsequent function calls to specify the panel.

 

You can answer your question by looking into your UI include files: probably FRONTPANEL etc. all are defined as 1 (because the first panel in a UI file is enumerated as first element, hence 1, and all your four different UI files start enumerating panels / controls / menus with 1...) - so how should the program distinguish which panel / which '1' you have in mind? That's what the function LoadPanel is for, it creates a unique handle, while the constants may not be unique if there is more than one file...

Message 6 of 12
(4,049 Views)

Correct again, Wolfgang -- I'm confused!  But it won't be the first or last time.

 

I see what you are saying, that the resource IDs are not matching the return values of the function LoadPanel.  But let me ask another way: What are the resource IDs that are auto-generated for each panel for?  As you can see below, mine are not all 1. They increment at a top level structure, i.e., each panel constant is unique.  Then, each control within that panel starts at 2 and increments.

 

#define  AUTOPANEL                        1
#define  AUTOPANEL_QUITBUTTON             2       /* control type: command, callback function: QuitCallback */
#define  AUTOPANEL_GOBUTTON               3       /* control type: command, callback function: AutoStart */

#define  FRONTPANEL                       2
#define  FRONTPANEL_TEXTMSG               2       /* control type: textMsg, callback function: (none) */
#define  FRONTPANEL_TECHBUTTON            3       /* control type: command, callback function: ModeEntry */
#define  FRONTPANEL_ENGBUTTON             4       /* control type: command, callback function: ModeEntry */
#define  FRONTPANEL_QUITBUTTON            5       /* control type: command, callback function: QuitCallback */

#define  MANPANEL                         3
#define  MANPANEL_LED3                    2       /* control type: LED, callback function: (none) */
#define  MANPANEL_LED2                    3       /* control type: LED, callback function: (none) */
#define  MANPANEL_LED1                    4       /* control type: LED, callback function: (none) */
#define  MANPANEL_LED0                    5       /* control type: LED, callback function: (none) */
#define  MANPANEL_BINARYSWITCH3           6       /* control type: binary, callback function: ButtonFio3 */
#define  MANPANEL_BINARYSWITCH2           7       /* control type: binary, callback function: ButtonFio2 */
#define  MANPANEL_BINARYSWITCH1           8       /* control type: binary, callback function: ButtonFio1 */
#define  MANPANEL_BINARYSWITCH0           9       /* control type: binary, callback function: ButtonFio0 */
#define  MANPANEL_QUITBUTTON              10      /* control type: command, callback function: QuitCallback */
#define  MANPANEL_TEXTMSG4                11      /* control type: textMsg, callback function: (none) */
#define  MANPANEL_TEXTMSG3                12      /* control type: textMsg, callback function: (none) */
#define  MANPANEL_TEXTMSG2                13      /* control type: textMsg, callback function: (none) */
#define  MANPANEL_TEXTMSG1                14      /* control type: textMsg, callback function: (none) */

#define  PASSPANEL                        4
#define  PASSPANEL_PASSSTRING             2       /* control type: string, callback function: StringCallback */
#define  PASSPANEL_OKBUTTON               3       /* control type: command, callback function: OkCallback */
#define  PASSPANEL_QUITBUTTON             4       /* control type: command, callback function: QuitCallback */

 

0 Kudos
Message 7 of 12
(4,046 Views)

The panel constants are not identical 1 because they are all in the same UI file... but you could also load two or three UI files, what then?

 

Also, the include file does not distinguish between panels and controls, '2' can be both a panel and a control...

 

So what are these constants for - they are needed to generate a handle that is (always) unique Smiley Wink

Message 8 of 12
(4,043 Views)
Solution
Accepted by ElectroLund

Just to add some detail to Wolfgang answer, consider that you can load the same panel more than once, and each instance of it will have independent life! Smiley Surprised

 

Situation is as follows:

 

  • Each time you load a panel, you use the resource ID together with the filename; as you have noted, panel resource IDs are unique within the same UIR file, so that filename+resource ID identificates a single object.
  • When you actually load the panel, LoadPanel returns a panel handle, which in turns identifies it among the panels in memory; if you load the panel another time, the handle will be different. The system guarantees that panel handles are unique in the application, so that each of them identifies one single object. Using the panel handle to manipulate the panel itself or controls on it permits you to distinguish between all existing objects the exact one that you are interesting into even if you have previously loaded several instances of it
  • When you address one control on a panel, you use the control ID together with the panel handle; the resource IDs are unique within the same panel, so again panel handle + control ID identifies a single object among all those in memory


Proud to use LW/CVI from 3.1 on.

My contributions to the Developer Community
________________________________________
If I have helped you, why not giving me a kudos?
Message 9 of 12
(4,037 Views)

simonnj wrote:

In a callback the value of panel will match the value of the handle obtained when you called LoadPanel().

 

You need to use these handles as your cases.

 

switch (panel)		   // TODO: this isn't working. panel variable doesn't seem to be changing
         {
	        case autopanel:
			printf("AUTOPANEL");
			HidePanel(autopanel);
	                DisplayPanel(frontpanel);
	                break;
	        case manualpanel:
			printf("MANPANEL");
			HidePanel(manualpanel);
	                DisplayPanel(frontpanel);
	                break;
	        case passpanel:
			printf("PASSPANEL");
			HidePanel(passpanel);
	                DisplayPanel(frontpanel);
	                break;
	            case frontpanel:
			printf("FRONTPANEL");
			QuitUserInterface(0);
	                break;
            }

What I've learned is that switch statement cases must be known at compile time.  Because the above suggested cases are loaded during run-time with the return of LoadPanel(), they by definition are not constants at compile time. So a switch statement won't work there.  Bummer.

 

So a big ugly if-else block is in order for my situation, checking the panel handles.

0 Kudos
Message 10 of 12
(3,995 Views)