[RESOLVED] flickering problem Button with PNG image.
CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 27

Thread: [RESOLVED] flickering problem Button with PNG image.

  1. #1
    Join Date
    Mar 2011
    Posts
    27

    [RESOLVED] flickering problem Button with PNG image.

    Hi Again,
    So next riddle for you guys,
    I have a button which location is changing dynamically, the button itself has a PNG image set from which some parts are transparent, and background colour is set to transparent.

    Now moving the button I get the flickering issue(for some milliseconds you can see the entire button in white).

    1) I tried double buffering:
    Form1(void)
    {
    InitializeComponent();
    SetStyle(ControlStyles::UserPaint, true);
    SetStyle(ControlStyles::AllPaintingInWmPaint, true);
    SetStyle(ControlStyles:oubleBuffer, true);
    UpdateStyles();

    But it gives no effect.

    2)Also I used the Paint method of the button to redraw the button image but neither that one worked.

    private: System::Void Button_Palanca_IZQ_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
    g->DrawImage(image,loc);
    }

    3) I tried the advice from other topic to use bufferedGraphics
    http://msdn.microsoft.com/en-us/libr...dgraphics.aspx
    But it didn't work.

    I am new to this stuff, so maybe somebody will give me a clue where to look for ?
    Thanks in Advance

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

    Re: flickering problem Button with PNG image.

    Hmmm... I couldn't reproduce your problem here. But maybe that's due to incomplete information about what you're actually trying to do.

    I have set up a toy app with a button that contains a PNG bitmap which has a transparent area. The button's BackColor can be toggled between what has been set up in the Forms Designer (didn't change the default of SystemColors::Control) and Color::Transparent. When clicked, the button traves along a circle, driven by a timer that fires at an interval of 40 ms, until it returns to its original position. The circular shape the button travels along can be visibly painted onto the form. This serves two purposes: to demonstrate that the button actually is transparent (i.e. providing something to be actually seen behind the button) and to paint something directly to the form, which is critical as TheGreatCthulhu said.

    I have attached a screen shot of that toy app (sorry, it takes up a lot of screen real estate while not actually showing much content - in return it compresses pretty good... ) and these are the event handlers involved:

    Code:
    // Form1.cpp
    
    #include "stdafx.h"
    
    #include "Form1.h"
    
    using namespace MovingButton;
    
    System::Void Form1::button1_Click(System::Object^  sender, System::EventArgs^  e)
    {
      m_dAngle = 0;
      timer1->Start();
    }
    
    System::Void Form1::timer1_Tick(System::Object^  sender, System::EventArgs^  e)
    {
      if ((m_dAngle += m_dAngleStep) <= 2 * Math::PI)
        button1->Location = m_ptRotationCenter
          + Drawing::Size(m_nRadius * Math::Sin(m_dAngle), - m_nRadius * Math::Cos(m_dAngle))
          + m_szOriginVector;
      else {
        timer1->Stop();
        button1->Location = m_ptOriginalButtonLocation;
      }
    }
    
    System::Void Form1::Form1_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e)
    {
      if (chkShowTrack->Checked)
        e->Graphics->DrawEllipse(Pens::Black, Rectangle(m_ptRotationCenter - Drawing::Size(m_nRadius, m_nRadius),
          Drawing::Size(2 * m_nRadius, 2 * m_nRadius)));
    }
    
    System::Void Form1::chkShowTrack_CheckedChanged(System::Object^  sender, System::EventArgs^  e)
    {
      Invalidate();
    }
    
    System::Void Form1::chkTransparent_CheckedChanged(System::Object^  sender, System::EventArgs^  e)
    {
      button1->BackColor = chkTransparent->Checked ? Color::Transparent : m_clrOriginalButtonColor;
    }
    I didn't see anything disturbing with any of the possible combinations of settings, in particular not the button flashing up in white for a short but noticable time as you describe. I just would've expected the motion to look smoother at 25 fps.

    Note that I didn't change any of the form's defaults with respect to painting (except for setting up the Paint event handler you can see in the listing) and double buffering.

    Why do you have a Paint handler for the button at all? The Forms::Button class knows various ways to hold bitmaps in its original incarnation without the need to override anything.
    Attached Images Attached Images  
    Last edited by Eri523; March 22nd, 2011 at 11:37 PM. Reason: Minor terminology fix
    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
    Mar 2011
    Posts
    27

    Re: flickering problem Button with PNG image.

    Well,
    I don't need to override anything, I just tried to resolve the flickering.
    When I leave it to the class itself it flickers. I read somewhere here that this is the common solution fot that.

    Anyway I couldn't fix it yet, My app is quite complex already, it has many buttons and other controls, as well as Glpanel, webbrowser etc maybe this is a reason. Thus the button animation goes in 10FPS only and still flickers.

    I have noticed that it might depend on the cpu "condition", when I run it fresh after rebooting it goes smoothly with almost no flicker, than after an hour or two with more apps opened it flickers more and more.

    Cheers,
    Smallbit

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

    Re: flickering problem Button with PNG image.

    Can you set up a sample app that reproduces the problem? (Please do a Clean on the project before zipping and uploading it.) If not, I could use some tips to tune my own sample app to get closer to the problem.

    CPU load might be problematic when approaching 100%, especially if your app already generates much of that without the animation. Did you have a look at the CPU load generated by your animation? My demo app is somewhere around 5% on my 1.8 GHz P4.
    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
    Mar 2011
    Posts
    27

    Re: flickering problem Button with PNG image.

    Hi Eri,
    Attached you will find a small project that reproduces the problem, I have noticed that is not a problem of PNG itself, because it only happens when there is another picture below as a background.

    Please check if you get it too.

    Thanks.

    P.S. i am running on :
    Processor: Intel(R) Core(TM)2 Quad CPU Q9550 @ 2.83GHz (4 CPUs)
    Attached Files Attached Files

  6. #6
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,588

    Re: flickering problem Button with PNG image.

    After downloading, converting, building and running your sample project I could see myself what the problem is. The next thing I did then was adding a background bitmap to my test app as well, to see whether this would reproduce the problem, and it actually did.

    The fact that I used a somewhat more traditional button design gave me some additional information. (See attached screen shot.) Obviously the button is dragging along an "echo" of itself while moving. So the problem can be narrowed down to repaintig the region of the form the button has just left. This leads me to the conclusion that just double-buffering the painting of the form itself wouldn't solve the problem. (Actually, I discovered that double-bufferig of the form is already enabled by default.) What we need is rendering both the form and the controls it hosts to a BufferedGraphics and finally blit the entire thing onto the form's surface. That way repainting of the form and the moving button would get force-synchronized.

    I'm currently working on a solution to that, involving an OnPaint() overload in the form class, but that's not working yet. I'm struggling with the fact that the Control class has a DrawToBitmap() method but nothing like a DrawToGraphics(). I'll probably come up with more after I had some sleep but wanted to post a status report in the meantime.

    Quote Originally Posted by smallbit View Post
    P.S. i am running on :
    Processor: Intel(R) Core(TM)2 Quad CPU Q9550 @ 2.83GHz (4 CPUs)
    Well... That's probably a bit more powerful than what I have... If I get that working on my system it will certainly work on yours too.
    Attached Images Attached Images  
    Last edited by Eri523; March 21st, 2011 at 11:11 PM.
    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.

  7. #7
    Join Date
    Mar 2011
    Posts
    27

    Thumbs up Re: flickering problem Button with PNG image.

    Thanks,
    And this might sound weird, but i am glad that you have the same problem .

    Anyways, I could eventually use a picturebox (instead of button) and manage the mouse events there, but using picBox gave me same flickering.

    Keep on good work
    Cheers

  8. #8
    Join Date
    Jan 2010
    Posts
    1,099

    Re: flickering problem Button with PNG image.

    Quote Originally Posted by smallbit View Post
    1) I tried double buffering:
    Form1(void)
    {
    InitializeComponent();
    SetStyle(ControlStyles::UserPaint, true);
    SetStyle(ControlStyles::AllPaintingInWmPaint, true);
    SetStyle(ControlStyles:oubleBuffer, true);
    UpdateStyles();

    But it gives no effect.
    The SetStyle(...) finction effects only (well, better to say mostly) the control it belongs to, and the DoubleBuffer flag doesn't really help in situations like this.

    Quote Originally Posted by smallbit View Post
    2)Also I used the Paint method of the button to redraw the button image but neither that one worked.
    That's because the system has it's own way of handling the paint requests, and thus there's a lot of stuff going on that might interfere with your handler, which basically messes with the normal order of things.

    Quote Originally Posted by smallbit View Post
    3) I tried the advice from other topic to use bufferedGraphics
    http://msdn.microsoft.com/en-us/libr...dgraphics.aspx
    But it didn't work.
    BufferedGraphics and double buffering work when drawing on the same logical surface, especially if it involves multiple draw operations before the final image is created. So that would work if you were, for example, drawing multiple semitransparent PNG images on the same control.

    Refer to your original thread to find code samples on how to do that, as me and Eri523 have continued the discussion.

    I've managed to reduce flicker with in your app (on my PC it appears occasionally, and it is fairly less noticeable than before.)
    The flicker is caused by some internal aspects of how the controls draw themselves (or, how the framework draws them, or how whatever draws them...). Many (most?) of these aspects are not know to us, so we can't rely on the system. Although the default painting algorithm works fine in most cases, in this particular app we need to take over.

    What I did is this:
    Code:
    Form1(void)
    		{
    			//...
    
    			SetStyle(ControlStyles::Opaque | ControlStyles::OptimizedDoubleBuffer, true);
    
    		}
    
    //later...
    
    private: System::Void Form1_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
    
    				 e->Graphics->DrawImage(this->BackgroundImage,temp);
    			 }
    You can try to further reduce it by overriding OnPaint() instead:
    Code:
    protected:	 virtual System::Void OnPaint(PaintEventArgs^ e) override
    			 {
    				 e->Graphics->DrawImage(this->BackgroundImage,temp);
    
    				 Form::OnPaint(e);
    			 }
    But, since you're using a button, some flicker will inevitably remain. Note that, if using this method, the entire client area needs to be redrawn, and some other problems may arise. Also, since it's a button, you have to deal with special conditions, like what happens when the button is highlighted. Hover the mouse pointer over it - it suddenly isn't transparent anymore (at least on Win 7).

    If you ask me, you should scrap the button-based approach altogether, and do something like this:
    • Create a custom panel control by deriving from UserControl - you get all the functionality ready. [see notes below]
    • Call SetStyle to set the Opaque and AllPaintingInWmPaint to true (and UserPaint - to respect the recommendation by MS). [see more notes below]
    • Use BufferedGraphics to implement custom double buffering.
    • Create a simple public property or a function that would enable you to set the location of the bubble (or two, as there are two bubbles?).
    • Overide OnPaint or handle the Paint event.
    • Draw the background image (I'm assuming it's opaque - if not, call Clear() first).
    • Draw the bubble png alpha-masked image.
    • (optional) Draw the frame png alpha-masked image. (or use the same method as before - since the frame is static).
    • Call Render().
    • Drag your custom panel from the toolbox on your form, or create and add it code. (You should be able to drag it from the toolbox if you use the IDE: "Add New Item..." --> "User Control"


    It is not that hard - the user control comes as fully functional, you just need to add a few lines of code. You'll basically end up with a "spirit level control". As for SetStyle(), I don't think that AllPaintingInWmPaint and UserPaint are needed when Opaque is used, but I'm not sure.

    Quote Originally Posted by Eri523 View Post
    I'm struggling with the fact that the Control class has a DrawToBitmap() method but nothing like a DrawToGraphics().
    Both Graphics::Draw() and DrawToBitmap() can draw to a bitmap - if you create graphics from one (using the static methid Graphics::FromImage()) - so you can just call DrawToBitmap() and then use graphics to draw whatever you need on top.
    Attached Files Attached Files
    Last edited by TheGreatCthulhu; March 22nd, 2011 at 08:18 PM.

  9. #9
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,588

    Red face Re: flickering problem Button with PNG image.

    TheGreatCthulhu's modified demo project behaves close to perfect, even on my weak machine. So what do I still have to say?

    During my experiments I noticed that I can simplify the life of the .NET framework and/or Windows by giving them a form background bitmap with the same size and resolution as the form itself, thereby eliminating the need for scaling the bitmap while painting. So I tried to add the following code to the form's constructor in the modified demo project:

    Code:
          // Load background image from file and adjust resolution
    
          Bitmap ^bmpTemp = gcnew Bitmap("..\\palancaBase_upsampled.bmp");
          Diagnostics::Trace::Assert(bmpTemp != nullptr, "Construction of background bitmap from file failed");
          Graphics ^grTemp = CreateGraphics();
          bmpTemp->SetResolution(grTemp->DpiX, grTemp->DpiY);
          BackgroundImage = bmpTemp;
    I decided to load the bitmap from a disk file to bypass constructing and using the ResourceManager object (lazy me... ). The .bmp file I load there is a version of your original palanca_base.bmp, upsampled to the pixel dimensions of the form's client area using an external tool. (The aspect ratio of the form and the original image don't match exactly, so the upsampled .bmp is slightly distorted.)

    The bad news: Unlike my own sample app this didn't yield a noticable gain with TheGreatCthulhu's modified demo project. Maybe that's because the custom drawing code in my own project did a more specialized handling of the background image. Additionally, this would be significantly complicated if the form was resizable (I disabled resizing for the test). This would require to generate matching bitmaps for each resizing operation. I didn't yet research whether the .NET framework provides convenient methods to generate them.

    The problem I mentioned above, that the Control class doesn't have a method to render itself to a Graphics object turned out to be not that severe at all: I could have constructed a bitmap with the control's dimensions, render the control to this using Control::DrawToBitmap() and finally blit the result to the buffered graphics context.

    The approach I tried myself was based on buffering all painting before blitting it to the form. I didn't get away with that, though. The main problem was to prevent the controls on the form from painting themselves.

    I tried several variants of this and finally resorted to go way down to real low-level stuff. I set up an application-wide message filter:

    Code:
      private ref class AppMessageFilter : public Windows::Forms::IMessageFilter
      {
      public:
        AppMessageFilter(Form1 ^form) : m_form(form)
        {}
    
        [SecurityPermission(SecurityAction::LinkDemand, Flags = SecurityPermissionFlag::UnmanagedCode)]
        virtual bool PreFilterMessage(Message &#37;m);
    
      private:
        Form1 ^m_form;
      };
    Code:
    bool AppMessageFilter::PreFilterMessage(Message %m)
    {
      if (m.Msg == WM_PAINT) {
    #ifdef _DEBUG
        Debug::Write("WM_PAINT received for ");
    #endif
        if (m_form->m_dictHWndToControl->ContainsKey(m.HWnd)) {
    #ifdef _DEBUG
          Debug::WriteLine(m_form->m_dictHWndToControl[m.HWnd]->Name);
    #endif
          return true;
        }
    #ifdef _DEBUG
        else {
          Debug::WriteLine("HWND = 0x{0:X8}", m.HWnd.ToInt32());
        }
    #endif
      }
      return false;
    }
    And finally in the form class' constructor:

    Code:
          // Set up mapping from HWNDs to controls
    
          m_dictHWndToControl = gcnew Dictionary<IntPtr, Control ^>(Controls->Count);
          for each (Control ^ctl in Controls)
            m_dictHWndToControl->Add(ctl->Handle, ctl);
    
          // Apply application-wide message filter
    
          m_msgfilter = gcnew AppMessageFilter(this);
          Application::AddMessageFilter(m_msgfilter);
    This was meant to block all WM_PAINT messages to the controls to avoid painting them twice. But Windows (or the .NET framework) doesn't like it whan I refuse to process the WM_PAINT requests and keeps sending them over and over again, so all that hassle was of no use...

    And, thinking about it a bit more afterwards, even if I had got that to work it wouldn't have been of much use: I may be get through to painting the "raw" controls but once they need to paint themselves independent from the form (e.g. when a button wants to draw its clicked state) I would get busted...

    So, after all this text about non-working stuff, I can only conclude: Please keep us informed about your progress...
    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.

  10. #10
    Join Date
    Mar 2011
    Posts
    27

    Re: flickering problem Button with PNG image.

    Eri523, TheGreatCthulhu

    Thank a lot for your help,
    And thanks for explanation what is really going on around this drawing processes. As i wrote i am new to this, now i have clearer view for all of this.

    Quote Originally Posted by TheGreatCthulhu View Post


    But, since you're using a button, some flicker will inevitably remain. Note that, if using this method, the entire client area needs to be redrawn,
    In my original project I have 3 buttons of this kind, but those are located in a separated panel with dimensions of around 300x150 pix. In this case the the entire client still needs to be redrawn ? or just a panel will do ? (its just a curiosity)

    Quote Originally Posted by TheGreatCthulhu View Post
    and some other problems may arise. Also, since it's a button, you have to deal with special conditions, like what happens when the button is highlighted. Hover the mouse pointer over it - it suddenly isn't transparent anymore (at least on Win 7).
    I have figured this out before.
    I set the MouseDownBackColor and MouseOverBackColor (in flat appearance) to transparent too.

    And one final question, shoud I expect diferent (better) behaviour if I would use picture box instead of button ?


    Anyway I'am tagging the topic as resolved,

    Thanks again guys for your effort.
    Peace

  11. #11
    Join Date
    Mar 2011
    Posts
    27

    Re: [RESOLVED] flickering problem Button with PNG image.

    I did a school mistake,
    It works nice but I have forgot to mention that my buttons are in the panel ...
    Therefore is not so direct to set it's style.

    I know that I have to do some of these steps but I am stucked on the first ...
    Create a custom panel control by deriving from UserControl - you get all the functionality ready. [see notes below]
    Call SetStyle to set the Opaque and AllPaintingInWmPaint to true (and UserPaint - to respect the recommendation by MS). [see more notes below]
    Use BufferedGraphics to implement custom double buffering.
    Create a simple public property or a function that would enable you to set the location of the bubble (or two, as there are two bubbles?).
    Overide OnPaint or handle the Paint event.
    Draw the background image (I'm assuming it's opaque - if not, call Clear() first).
    Draw the bubble png alpha-masked image.
    (optional) Draw the frame png alpha-masked image. (or use the same method as before - since the frame is static).
    Call Render().
    Drag your custom panel from the toolbox on your form, or create and add it code. (You should be able to drag it from the toolbox if you use the IDE: "Add New Item..." --> "User Control"
    When I create custom panel with all the styles as external project, once adding it to the toolbox it becomes completely black, settings change anything (it looks like on pic i adjust).

    The same happens when I create it as a part of the project.
    As you can see In the picture, I can see its background only on the transparent parts of the png texture of the button.

    I guess I am missing something.

    ////////// EDIT

    I have managed to do so, the problem was obviously in one of your points (Overide OnPaint or handle the Paint event), I have run two aplications next to each other and the flickering is maybe around 5&#37; of the state before, for me is enough. Now only implement it into My project,

    Thank you guys again,

    I will have another riddle for you very soon so stay tuned
    Have a nice evening.
    Attached Images Attached Images  
    Last edited by smallbit; March 23rd, 2011 at 10:22 AM.

  12. #12
    Join Date
    Jan 2010
    Posts
    1,099

    Re: [RESOLVED] flickering problem Button with PNG image.

    Quote Originally Posted by smallbit View Post
    In this case the the entire client still needs to be redrawn ? or just a panel will do ? (its just a curiosity)
    Just the panel - the entire client area of the panel.

    Quote Originally Posted by smallbit View Post
    And one final question, shoud I expect diferent (better) behaviour if I would use picture box instead of button ?
    Except for the elimination of the need to handle button-specific behavior (flat style, pressed state, highlighting...) - no. But, note that you can basically use any control which accepts a background image - a Panel is a good choice, for example.

    Quote Originally Posted by smallbit View Post
    I did a school mistake,
    It works nice but I have forgot to mention that my buttons are in the panel ...
    Therefore is not so direct to set it's style.

    I know that I have to do some of these steps but i don't know where to start ...
    Yeah, SetStyle() is a protected method. That's why I listed those steps.
    It might seem pretty complicated at first glance, but it is not all that much.

    Start by creating a class derived from UserControl. The IDE should provide support for this ("Add new item...").
    If by any chance i doesn't, just create a new class and append ": public UserControl" to it. (Similarly, your Form1 class derives from Form). Then set Location, Width and Height, and add your user control to the Controls collection of your form. (You can change background color too, so you can see it when you run the app.)

    At this point - you have a user control that basically replicates the behavior of a panel.

    Now, all those painting methods, events and such are in both cases inherited from the Control class, so there's really no difference: the procedure is exactly the same. Just as you've done with the form, handle the corresponding events of your user control (or override the corresponding methods.)

    Me or someone else will provide more info once you've tried it.

    EDIT: Just saw your image you attached afterwards (I was AFK for a while when writing the original reply): You shouldn't be doing any drawing on the main form with the new approach. The idea is to create a specialized control that would be the size of your background image (of the spirit level you're trying to implement), and than add the bubble on top of that (as a separate transparent control, or even better, by painting the png image). Once setup, drag your custom "sprit level control" on a normal form (unmodified with regard to painting), as you would do with a label, or a button, or a text box, or a picture box.
    Basically - migrate all the spirit level related logic into this specialized control.
    Last edited by TheGreatCthulhu; March 23rd, 2011 at 10:29 AM.

  13. #13
    Join Date
    Mar 2011
    Posts
    27

    Re: [RESOLVED] flickering problem Button with PNG image.

    All right I will do so,
    I thought it will work, but suddenly when dragging the custom control i get error because it has no background, I will try to do your way.

    Lets say I have my bubble in the user control as a button, how can I access its location from the form ??

  14. #14
    Join Date
    Jun 2010
    Location
    Germany
    Posts
    2,588

    Cool Re: [RESOLVED] flickering problem Button with PNG image.

    Quote Originally Posted by smallbit View Post
    [...] the flickering is maybe around 5&#37; of the state before, for me is enough.
    Well, if you feel comfortable with that...

    But let me suggest an alternative approach, based on TheGreatCthulhu's modified version of the flicker project from post #8, which is completely flicker-free.

    As we all have seen, rendering the button caused annoying effects, so my idea was to make the button invisinle to avoid rendering it at all. Instead, I draw the button bitmap myself in the Paint handler, thereby making full use of the double-buffering:

    Code:
      private: System::Void Form1_Paint(System::Object^  sender, System::Windows::Forms::PaintEventArgs^  e) {
    
                 // Some strange scaling issue...
                 Rectangle temp(Point(0,0), ClientSize);
                 temp.Width+=3;
                 temp.Height+=3;
    
                 e->Graphics->DrawImage(this->BackgroundImage,temp);
    
                 // Draw button bitmap
    
                 e->Graphics->DrawImage(m_bmpButton, button1->Bounds);
               }
    However, an invisible button doesn't cause any repainting (which actually was the intention behind that modification), so we need to do that ourselves in the timer tick handler that already is responsible for moving the button:

    Code:
      private: System::Void timer1_Tick(System::Object^  sender, System::EventArgs^  e) {
    
                 loc+=5;
                 if(loc>600) loc=0;
                 Drawing::Region ^rgToInvalidate = gcnew Drawing::Region(button1->Bounds);  // Store old button area
                 button1->Location = System::Drawing::Point(loc,loc);
                 rgToInvalidate->Union(button1->Bounds);  // Add new button area
    
                 // Invalidate the union of the old and new button areas
    
                 Invalidate(rgToInvalidate);
               }
    And that only causes repainting of what is really required.

    Another disadvantage of an invisible button is that it isn't clickable. So we need to handle that ourselves too, which isn't really that complicated either:

    Code:
      private: System::Void Form1_MouseClick(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {
                 // If the click hits the invisible button explicitly invoke its Click handler
                 if (e->Button == Windows::Forms::MouseButtons::Left && button1->Bounds.Contains(e->Location))
                   button1_Click(sender, e);
               }
    The above is what implements the flicker-free moving button, but there's some additional code in the form class' constructor:

    Code:
          // Load button bitmap (it's no longer an actual property of the button)
    
          m_bmpButton = gcnew Bitmap("..\\palancaPNG.png");
          Diagnostics::Trace::Assert(m_bmpButton != nullptr, "Construction of button bitmap from file failed");
    This became necessary when I tried to make the button completely transparet in an earlier stage of development of this modifcation. But now, as the button is invisible, you can as well re-add the PNG as the button's background image (or not remove it in the first place) and access it as button1->BackgroundImage instead of m_bmpButton. I was a bit in a hurry and, to be honest, just too lazy to revert that before posting...

    I hope I didn't miss any of the changes I applied. As I know that smallbit can't open VS 2010 projects, I have just attached a ZIP containing the modified Form1.h.

    Caution: Be careful if you want to simply replace the Form1.h in your project with my version. This may mess up the internal form design data that VS keeps in some secret place, so better make a backup of the entire project before attempting that.

    Alternatively, you can just copy over the modified functions (or parts of them) to your project. You can find the properties I set up for the button in Form1::InitializeComponent(). But do not copy these over to your project because the IDE gets very angry if you modify InitializeComponent() on your own. Better adjust the button properties in the Forms Designer.
    Attached Files Attached Files
    Last edited by Eri523; March 23rd, 2011 at 12:59 PM.
    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.

  15. #15
    Join Date
    Mar 2011
    Posts
    27

    Re: [RESOLVED] flickering problem Button with PNG image.

    Very nice Eri,
    I will try now to mix your way within the panel I am sorry but I have forgot to mention about that.
    Anyway Cthulu game me some hints already, on which I will try to apply your way.

    Thanks guys.

Page 1 of 2 12 LastLast

Posting Permissions

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


Windows Mobile Development Center


Click Here to Expand Forum to Full Width

This is a CodeGuru survey question.


Featured


HTML5 Development Center