CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 5 of 5
  1. #1
    Join Date
    Apr 2012
    Posts
    5

    [RESOLVED] How to use Picturebox's Invoke method in C++

    Hi,

    The language that I'm using is C++. I have a backgroundworker to prevent my UI from crashing. However, within the background function I need to update my UI. I read that using the control's Invoke will do the trick. However, I can't seem to make it work. The code is as follows:

    pictureBox2->Invoke((MethodInvoker^) delegate(){
    pictureBox2->Image = btmp;
    pictureBox2->Update();
    });

    error C2065: 'delegate' : undeclared identifier
    error C2143: syntax error : missing ')' before '{'
    error C2143: syntax error : missing ';' before '{'
    error C2059: syntax error : ')'

    Any ideas? Thanks! Any help would be greatly appreciated!

  2. #2
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: How to use Picturebox's Invoke method in C++

    I'm not completely sure whether I really get what you want to express with that obscure syntax, but if it's setting the picture box' Image property and then call its Update() method, both as cross-thread calls, then it would go like this (assuming the background worker work function and the picture box are members of the same form class instance):

    Code:
    pictureBox2->Invoke(gcnew Action<Image ^>(pictureBox2, &PictureBox::Image::set), btmp);
    pictureBox2->Invoke(gcnew Action(pictureBox2, &PictureBox::Update));
    As you're probably not blocking your GUI thread (which probably was at least one of the main reasons why you're using a worker thread in the first place), invoking Update() probably isn't even necessary.

    But there's an alternative option here that you may find simpler: While the MSDN documentation superficially suggests that you can only pass a progress percentage and the handle to the object you got passed in via RunWorkerAsync() to the two-paremeter overload of ReportProgress(), in fact this is not the case. For instanxce, I like to pass a per-mille value rather than a percentage value as the first parameter to get more fine-grained progress reporting. But of course it's not limited to that either; you may pass anything that fits into an int.

    However, much more important is the second parameter: You may practically pass anything you like though that parameter, in this specific case btmp. You need to observe the principles of thread safety when doing that, but you'd need to do that when using Invoke() as well. Using the progress reporting facility just hides the cross-thread call inside the BackgroundWorker class. One technique I really like to use in that context is passing "fire and forget" packets as that second parameter: Once you passed them to ReportProgress(), never touch them (or any objects directly or indirectly referenced by them) again from inside the worker thread. That way you're always on the safe side regarding potential multithreading issues. And of course, the safest way to ensure that is simply not keeping a handle to the progress packet inside your worker function once you passed it.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  3. #3
    Join Date
    Apr 2012
    Posts
    5

    Re: How to use Picturebox's Invoke method in C++

    Hi,

    Many thanks! It's exactly what I need. I think I can't use the ReportProgress() function since I update a lot of GUI controls on the function associated with RunWorkerAsync(). Moreover, do you have an article that explains the syntax of what you showed me because I can't seem to make it work now for RichTextBox. My code is:

    richTextBox1->Invoke(gcnew Action<array<String^>^>(richTextBox1, &RichTextBox::Lines::set), resultsArray);

    and I get a System.Reflection.TargetParameterCountException: Parameter count mismatch error.

    Pardon me for my lack of knowledge as I'm a beginner in C++ and there's very little source on the net on this topic.

    Thank you very much!

  4. #4
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,675

    Re: How to use Picturebox's Invoke method in C++

    Quote Originally Posted by nicolee7 View Post
    I think I can't use the ReportProgress() function since I update a lot of GUI controls on the function associated with RunWorkerAsync().
    You're not limited to passing a single instance of one of the already defined .NET framework classes when using that technique. You can define your own progress packet class at will and pass that. For instance, this is a progress packet class from one of my real-life programs:

    Code:
    // ProgressPacket.h
    
    #pragma once
    
    namespace fileage
    {
    
    public ref class ProgressPacket
    {
    public:
      ProgressPacket() : m_nFileCount(0), m_nDirCount(0)
      {}
    
      ProgressPacket(int nFc_, int nDc_) : m_nFileCount(nFc_), m_nDirCount(nDc_)
      {}
    
      ProgressPacket(ProgressPacket ^orig)
      {
        *this = orig;
      }
    
      void operator=(ProgressPacket ^orig)
      {
        m_nFileCount = orig->m_nFileCount;
        m_nDirCount = orig->m_nDirCount;
      }
    
      int m_nFileCount, m_nDirCount;
    };
    
    }
    Though it may look somewhat more complex at first sight, this essentially conveys nothing more that two ints.

    And this is how I pass it from inside the worker function:

    Code:
            bw->ReportProgress(0, gcnew ProgressPacket(m_nFileCount, m_nDirCount));
    I'm not making use of the percentage parameter here at all, so I'm passing 0 for that.

    Moreover, do you have an article that explains the syntax of what you showed me [...].
    Actually, what I proposed is mostly based on the MSDN documentation on Control::Invoke() and some experience. I'm not using that really frequently either, so I had to look it up in one of my own programs when writing my post. At the end of the individual method documentation there's a link to a "How to" article which may be more instructive, but chances are it's rather C#-centric like much of the MSDN material.

    [...] I can't seem to make it work now for RichTextBox. My code is:

    richTextBox1->Invoke(gcnew Action<array<String^>^>(richTextBox1, &RichTextBox::Lines::set), resultsArray);

    and I get a System.Reflection.TargetParameterCountException: Parameter count mismatch error.
    Whell, that's actually a quite tricky one over which I already stumbled myself, and it took me some time to figure that out... This "more than one parameter" overload of Invoke() in fact is a variadic function, which means you can call it with two or more parameters of type Object ^ (except the first one), which essentially can represent any .NET type. Internally, this variable-length parameter list is represented as an array<Object ^>, and instead of passing each parameter to the to-be-invoked method to Invoke() individually, you may also pass the entire parameter list as a single array passed as the second parameter of Invoke().

    Now, if you try to invoke a method that way that takes an array of any .NET type as its only parameter, Invoke() misinterprets this array as a parameter list rather than a single array parameter. Consequentially, in your case, it attempts to invoke a RichTextBox::Lines::set() that takes a bunch of string parameters instead of one taking a single string array, and as such a method neither exists nor matches the delegate you passed to Invoke(), it naturally fails. The remedy to prevent this misinterpretation is wrapping up your string array inside a single-element array of string arrays, giving Invoke() what it expects when seeing a single array as the second parameter. Like this:

    Code:
    richTextBox1->Invoke(gcnew Action<array<String^>^>(richTextBox1, &RichTextBox::Lines::set),
      gcnew array<array<String ^> ^>{resultsArray});
    Pardon me for my lack of knowledge as I'm a beginner in C++ and there's very little source on the net on this topic.
    No problem. That's what forums like this one are for. C++/CLI is used rather rarely, in particular by beginners, so there's relatively few material about it out there.

    Please use code tags when posting code. Omitting them didn't do much harm with the short snippets you posted so far, but the longer the snippets get, the more important the code tags become.
    Last edited by Eri523; April 16th, 2012 at 07:33 AM.
    I was thrown out of college for cheating on the metaphysics exam; I looked into the soul of the boy sitting next to me.

    This is a snakeskin jacket! And for me it's a symbol of my individuality, and my belief... in personal freedom.

  5. #5
    Join Date
    Apr 2012
    Posts
    5

    Re: How to use Picturebox's Invoke method in C++

    Hi,

    Thank you for your very detailed explanation. I can run my program now!

    Thank you very much!

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured