Solved

Need to know why my picture boxes won't display during runtime

Posted on 2006-06-13
6
274 Views
Last Modified: 2010-08-05
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
0
Comment
Question by:John500
  • 3
  • 3
6 Comments
 
LVL 49

Expert Comment

by:DanRollins
ID: 16898603
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
 

Author Comment

by:John500
ID: 16899053
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
 
LVL 49

Expert Comment

by:DanRollins
ID: 16906516
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
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:John500
ID: 16913222
>> 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
 
LVL 49

Accepted Solution

by:
DanRollins earned 250 total points
ID: 16915489
>> ...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
 

Author Comment

by:John500
ID: 17015793
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

Featured Post

Highfive Gives IT Their Time Back

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

The following diagram presents a diamond class hierarchy: As depicted, diamond inheritance denotes when two classes (e.g., CDerived1 and CDerived2), separately extending a common base class (e.g., CBase), are sub classed simultaneously by a fourt…
In Easy String Encryption Using CryptoAPI in C++ (http://www.experts-exchange.com/viewArticle.jsp?aid=1193) I described how to encrypt text and recommended that the encrypted text be stored as a series of hexadecimal digits -- because cyphertext may…
Internet Business Fax to Email Made Easy - With eFax Corporate (http://www.enterprise.efax.com), you'll receive a dedicated online fax number, which is used the same way as a typical analog fax number. You'll receive secure faxes in your email, fr…
Get a first impression of how PRTG looks and learn how it works.   This video is a short introduction to PRTG, as an initial overview or as a quick start for new PRTG users.

743 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now