Go Premium for a chance to win a PS4. Enter to Win

x
?
Solved

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

Posted on 2006-06-13
6
Medium Priority
?
285 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
Free Tool: Subnet Calculator

The subnet calculator helps you design networks by taking an IP address and network mask and returning information such as network, broadcast address, and host range.

One of a set of tools we're offering as a way of saying thank you for being a part of the community.

 

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 1000 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

Keep up with what's happening at Experts Exchange!

Sign up to receive Decoded, a new monthly digest with product updates, feature release info, continuing education opportunities, and more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

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…
We’ve all felt that sense of false security before—locking down external access to a database or component and feeling like we’ve done all we need to do to secure company data. But that feeling is fleeting. Attacks these days can happen in many w…
Screencast - Getting to Know the Pipeline
Suggested Courses
Course of the Month7 days, 21 hours left to enroll

824 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