-
[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::DoubleBuffer, 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
-
1 Attachment(s)
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... :D) 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.
-
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
-
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.
-
1 Attachment(s)
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)
-
1 Attachment(s)
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
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... :rolleyes: If I get that working on my system it will certainly work on yours too.
-
Re: flickering problem Button with PNG image.
Thanks,
And this might sound weird, but i am glad that you have the same problem :D.
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
-
1 Attachment(s)
Re: flickering problem Button with PNG image.
Quote:
Originally Posted by
smallbit
1) I tried double buffering:
Form1(void)
{
InitializeComponent();
SetStyle(ControlStyles::UserPaint, true);
SetStyle(ControlStyles::AllPaintingInWmPaint, true);
SetStyle(ControlStyles::DoubleBuffer, 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
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
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
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. :thumb: So what do I still have to say? :o
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... :o). 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 %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... :sick:
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...
-
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
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
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
-
1 Attachment(s)
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 ... :(
Quote:
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% 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 :D
Have a nice evening.
-
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
smallbit
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
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
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.
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 ??
-
1 Attachment(s)
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
smallbit
[...] the flickering is maybe around 5% 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. :D
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. :cool:
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... :o
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.
-
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.
-
Re: [RESOLVED] flickering problem Button with PNG image.
Hi Guys,
I have tried to implement a mix of both of your solution in a custom control, but I am still getting the flicker however very tiny like from the Cthulu's solution, probably Eri's idea doesn't work correctly here or I have done something wrong.
Here is the code of the user control that i am dragging then to the form.
Code:
#pragma once
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
using namespace System::Data;
using namespace System::Drawing;
namespace flicker {
/// <summary>
/// Summary for PanREAL
/// </summary>
public ref class PanREAL : public System::Windows::Forms::UserControl
{
public:
PanREAL(void)
{
InitializeComponent();
SetStyle(ControlStyles::Opaque | ControlStyles::OptimizedDoubleBuffer | ControlStyles::UserPaint , true);
//
//TODO: Add the constructor code here
//
}
protected:
/// <summary>
/// Clean up any resources being used.
/// </summary>
~PanREAL()
{
if (components)
{
delete components;
}
}
public: System::Windows::Forms::Button^ button2;
private: System::Windows::Forms::Timer^ timer1;
public:
int loc;
private: System::ComponentModel::IContainer^ components;
protected:
protected:
private:
/// <summary>
/// Required designer variable.
/// </summary>
#pragma region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
void InitializeComponent(void)
{
this->components = (gcnew System::ComponentModel::Container());
System::ComponentModel::ComponentResourceManager^ resources = (gcnew System::ComponentModel::ComponentResourceManager(PanREAL::typeid));
this->button2 = (gcnew System::Windows::Forms::Button());
this->timer1 = (gcnew System::Windows::Forms::Timer(this->components));
this->SuspendLayout();
//
// button2
//
this->button2->BackColor = System::Drawing::Color::Transparent;
this->button2->BackgroundImage = (cli::safe_cast<System::Drawing::Image^ >(resources->GetObject(L"button2.BackgroundImage")));
this->button2->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Center;
this->button2->FlatAppearance->BorderSize = 0;
this->button2->FlatStyle = System::Windows::Forms::FlatStyle::Flat;
this->button2->Location = System::Drawing::Point(3, 3);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(63, 60);
this->button2->TabIndex = 1;
this->button2->Text = L"button1";
this->button2->UseVisualStyleBackColor = false;
//
// timer1
//
this->timer1->Tick += gcnew System::EventHandler(this, &PanREAL::timer1_Tick);
//
// PanREAL
//
this->AutoScaleDimensions = System::Drawing::SizeF(6, 13);
this->AutoScaleMode = System::Windows::Forms::AutoScaleMode::Font;
this->BackColor = System::Drawing::SystemColors::ActiveCaption;
this->BackgroundImage = (cli::safe_cast<System::Drawing::Image^ >(resources->GetObject(L"$this.BackgroundImage")));
this->BackgroundImageLayout = System::Windows::Forms::ImageLayout::Stretch;
this->Controls->Add(this->button2);
this->Name = L"PanREAL";
this->Size = System::Drawing::Size(436, 412);
this->Load += gcnew System::EventHandler(this, &PanREAL::PanREAL_Load);
this->Paint += gcnew System::Windows::Forms::PaintEventHandler(this, &PanREAL::PanREAL_Paint);
this->ResumeLayout(false);
}
#pragma endregion
private: System::Void PanREAL_Paint(System::Object^ sender, System::Windows::Forms::PaintEventArgs^ e) {
System::Drawing::Rectangle temp(0,0,ClientSize.Width,ClientSize.Height );
temp.Width+=3;
temp.Height+=3;
// currentImage3 = splitContainerBajoVisual->Panel2->BackgroundImage;
e->Graphics->DrawImage(this->BackgroundImage,temp);
e->Graphics->DrawImage(this->button2->BackgroundImage, button2->Bounds);
}
private: System::Void timer1_Tick(System::Object^ sender, System::EventArgs^ e) {
loc+=5;
if(loc>600)
loc=0;
Drawing::Region ^rgToInvalidate = gcnew Drawing::Region(button2->Bounds);
button2->Location = System::Drawing::Point(loc,loc);
rgToInvalidate->Union(button2->Bounds); // Add new button area
// Invalidate the union of the old and new button areas
Invalidate(rgToInvalidate);
}
private: System::Void PanREAL_Load(System::Object^ sender, System::EventArgs^ e) {
loc=0;
timer1->Start();
}
};
}
Anyway The Eris solution applied directly on the form is 100% flicker free Good job
-
Re: [RESOLVED] flickering problem Button with PNG image.
Note that the trick I suggested only works if the button is invisible and the code of your user control pretty much looks like it's not. Keep in mind that in this case you need to handle the click yourself because an invisible button is not clickable. The user control class doesn't contain a click handler for the button but the button object is public, so there may be something outside that class.
BTW, for that trick to actually work, a button (or any other control for that matter) isn't even needed: If you store the button bitmap separately like I did in my version of the flicker sample project, a plain Rectangle will suffice. My code handles every aspect of mimicing a button's behaviour on its own.
Quote:
Originally Posted by
smallbit
Anyway The Eris solution applied directly on the form is 100% flicker free Good job
Thanks. :blush:
-
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
Eri523
Note that the trick I suggested only works if the button is invisible and the code of your user control pretty much looks like it's not. Keep in mind that in this case you need to handle the click yourself because an invisible button is not clickable. The user control class doesn't contain a click handler for the button but the button object is public, so there may be something outside that class.
Well I could bet money that it works also on button that isn't invisible (I mean has a half PNG file with some transparent parts, assigned as a background from the beginning through the preferences window), when button parent is form itself.
However I tried to reproduce it in the custom control code (source 2 posts above) and it's not working any more as i wrote above.
Anyway I got it implemented on my project already with all the button functionality and it works just fine (except for the 5% flicker :D )
Thanks again for your time!
-
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
smallbit
Well I could bet money that it works also on button that isn't invisible (I mean has a half PNG file with some transparent parts, assigned as a background from the beginning through the preferences window), when button parent is form itself.
You would win that bet but this is not the kind of invisibility I mean. What I mean is setting the button's Visible property to false, and only this ensures no flicker. In that state then buton isn't clickable anymore.
-
Re: [RESOLVED] flickering problem Button with PNG image.
smallbit, you must be doing something wrong here...
This is what I had in mind:
Code:
+----------------------------+
| Form1 (normal painting) |
+----------------------------+
| |
| +-------------+ |
| | |........... SpititLevel Control
| | [] | | (not moving, custom painting: background > bubbles > frame)
| | . [] | |
| +--.--------.-+ |
| . . |
| ..................... Bubbles (can be moved/animated)
| |
+----------------------------+
// Intended usage (for example, from within a containing form):
// (Note: I'm not sure how your multiple bubbles are used; I'll just call them X, and Y.)
aSpititLvl->SetXBubble(0.4); // (for example: -1 is left, 0 is level, 1 is right)
aSpiritLvl->SetYBubble(-0.12); // (same logic...)
// (u can also use properties)
So, based on what you've said before: why would the bubbles need button-like functionality anyway?
:confused:
If such functionality is not required, you can just draw the PNG image of the bubble on your user control. Keep it simple.
If it is required, Eri523's approach should work... Can you post a sample app that reproduces the problem again? I need to see what kind of flicker it is. Unless you manage to fix it after this, of course.
@Eri523:
Quote:
But let me suggest an alternative approach, [...] which is completely flicker-free.
Nice! Good job. :thumb:
-
1 Attachment(s)
Re: [RESOLVED] flickering problem Button with PNG image.
Well I have never written that this is still bubble case :D
This is different part already therefore I created a new thread here.
This is gonna be some sort of joystick that does two things,
- reflects the state of the game pad joystick.
- can be used as a virtual joystick using mouse.
However in the bubble case while i'm moving them there is no flicker at all although I haven't written any custom methods for that.
I adjust the sample code of the button in the panel creating flicker.
-
1 Attachment(s)
Re: [RESOLVED] flickering problem Button with PNG image.
Completing the changes analoguos to my suggestions in post #14 (that you already applied partially), just applying them to PanREAL instead of the form class eliminates flicker here as well.
I have attached a ZIP file containing the two modified project files (PanREAL.h and PanREAL.cpp) to this post.
This time I decided to implement the two new member functions in the .cpp file instead of the .h file to avoid the common circular inclusion problem in case you want to make the actual button click handler a member of the form class. Also, I implemented the panel's click handler as a base class method override instead of an event handler (mainly to avoid having to manually deal with delegates):
Code:
// Mouse click handler of the panel - this time implemented as base class member override
void PanREAL::OnMouseClick(MouseEventArgs ^e)
{
// If the click hits the invisible button explicitly invoke its Click handler
if (e->Button == Windows::Forms::MouseButtons::Left && button2->Bounds.Contains(e->Location))
TheButtonHasBeenClicked(this, e);
// Alternatively static_cast<Form1 ^>(Parent)->TheButtonHasBeenClicked(this, e);
// to call an equivalent (public) handler in the form class
}
Calling the actual button click handler could also be implemented using delegates here (like the .NET framework handles this) but that would be a bit more complicated and would only gain something in case you want to reuse the panel class, because then it wouldn't need to know anything about its parent class.
Unfortunately, my IDE refused to open both the form and the panel of the converted project in design view this time. It complained about an exception of type System::Exception (huh, the most informative exception type of them all... :rolleyes:) having been thrown and the call stack showed lots of stuff from the Microsoft::VisualC namespace I never heard of... :o
The only change I needed to apply to the design was to set button2->Visible to false though, and I manually edited that into PanREAL::InitializeComponent(). For this reason the caveats I mentioned in post #14 about replacing/modifying .h files used by the Forms Designer apply even more here.
All new stuff is marked with comments beginning with *****.
-
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
smallbit
Well I have never written that this is still bubble case :D
:D(:rolleyes:)->:mad:
(translation: I made a big grin (but a sarcastic one, cause I'm actually angry.))
Why didn't you say so in the first place?! How can one provide you with meaningful help if you haven't clearly stated both what is the problem and what the requirements are?
Well, at least not all of the discussion was off-track.
:lol:
-
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
TheGreatCthulhu
:D(:rolleyes:)->:mad:
(translation: I made a big grin (but a sarcastic one, cause I'm actually angry.))
Why didn't you say so in the first place?! How can one provide you with meaningful help if you haven't clearly stated both what is the problem and what the requirements are?
Well, at least not all of the discussion was off-track.
:lol:
Well forgive me, but
Quote:
Originally Posted by
smallbit
Hi Again,
So next riddle for you guys,
The only thing that two examples had in common is a PNG file used. I'am sorry I thought it was clear. Anyway I described the problem precisely and upload an example recreating it, therefore i don't really understand why did you wrote that :
Quote:
Originally Posted by
TheGreatCthulhu
... if you haven't clearly stated both what is the problem and what the requirements are?
//////////////////////////////////////
Quote:
Originally Posted by
Eri523
The only change I needed to apply to the design was to set button2->Visible to false though, and I manually edited that into PanREAL::InitializeComponent(). For this reason the caveats I mentioned in post #14 about replacing/modifying .h files used by the Forms Designer apply even more here.
Big thanks, Now the solution is complete !!!
Thanks again guys !!!
-
Re: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
smallbit
Well forgive me, but
The only thing that two examples had in common is a PNG file used. I'am sorry I thought it was clear.
Don't sweat it: if I meant it seriously, I wouldn't have used smilies to express it. :)
I somehow connected this thread to the previous one cause IIRC you mentioned that you had some flicker problems with the bubble. And a sample app did contain a bubble-like sphere; furthermore, since it was just a sample app meant to reconstruct the problem, I thought that it just had some random background.
And, yes, you did say it's another puzzle, but that doesn't automatically mean that it's not the part of the same overall problem.
Anyway, people asking questions on the forums often presume that people reading will have their mind set in a similar state, so that it is not necessary to explicitly state some things; however, this is generally not the case - people will interpret someone's words differently for various reasons. Because of that, it's best to be as explicit as possible - and not just on forums, but when discussing/documenting software in general.
-
Re: [RESOLVED] flickering problem Button with PNG image.
Guys I could use some tips to tune my sample app to get closer to the problem. but that's conditional. because 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: [RESOLVED] flickering problem Button with PNG image.
Quote:
Originally Posted by
KieBenJ54
Guys I could use some tips to tune my sample app to get closer to the problem. but that's conditional. because I have noticed that is not a problem of PNG itself, because it only happens when there is another picture below as a background.
So please give us more details to get started with. What you already posted is practically nothing.
Also, chances are your concrete problem isn't really so closely related to what has been discussed in this more than one year old thread. Unless it's really quite similar, please start a new thread.