LabWindows/CVI

cancel
Showing results for 
Search instead for 
Did you mean: 

multithread and draw on childpanel

Hallo everybody,

I want to write from a multithread to a CANVAS on the childPanel of panelHandle.
How can I get the panelID to the multithread for writing on the childPanel?
Any ideas?
The examples of multithreading didn't help me. Perhaps you can suggest me one with some explanations...


my program is like:



int main (...) //main function
{
...
if ((panelHandle = LoadPanel(0, "test.uir", PANEL))<0) //load parentPanel
return -1;

tabCtrl = EasyTab_ConvertFromCanvas (panelHandle, PANEL_TABCANVAS); //first tabpanel
EasyTab_LoadPanels(panelHandle, tabCtrl, 1, "test.uir", __CVIUserInst, TABPANEL, &childpanel, 0);

childpanel = LoadPanel(PANEL, "test.uir", CHILDPANEL); //load childPanel

DisplayPanel (panelHandle);

RunUserInterface();
DiscardPanel (panelHandle);
return 0;
}

int CVICALLBACK BUTTON_FUNC (int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
...
CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, multithread_func, NULL, NULL);
...
return 0;
}



int multithread_func (void *FunctionData) //multithread function
{
...
CanvasDrawBitmap(...);
SetCtrlAttribute(..., ATTR_PEN_COLOR,...);
SetCtrlAttribute(..., ATTR_PEN_FILL_COLOR,...);
CanvasDrawRect(...);
ProcessDrawEvents();
...
return 0;
}




Thank you very much!
Florian
0 Kudos
Message 1 of 10
(3,635 Views)
You have two options:

The simplest, but the least desirable from a software engineering standpoint, is to turn the panel handle that you want to use in the thread function into a global variable. If it's a global, you can access it from any function, regardless of thread.

The other option is to pass the panel handle to the thread function via the FunctionData parameter. This parameter is there precisely so that you can pass in any four-byte data item that you want your thread function to use. Simply pass the panel handle to CmtScheduleThreadPoolFunction as the 3rd parameter to the function, instead of NULL.

If you chose the second option, you will also have to have access to the panel handle in your control callback, where you create the thread. I don't know if the canvas is in the same panel as the control that starts the thread. If it's not, then you will have to pass the panel of the canvas to the control callback using the callbackData parameter, or if you can, navigate to that panel using GetPanelAttribute. You can do this if there is a child/parent relationship between the two panels.

Luis
NI
0 Kudos
Message 2 of 10
(3,616 Views)
OK, when I understand your answer correct. Can I use the name "childpanel" everywhere, when I declare it as public.

====
to declare something as public:
put this between initialisation and main_function? :

static int childpanel

Is that correct?

Thanks for your answer.
Florian
0 Kudos
Message 3 of 10
(3,593 Views)
Florian >> To declare a variable as public to all functions in a project add them to a .h file that you #include in all modules in your project. Variables declared in a module pertains only to that module and are visible only to functions included in the module itself.

Luis >> Exactly why you consider "not desirable" that panel handles are global variables? They are substantially read only variables, so there should be no problem in sharing between different threads. I don't expect there is a lock or a race condition on such a variable. Can you explain me a little more, please?


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 4 of 10
(3,587 Views)
Roberto,

It's not because of ultithreading issues that they're not considerable desirable. I was just speaking from a general software engineering perspective. Overuse of global variables breaks the compartmentalization of the code, which you need to have when projects grow beyond a certain size. But for small programs, it really doesn't matter much.

C is not inherently an object-oriented language, but it can be made somewhat object-oriented by employing data abstraction and encapsulation principles to make the different pieces work as independently as possible. This allows the code to grow and to be maintained while minimizing the interactions between all the different pieces. Otherwise, whenever one piece of code is refactored, or a bug is fixed, you have a huge testing burden, since it can conceivably affect a very large chunk of your application.

Luis
0 Kudos
Message 5 of 10
(3,582 Views)
Luis >> Well put. Most programs that we write will use some global variables, but they can contribute to hard to maintain code if overused.

The only thing I want to add the general discussion is there are certain cases where the actual integer value of the panel handle will change (for instance, if you were duplicating a panel, discarding the original, and writing the new panel handle value to the original panel handle variable.) Maybe this wouldn't be a problem in certain cases... like if your function only operates for a short period of time and is called often. Still, if you're doing this anywhere in your code, the best way might be the global variable method and use a thread lock.
0 Kudos
Message 6 of 10
(3,573 Views)
My problem now:
the program runs, but when I close it, this error appears:
"invalid contol id" in the line of the "MULTITHREAD CODE" in the command line of "CanvasDrawBitmap"
 
When I don't write "movepanel = panel;" in the commandbutton code and use the variable "beweg" instead of "movepanel"  than I get directly the error: "panel, pop-up, or menu bar handle is invalid"
 
How can I solve this problem?
 
 
A summery of my code:
 
public variable are :
 
int beweg;
int movepanel;
 
//=======================================================================================
//  MAIN PROGRAM
 
...main...
{
tabCtrl = EasyTab_ConvertFromCanvas (panelHandle, PANEL_TABCANVAS);
EasyTab_LoadPanels (panelHandle, tabCtrl, 1, "Teilnehmersimulator.uir", __CVIUserHInst, BEWEGPAN, 0, 0);
 
beweg = LoadPanel(PANEL, "Teilnehmersimulator.uir", BEWEGPAN);
DisplayPanel(panelHandle);
RunUserInterface();
return 0;
}
 
//========================================================================================
//  COMMANDBUTTON WHICH HAS TO START THE MULTITHREAD
 
int CVICALLBACK ROUTESTART_FUNC (int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
 movepanel = panel;
 CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, ShowMove_FUNC, NULL, NULL);
 return 0;
}
//=========================================================================================
//  MULTITHREAD CODE
 
int CVICALLBACK ShowMove_FUNC (void *functionData)
{
SetCtrlAttribute (movepanel, BEWEGPAN_ROUTESTARTBUTTON, ATTR_DIMMED, 1)
...
  CanvasDrawBitmap (movepanel, BEWEGPAN_CANVASKARTE, map, MakeRect(lastDisplayY, lastDisplayX, 7, 7), MakeRect(lastDisplayY, lastDisplayX, VAL_KEEP_SAME_SIZE, VAL_KEEP_SAME_SIZE));
...
}
 
Thank you two!
Florian

Message Edited by Greber on 07-11-2005 07:33 AM

0 Kudos
Message 7 of 10
(3,513 Views)

Hallo everybody,

I've decided to try to pass the panel handle to the thread function via the functionData parameter.

 

@Luis:

You wrote:

"This parameter is there precisely so that you can pass in any four-byte data item that that you want your thread function use. Simply pass the panel handle to CmtScheduleThreadPoolFunction as the 3rd parameter to the function, instead of NULL."

 

How do I have to change the "3rd parameter" to give the Panel "int CHILDPANEL" to this thread?

CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, MULTITHREAD_FUNCTION, "3rd parameter", NULL);

 

THX

0 Kudos
Message 8 of 10
(3,494 Views)
Florian,
 
The function call would look something like this:
 
CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, MULTITHREAD_FUNCTION, (void *)childpanel, NULL);

Then, inside the thread function, the code would look like this:

 
int CVICALLBACK BUTTON_FUNC (int panel, int control, int event, void *callbackData, int eventData1, int eventData2)
{
int
...
CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, multithread_func, NULL, NULL);
...
return 0;
}
0 Kudos
Message 9 of 10
(3,476 Views)
I'm sorry. Please ignore the last message. I must have accidentally clicked on "Submit"
 
Use this reply instead:
 
--------------------------------
 
Florian,
 
The function call would look something like this:
 
CmtScheduleThreadPoolFunction(DEFAULT_THREAD_POOL_HANDLE, MULTITHREAD_FUNCTION, (void *)childpanel, NULL);

Then, inside the thread function, the code would look like this:

int multithread_func (void *FunctionData) //multithread function
{
int panel = (int)functionData;
...
CanvasDrawBitmap(...);
SetCtrlAttribute(..., ATTR_PEN_COLOR,...);
SetCtrlAttribute(..., ATTR_PEN_FILL_COLOR,...);
CanvasDrawRect(...);
ProcessDrawEvents();
...
return 0;
}

0 Kudos
Message 10 of 10
(3,472 Views)