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(int *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->Visible = true;
                  listBox22->BeginUpdate();
                  listBox22->Items->Clear();
                  listBox22->Items->Add(ACSideNum);
                  listBox22->EndUpdate();
                  break;
            case 2:      
                  pictureBox3->Visible = true;
                  listBox23->BeginUpdate();
                  listBox23->Items->Clear();
                  listBox23->Items->Add(ACSideNum);
                  listBox23->EndUpdate();
                  break;
            case 3:
                  pictureBox4->Visible = true;
                  listBox24->BeginUpdate();
                  listBox24->Items->Clear();
                  listBox24->Items->Add(ACSideNum);
                  listBox24->EndUpdate();
                  break;
            case 4:
                  pictureBox5->Visible = true;
                  listBox25->BeginUpdate();
                  listBox25->Items->Clear();
                  listBox25->Items->Add(ACSideNum);
                  listBox25->EndUpdate();
                  break;
            case 5:
                  pictureBox6->Visible = true;
                  listBox26->BeginUpdate();
                  listBox26->Items->Clear();
                  listBox26->Items->Add(ACSideNum);
                  listBox26->EndUpdate();
                  break;
         }
      return;
}


void Form1::ClientSocketProc(int *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",QueueInfo[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(QueueArray);
                             ....
      }
}

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
John500Asked:
Who is Participating?
 
DanRollinsCommented:
>> ...but the only function that is calling the pictureBox is thread itself ...

The issue with the control is that it would have been created by the U/I thread and is being accessed by the worker thread(s).

>> At any rate, since ' InvokeRequired ' returned ' true ' what is the next step

You need to use the Invoke or BeginInvoke.  I have not used the technique, but AlexFM has posted a nice example here:
  http://www.experts-exchange.com/Programming/Programming_Languages/Dot_Net/VisualC_PLUS_PLUS_DOT_NET/Q_21022249.html

I find this whole Invoke/delegate business tough going (it's probably easier than it seems, but all the example code tends to be in C#).  

Since your goal is to just tell the U/I control to hide or unhide itself, It seems to me that you could do a PostMessage sending it WM_SHOWWINDOW (which is very likely all that is happening when you set  Control::Visble to true)

-- Dan
0
 
DanRollinsCommented:
You should try PictureBox::InvokeRequired()

      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->Visible = true;
       Form1::pictureBox2->Invalidate();
to force a redraw.

-- Dan
0
 
John500Author Commented:
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(QueueArray);
               LineUp = QueueArrary[0];
               swithch(LineUp){
                     case 1:
                              bool TestInvoke;
                              TestInvoke = pictureBox2->InvokeRequired();
                              ....
     }
}

Incidently, without the ' pictureBox2->InvokeRequired() ' 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
0
Free Tool: SSL Checker

Scans your site and returns information about your SSL implementation and certificate. Helpful for debugging and validating your SSL configuration.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
DanRollinsCommented:
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
0
 
John500Author Commented:
>> 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 ?
0
 
John500Author Commented:
Dan,

Thanks for the help.  I found this to be the answer:

Form1.h
-----------

public __gc class Form1 : public System::Windows::Forms::Form
{
     ....
     ....
     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::HandlePictureBox1Update()
{
       pictureBox1->Visible = PictureBox1State;      // boolean sets pictureBox state
}

MyPictureSettingFunction(bool PictureState)
{
       PictureBox1State = PictureState;
       if(pictureBox1->IsHandleCreated && pictureBox2->InvokeRequired)
       {
      // Invoke the UI thread handler to change the PictureBox visibility
      pictureBox1->Invoke( __gc new System::Threading::ThreadStart(this, &Form1::HandlePictureBox1Update));
       }
}
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.