LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

place the cursor

Hello everybody!!
 
My question is the following:
 
In the program I've developed there is a numeric control where the user must enter a value.
If the entered value is out of range, the program pops up a message, warning the user about this fact.
 
I want the cursor returns to the numeric control in order to change the value, once the user has clicked the "OK" button to accept the message. How can i do this?
 
I attached a brief example of this part of the program.
 
GetCtrlVal(PANEL, PANEL_Nivel_Campo, &nivel_campo);
if((nivel_campo<20)||(nivel_campo>125))
    MessagePopup("ERROR", "Margen de nivel de campo: 20-125");
 
Thanks for advanced!!
 
 
 
0 Kudos
Message 1 of 7
(3,873 Views)
Sorry but I have another question for you guys!!
 
I'm trying to acquire data and plot them into a graph. To do this I've implemented three buttons called "START", "PAUSE", "CONTINUE" with their associated callback functions.
 
When the panel is displayed the "PAUSE" and "CONTINUE" buttons are initially dimmed. My intention is to enable theese buttons after the user has clicked the "START" so he could pause the acquisition and resume it whenever he wants. See the code lines below:
 
 
int CVICALLBACK Start (int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2)
{
 double umbral;
 int medida=1, indice=0;
 char indica[200];
 static double traza[500L];
 char Linea_Fichero[200];
 
 switch (event)
 {
  case EVENT_COMMIT:
   
   GetCtrlVal(PANEL, PANEL_Nivel_Campo, &nivel_campo);
   if((nivel_campo<20)||(nivel_campo>125))
    MessagePopup("ERROR", "Margen de nivel de campo: 20-125");
   
   GetCtrlVal(PANEL, PANEL_Tolerancia_Superior, &tol_inf);
   if((tol_inf>1)||(tol_inf<0.1))
    MessagePopup("AVISO", "Tolerancia Superior recomendada: 0.1-1");
     
   GetCtrlVal(PANEL, PANEL_Tolerancia_Inferior, &tol_sup);
   if((tol_sup>1)||(tol_sup<0.1))
    MessagePopup("AVISO", "Tolerancia Inferior recomendada: 0.1-1");
   
   fichero=OpenFile(Nombre_Fichero, VAL_WRITE_ONLY, VAL_TRUNCATE, VAL_ASCII);
   if(GetFmtIOError()>0)
    SetCtrlVal(PANEL, PANEL_Comentario, "ERROR AL MANEJAR EL FICHERO");
   else
   {
    SetCtrlVal(PANEL, PANEL_Comentario, "");
    
    SetCtrlAttribute (PANEL, PANEL_PAUSE, ATTR_DIMMED, 0);
    SetCtrlAttribute (PANEL, PANEL_CONTINUE, ATTR_DIMMED, 0);
.
.
.
 
As you can see the last two statements are written for my purpose, but the buttons only become active when the callback function Start has finished and the acquisition of data is out.
How can I solve this problem?
 
Thanks a lot for your interest.. Bye. 
 
 
 
0 Kudos
Message 2 of 7
(3,868 Views)

Your first question can be solved by using SetActiveCtrl (PANEL, PANEL_Nivel_Campo); after MessagePopup () function: this sets the numeric control as the active control (i.e. the one that has the user input).

The second question is normally due to the function not leaving space for the system to update control values and state and so on. That is: if all of your process lies inside the callback function, your program is stuck inside it and no other tasks can be executed until the callback ends. It is well possible that not only buttons are not undimmed, but even if they were, pressing them will lead to no action, since the system cannot execute their callback.
When a process is long lasting it is normally a good practice not to develop it inside a single control callback, but structure it as a separate process that leaves the user interface unlocked to permit user interaction with the system. You will then need to tailor the exact actions that are permitted to the user while inside the acquisition (e.g. avoid launching the process a second time and so on). Usual ways to make a routine a separate process are spawning a new thread or making a state machine inside a timer callback. An alternative approach could be to insert ProcessDrawEvents ()  or ProcessSystemEvents () inside your code but I would discourage this practice as it may lead to unforeseen situations that are difficult to debug and correct.

As a side comment, I noted that you are using PANEL as the first parameter of user interface function: remember that the first parameter of SetCtrlAttribute or SetCtrlVal or similar functions is the panel handle, not the panel constant name. The panel handle is the value returned by LoadPanel () function and it is unique in the whole application (i.e. even if you load a panel two times -which is admitted and safe- each instance has its own unique identifier); the use of the unique panel handle prevents confusion while addressing a control, since only one panel at a time can have a specific handle during program life.



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 7
(3,847 Views)

Thank you, Roberto for all your tips!!

I hope they woluld be helpful for me to make progress with my program.

I'll sure be back with more questions soon. Untill then, best wishes!

0 Kudos
Message 4 of 7
(3,835 Views)
You're welcome!


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 5 of 7
(3,831 Views)

Hi again everybody!

I'm writing regarding to the first doubt I posted few days ago.

To clarify my question I,m giving a brief example of a program.

int CVICALLBACK Light (int panel, int control, int event,
  void *callbackData, int eventData1, int eventData2)
{
 int val_X;
 
 switch (event)
 {
  case EVENT_COMMIT:
   
   GetCtrlVal(panelHandle, PANEL_NUM_X, &val_X);
   if((val_X<1)||(val_X>5))
   {
    MessagePopup("ERROR", "Range NUM_X 1 to 5");
    SetActiveCtrl(panelHandle, PANEL_NUM_X);
   }
   
   SetCtrlVal (panelHandle, PANEL_LED, 1);
   
   break;
  case EVENT_RIGHT_CLICK:

   break;
 }
 return 0;
}

Imaging that we have a LED which lights when the value of a numeric control is in a range from 1 to 5; any other way the LED should be off. When the user introduces a value out of range the MessagePopup function reports him about the available range. At this point the program should request for another value until the user enters one within the range, so the numeric control should be active to get the new value. To do this I use the SetActiveCtrl function as Roberto suggested me, however, after that the LED lights even with a wrong value.

Should I use a "while" structure instead or what's wrong?

Thank you for your support.

 

0 Kudos
Message 6 of 7
(3,774 Views)

Well, there are a couple of hints on your problem.

1. You are never turning off the led (or better: you are always turning it on)! You could try something like this:

   GetCtrlVal(panelHandle, PANEL_NUM_X, &val_X);
   if ((val_X<1) || (val_X>5))
   {
    MessagePopup("ERROR", "Range NUM_X 1 to 5");
    SetCtrlVal (panelHandle, PANEL_LED, 1);
    SetActiveCtrl(panelHandle, PANEL_NUM_X);
   }
   else
      SetCtrlVal (panelHandle, PANEL_LED, 0);
  
2. This callback is attached to the numerico control, right? If this is the case, you are receiving the panel handle and control ID as the first parameter of the function; that is, your first line could be modified as follows:

   GetCtrlVal(panel, control, &val_X);

3. You may consider limiting the control values to 1 to 5 range only. To do this edit the control and A.Place appropriate values in "Minimum" and "Maximum" fields  B.Set "Range checking" field to "Coerce". by doing this the user is limited to the valid range: even if he inputs a value out of range, it is clipped to the nearest limit immediately before any control event.



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 7 of 7
(3,772 Views)