John500
asked on
Need to know why my picture boxes won't display during runtime
Greetings:
I have a Form Application and I'm using a thread to call a procedure that sets the 'Visible' state of a few pictures on the Form. For some reason the pictures won't display if I use the thread, only the frame of the picture box will show.
If I don't use a thread to make the call, the pictures show fine. Here is the basic call sequence with the thread:
void Form1::SetPictureStatus(in t *PictureUpdate, int *PictureNumber)
{
int PicUpdate = PictureUpdate;
char SideNumBuff[10];
sprintf(SideNumBuff,"%d", PictureNumber]);
String *ACSideNum = __gc new String(SideNumBuff);
switch (PicUpdate) {
case 1:
Form1::pictureBox2->Visibl e = true;
listBox22->BeginUpdate();
listBox22->Items->Clear();
listBox22->Items->Add(ACSi deNum);
listBox22->EndUpdate();
break;
case 2:
pictureBox3->Visible = true;
listBox23->BeginUpdate();
listBox23->Items->Clear();
listBox23->Items->Add(ACSi deNum);
listBox23->EndUpdate();
break;
case 3:
pictureBox4->Visible = true;
listBox24->BeginUpdate();
listBox24->Items->Clear();
listBox24->Items->Add(ACSi deNum);
listBox24->EndUpdate();
break;
case 4:
pictureBox5->Visible = true;
listBox25->BeginUpdate();
listBox25->Items->Clear();
listBox25->Items->Add(ACSi deNum);
listBox25->EndUpdate();
break;
case 5:
pictureBox6->Visible = true;
listBox26->BeginUpdate();
listBox26->Items->Clear();
listBox26->Items->Add(ACSi deNum);
listBox26->EndUpdate();
break;
}
return;
}
void Form1::ClientSocketProc(in t *QueueInfo)
{
int DemoStat;
int retstat = -1;
char SideNumBuff[10];
string TempSideNum;
LandingInfo QueueObj;
LandingInfo *QueObj = &QueueObj;
DemoStat = GetPanelInfo();
if((QueueInfo[1] == 1) && (DemoStat == 1)){
QueueInfo[0]++; // increment queue lineup
QueueInfo[2]++; // increment side number
sprintf(SideNumBuff,"%d",Q ueueInfo[2 ]);
TempSideNum = SideNumBuff;
QueueObj.SideNum = TempSideNum;
QueueObj.LineUpNum = QueueInfo[0];
QueueInfo[1] = insertAirObject(&AircraftQ ,QueueObj) ;
SetPictureStatus(QueueInfo [0], QueueInfo[2]);
}
return;
}
void Form1::MainPanelThreadProc ()
{
int QueueArray[4];
QueueArray[0] = 0; // lineup
QueueArray[1] = 1; // queue status: 0-full, 1- room remains
QueueArray[2] = 499; // side number
for(;;){
if((SocketFlag == 1) && (QueueArray[1] != 0))
ClientSocketProc(QueueArra y);
....
}
}
What do I need to do in order to make the pictures show using the thread ? As I said, the pictures show fine without the thread, but with the thread --> only the picture box/frame will display.
Thanks
I have a Form Application and I'm using a thread to call a procedure that sets the 'Visible' state of a few pictures on the Form. For some reason the pictures won't display if I use the thread, only the frame of the picture box will show.
If I don't use a thread to make the call, the pictures show fine. Here is the basic call sequence with the thread:
void Form1::SetPictureStatus(in
{
int PicUpdate = PictureUpdate;
char SideNumBuff[10];
sprintf(SideNumBuff,"%d", PictureNumber]);
String *ACSideNum = __gc new String(SideNumBuff);
switch (PicUpdate) {
case 1:
Form1::pictureBox2->Visibl
listBox22->BeginUpdate();
listBox22->Items->Clear();
listBox22->Items->Add(ACSi
listBox22->EndUpdate();
break;
case 2:
pictureBox3->Visible = true;
listBox23->BeginUpdate();
listBox23->Items->Clear();
listBox23->Items->Add(ACSi
listBox23->EndUpdate();
break;
case 3:
pictureBox4->Visible = true;
listBox24->BeginUpdate();
listBox24->Items->Clear();
listBox24->Items->Add(ACSi
listBox24->EndUpdate();
break;
case 4:
pictureBox5->Visible = true;
listBox25->BeginUpdate();
listBox25->Items->Clear();
listBox25->Items->Add(ACSi
listBox25->EndUpdate();
break;
case 5:
pictureBox6->Visible = true;
listBox26->BeginUpdate();
listBox26->Items->Clear();
listBox26->Items->Add(ACSi
listBox26->EndUpdate();
break;
}
return;
}
void Form1::ClientSocketProc(in
{
int DemoStat;
int retstat = -1;
char SideNumBuff[10];
string TempSideNum;
LandingInfo QueueObj;
LandingInfo *QueObj = &QueueObj;
DemoStat = GetPanelInfo();
if((QueueInfo[1] == 1) && (DemoStat == 1)){
QueueInfo[0]++; // increment queue lineup
QueueInfo[2]++; // increment side number
sprintf(SideNumBuff,"%d",Q
TempSideNum = SideNumBuff;
QueueObj.SideNum = TempSideNum;
QueueObj.LineUpNum = QueueInfo[0];
QueueInfo[1] = insertAirObject(&AircraftQ
SetPictureStatus(QueueInfo
}
return;
}
void Form1::MainPanelThreadProc
{
int QueueArray[4];
QueueArray[0] = 0; // lineup
QueueArray[1] = 1; // queue status: 0-full, 1- room remains
QueueArray[2] = 499; // side number
for(;;){
if((SocketFlag == 1) && (QueueArray[1] != 0))
ClientSocketProc(QueueArra
....
}
}
What do I need to do in order to make the pictures show using the thread ? As I said, the pictures show fine without the thread, but with the thread --> only the picture box/frame will display.
Thanks
ASKER
Dan,
I understand what you are getting at. In order to get a better feel for the problem, I put all the 'case' right in the thread. Hence, no additional method outside of the thread itself. So it looks something like this:
void Form1::MainPanelThreadProc ()
{
int QueueArray[4];
QueueArray[0] = 0; // lineup
QueueArray[1] = 1; // queue status: 0-full, 1- room remains
QueueArray[2] = 499; // side number
for(;;){
if((SocketFlag == 1) && (QueueArray[1] != 0))
ClientSocketProc(QueueArra y);
LineUp = QueueArrary[0];
swithch(LineUp){
case 1:
bool TestInvoke;
TestInvoke = pictureBox2->InvokeRequire d();
....
}
}
Incidently, without the ' pictureBox2->InvokeRequire d() ' line the pictures don't show and when I added the Invalidate(); line that didn't change things either.
When I try to compile this with the InvokedRequired() line, I get the error:
C2064: term does not evaluate to a function taking 0 arguements
What's up with that, any ideas ? Also, assuming I get this to compile and it returns ' true ', what is the syntax or invoke method I would use ? Thanks
I understand what you are getting at. In order to get a better feel for the problem, I put all the 'case' right in the thread. Hence, no additional method outside of the thread itself. So it looks something like this:
void Form1::MainPanelThreadProc
{
int QueueArray[4];
QueueArray[0] = 0; // lineup
QueueArray[1] = 1; // queue status: 0-full, 1- room remains
QueueArray[2] = 499; // side number
for(;;){
if((SocketFlag == 1) && (QueueArray[1] != 0))
ClientSocketProc(QueueArra
LineUp = QueueArrary[0];
swithch(LineUp){
case 1:
bool TestInvoke;
TestInvoke = pictureBox2->InvokeRequire
....
}
}
Incidently, without the ' pictureBox2->InvokeRequire
When I try to compile this with the InvokedRequired() line, I get the error:
C2064: term does not evaluate to a function taking 0 arguements
What's up with that, any ideas ? Also, assuming I get this to compile and it returns ' true ', what is the syntax or invoke method I would use ? Thanks
It must be that InvokeRequired is treated as a member variable. TYe it without the parentheses.
There are some additional warnings related to cross-threading access to U/I elements:
http://msdn2.microsoft.com/en-us/system.windows.forms.control.invokerequired.aspx
It seems that if the HANDLE for the control has not been created, the InvokeRequied property can contain an incorrect value.
>> Hence, no additional method outside of the thread itself.
BTW, moving code around does not put it inside of or outside of the thread. It is important to realize that a thread is not a place: it is a concept... the action of a executing some code (not the code itself). A function -- global or object memeber function -- can be executed by any thread that calls that function.
=-=-=-=-=-=-=-=
In non-DotNet MFC apps, I have had to go to great lengths to insure that worker threads do not access ListBoxes or other controls. For instance, I've had to have the worker threads just add to a queue of "U/I things that need to be done" and have the main thread process that queue periodically on a Window Timer.
-- Dan
There are some additional warnings related to cross-threading access to U/I elements:
http://msdn2.microsoft.com/en-us/system.windows.forms.control.invokerequired.aspx
It seems that if the HANDLE for the control has not been created, the InvokeRequied property can contain an incorrect value.
>> Hence, no additional method outside of the thread itself.
BTW, moving code around does not put it inside of or outside of the thread. It is important to realize that a thread is not a place: it is a concept... the action of a executing some code (not the code itself). A function -- global or object memeber function -- can be executed by any thread that calls that function.
=-=-=-=-=-=-=-=
In non-DotNet MFC apps, I have had to go to great lengths to insure that worker threads do not access ListBoxes or other controls. For instance, I've had to have the worker threads just add to a queue of "U/I things that need to be done" and have the main thread process that queue periodically on a Window Timer.
-- Dan
ASKER
>> Try it without the parentheses
That was the problem.... and it did return ' true '
>> A function -- global or object memeber function -- can be executed by any thread that calls that function.
Yes but the only function that is calling the pictureBox is thread itself --> each time the thread makes one iteration. With each iteration of the for lool ( for(;;) ) the appropriate picture box is updated. This should not be a case of cross-threading or multithreading.
I decided to go with your idea of removing all threads and only having one thread that calls individual sockets for an update during each iteration. You mentioned this idea in this question:
http:Q_21864971.html
I'll close that question if you don't want to consider the multithreading scenario.
At any rate, since ' InvokeRequired ' returned ' true ' what is the next step ? What must I do ?
That was the problem.... and it did return ' true '
>> A function -- global or object memeber function -- can be executed by any thread that calls that function.
Yes but the only function that is calling the pictureBox is thread itself --> each time the thread makes one iteration. With each iteration of the for lool ( for(;;) ) the appropriate picture box is updated. This should not be a case of cross-threading or multithreading.
I decided to go with your idea of removing all threads and only having one thread that calls individual sockets for an update during each iteration. You mentioned this idea in this question:
http:Q_21864971.html
I'll close that question if you don't want to consider the multithreading scenario.
At any rate, since ' InvokeRequired ' returned ' true ' what is the next step ? What must I do ?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Dan,
Thanks for the help. I found this to be the answer:
Form1.h
-----------
public __gc class Form1 : public System::Windows::Forms::Fo rm
{
....
....
private:
// used to toggle state of picture
bool PictureBox1State;
// Handlers to set the PictureBox controls Visible property
System::Void HandlePictureBox1Update();
private: System::Void Form1_Load(System::Object * sender, System::EventArgs * e)
{
// Set the PictureBox controls back to Visible=false once the handles
// have been created but before the Form is displayed.
pictureBox1->Visible = false;
...
}
...
...
}
Form1.cpp
-------------
void Form1::HandlePictureBox1Up date()
{
pictureBox1->Visible = PictureBox1State; // boolean sets pictureBox state
}
MyPictureSettingFunction(b ool PictureState)
{
PictureBox1State = PictureState;
if(pictureBox1->IsHandleCr eated && pictureBox2->InvokeRequire d)
{
// Invoke the UI thread handler to change the PictureBox visibility
pictureBox1->Invoke( __gc new System::Threading::ThreadS tart(this, &Form1::HandlePictureBox1U pdate));
}
}
Thanks for the help. I found this to be the answer:
Form1.h
-----------
public __gc class Form1 : public System::Windows::Forms::Fo
{
....
....
private:
// used to toggle state of picture
bool PictureBox1State;
// Handlers to set the PictureBox controls Visible property
System::Void HandlePictureBox1Update();
private: System::Void Form1_Load(System::Object * sender, System::EventArgs * e)
{
// Set the PictureBox controls back to Visible=false once the handles
// have been created but before the Form is displayed.
pictureBox1->Visible = false;
...
}
...
...
}
Form1.cpp
-------------
void Form1::HandlePictureBox1Up
{
pictureBox1->Visible = PictureBox1State; // boolean sets pictureBox state
}
MyPictureSettingFunction(b
{
PictureBox1State = PictureState;
if(pictureBox1->IsHandleCr
{
// Invoke the UI thread handler to change the PictureBox visibility
pictureBox1->Invoke( __gc new System::Threading::ThreadS
}
}
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemwindowsformscontrolclassinvokerequiredtopic.asp
to see if you must use an Invoke call to force visibility. From that page:
Controls in Windows Forms are bound to a specific thread and are not thread safe.
Therefore, if you are calling a control's method from a different thread, you must
use one of the control's invoke methods to marshal the call....
Additional info about cross-thread handling:
Multithreaded Windows Forms Control Sample
http://msdn.microsoft.com/library/en-us/cpguide/html/cpconDevelopingMultithreadedWindowsFormsControl.asp
=-=-=-=-=-=-=-=-=-=
If that is not the issue, then you could also try (e.g.)
Form1::pictureBox2->Visibl
Form1::pictureBox2->Invali
to force a redraw.
-- Dan