Why the superclass'es OnPaint() method is called on pressing button? - c++

I'm trying to implement the OnPaint() method in the subclass of the CButton MFC class.
class CImageButton : public CButton
public:
using CButton::CButton;
protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
};
BEGIN_MESSAGE_MAP(CImageButton, CButton)
ON_WM_PAINT()
END_MESSAGE_MAP()
void CImageButton::OnPaint()
{ /* Draws an image; Doesn't call the CButton::OnPaint(). */ }
Then, I have a dialog. In the resource editor, I placed the button on its form. In the dialog declaration, I wrote
CImageButton m_btn;
and
DDX_Control(pdc, IDC_BUTTON, m_btn);
in the DoDataExchange(). So, I think, I done all in order to my painting routine be working. But I got the strange thing: when my dialog is opening the image is painted OK (without the button's border, as I implemented in my method). But, if I'm trying to click on it, the image disappears the button's border is drawn as well a text which I specified in the VS resource editor. I.e., it looks like the superclass'es OnPaint() method is called by some way. I even was placing a debugging output on the entry of my method -- it is really not called. Then, if I switch the focus to some other control, my button is being redrawn with image.
Please, don't suggest me to use other ways to draw the image on the button. I need to get an answer on the question asked.
Thank you!

Related

Change the background color of a subclassed CStatic control

I am writing my own CStatic subclass right now, and I am a bit stuck on how to change its background color.
From previous experience I am used to reacting to the "CTLCOLORSTATIC" message with the color I want.
However, this is my subclass at the moment:
class LocationPane : public CWindowImpl<LocationPane, CStatic>
{
DECLARE_WND_CLASS(L"LocationPane");
public:
BEGIN_MSG_MAP_EX(LocationPane)
MSG_WM_PAINT(OnPaint)
MSG_WM_CTLCOLORSTATIC(OnCtlColorStatic);
END_MSG_MAP()
LocationPane();
~LocationPane();
private:
HBRUSH OnCtlColorStatic(CDCHandle cd, CWindow wnd);
//Paint routine
void OnPaint(CDCHandle dc);
};
I tried to listen for said message, but I am not receiving it at all. I do receive the paint message however, so I can't blame my custom control for not working at all.
Is it a legit solution to try to handle the background color in the paint routine? I don't really like solving it this way, but I am not receiving the other message which I am used to work with.
If additional code is needed, feel free to ask, I will gladly provide you with additional resources.
Thanks in advance.
I think you want to be catching WM_CTLCOLORSTATIC in the parent window that hosts your control. That's typically used for when you want to have a text control have a different background color.
But if you are going to be overriding WM_PAINT, you might as well let your OnPaint draw the background color.

How to define onDraw() in MFC

I understand that the onDraw() function is virtual void which is called automatically via OnPaint(), which is itself triggered by the WM_PAINT message.
My declaration goes something like this:
myDialog.cpp
void myDialog::OnDraw(CDC* dc)
{
CCustomMemDC pDC(dc);
CExampleDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
}
myDialog.h
afx_msg void OnDraw(CDC* dc);
and in my OnPaint()
CDialog::OnPaint();
However I could not get OnDraw to be triggered at all... Could anyone enlighten if this method is correct?
Thanks!
A dialog has no OnDraw. This is a virtual function in views to allow printing and drawing to a screen.
In a dialog just use OnPaint. There isno redirection to a virtual OnDraw function in a dialog.
It is not correct. As others have pointed out, OnDraw() is a virtual method of CView and not CDialog. Therefore, your OnDraw() method will never be called.
I don't know why your dialog would have a flicker problem that you would need to mitigate it. If you have a custom control on the dialog that is causing flicker, then you probably need to fix the drawing code in it and possibly add WS_CLIPCHILDREN as a Window Style to your dialog. That will make sure that the background of the custom control is not erased when the dialog executes its WM_ERASEBKGND message.
It makes no sense to override the WM_PAINT of the dialog unless you are really planning to do custom drawing on it. Unless you have a very good reason, don't do it.
If you choose to ignore the advice then add an ON_WM_PAINT() to your message handler to the dialog, and then draw the dialog yourself:
void myDialog::OnPaint()
{
CPaintDC dc(this);
CCustomMemDC pDC(&dc);
// do your specialized code knowing you are responsible for drawing the whole dialog
}
If you really want to use your OnDraw() method, then you could also write OnPaint() like this:
void myDialog::OnPaint()
{
CPaintDC dc(this);
OnDraw(&dc);
}
But, the first thing I would do in your situation is try adding the style WS_CLIPCHILDREN to your dialog style.

How to make popup image? wxWidgets

I'm trying to make a popup image preview window like it's done in Autodesk Revit Architecture:
The behaviour of popup image is:
When the mouse stops for 500 milliseconds over the truncated image, a full-sized popup image appears near the mouse cursor.
The Popup image is not a modal dialog, therefore controls of the main window(wxDialog) are still enabled.
The Popup window disappears on mouse movement.
I tried to do it, but i failed.
First I put wxStaticBitmap on wxDialog and use ShowModal() to show this full-sized image. It works great but as it's Modal, main window becomes disabled.
I tried to make this dialog not modal, but when I try to do it, main window raises(main window is modal) and image disappears.
upd.
Now my code:
class PictureFrame: public wxPopupTransientWindow
{
wxStaticBitmap *m_picture;
public:
PictureFrame( wxWindow *parent );
~PictureFrame();
};
Panel code structure is like this:
class MaterialsPane: public wxPanel
{
PictureFrame* m_popup;
wxTimer* m_timer;
public:
MaterialsPane( wxWindow* parent);
~MaterialsPane();
void OnTimer( wxTimerEvent& event);
void OnMouseMove( wxMouseEvent& event );
....
DECLARE_EVENT_TABLE()
};
Panel is placed in main modal dialog:
class MaterialsFrame: public wxDialog {
MaterialsPane* m_materialsPane;
public:
MaterialsFrame( wxWindow* parent, wxWindowID id = wxID_ANY);
~MaterialsFrame();
};
it helped but not completely. As image appears not under mouse cursor but near it (like in the picture of my question), popup window can't catch mouse movements. I tried to catch mouse movements in main dialog, but it failed, because focus is taken by popup window.
My goal is to close popup after any mouse movement.
You should post your code that 'fails'. It is hard to give specific advice when we have no information of what you are doing.
Have you looked at wxPopupWindow? http://docs.wxwidgets.org/trunk/classwx_popup_window.html
Personally, I find it easier to roll my own. Here's how the one I am working on right now looks
cNewDataPopup::cNewDataPopup( cPatDataset& data )
: wxDialog(NULL,-1,L"New data",wxPoint(200,200),wxSize(570,242),
wxDEFAULT_DIALOG_STYLE|wxSTAY_ON_TOP )
, myData( data )
{
...
Show();
}
To make this popup appear, simply call the constructor.
You would want to pass in your image to be displayed, store it in an attribute, handle the paint event by drawing your image on the client area.

OnRButtonDown on a modal dialog

I have a modal dialog that I would like to implement a right mouse click event on. I have added ON_WM_RBUTTONDOWN() to the class's message map.
BEGIN_MESSAGE_MAP(MyDialog, CDialog)
//{{AFX_MSG_MAP(MyDialog)
ON_WM_RBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
and have overridden the class's afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
However, my OnRButtonDown function does not execute when I click the mouse button on the Dialog window. My dialog is called using DoModal(), could it be that modal dialogs don't allow for these mouse events? Is there something else that I'm missing?
No, this should work also in modal dialogs. Two possible scenarios:
you have an invisible control which
captures the click
you have overridden the window procedure and do something unwanted with the message.

OwnerDrawn control in MFC

I am creating a MFC application in which there is a skin library which handles the UI effect of rendering the controls (it gets called in oninitdialog). But, meanwhile, I have also the requirement of displaying an icon on the buttons. For this, I am marking the buttons as ownerdrawn=true, and able to display icon, but in this case, skin effect is not taking place on those buttons whose ownerdrawing is done by me. So, my question is, how do I ensure that a control gets ownedrawn by me, and also by any other library.
Call the default handler for OnPaint to make sure the skinning library has a chance to draw the button, then draw your own content over the top.
void OnPaint()
{
Default();
CClientDC dc(this);
// your painting code goes here
}
You don't need owner-draw to display icons in buttons !