If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register or Login
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

[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).

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:

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.

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.

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.

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.

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.

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.

Originally Posted by smallbit

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.

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.

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?).

(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.

Originally Posted by Eri523

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.

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:

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:

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.

Re: flickering problem Button with PNG image.

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.

Originally Posted by TheGreatCthulhu

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)

Originally Posted by TheGreatCthulhu

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 ?

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.

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

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.

Originally Posted by smallbit

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.

Originally Posted by smallbit

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.

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

[...] 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:

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:

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.