0

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.

halfer
  • 19,824
  • 17
  • 99
  • 186
Serge Roussak
  • 1,731
  • 1
  • 14
  • 28
  • 2
    I know you don't want to hear it, but: https://forums.codeguru.com/showthread.php?390193-A-Derived-CButton-Problem-with-OnPaint – Adrian Mole Oct 07 '21 at 22:30
  • 1
    Or, from [here](http://www.44342.com/vc-f957-t8167-p1.htm): *There is nothing to prevent a control from repainting itself outside of WM_PAINT.* – Adrian Mole Oct 07 '21 at 22:34
  • @AdrianMole, so, are you saying, that I'm not the first one who steps on this rake? – Serge Roussak Oct 07 '21 at 22:36
  • So it would appear - I went looking for some *official* MFC documentation but found none. – Adrian Mole Oct 07 '21 at 22:36
  • @AdrianMole, OK, thank you a lot! )) – Serge Roussak Oct 07 '21 at 22:40
  • The "answer" is (probably) something like: "Dialog controls can be redrawn in a number of message handlers, such as `OnClick()`, and they don't necessarily call either `OnPaint` or `OnEraseBkgnd()` to do so." TLDR: Use an Owner-drawn button. – Adrian Mole Oct 07 '21 at 22:41
  • @AdrianMole, I think, furthermore: even if it call the `OnPaint` from within some internal place of its code, the `CButton::OnPaint()` may be called. As we can see on my case. It's because, the `OnPaint` is not a virtual method (which, IMHO, would be really-really logically for all family of the `On*` methods). – Serge Roussak Oct 07 '21 at 22:50
  • 3
    You are not supposed to override `CButton::OnPaint()` for a standard button. This function doesn't do anything except call `CWnd::Default()` to pass `WM_PAINT` to Windows, Windows will do the drawing. Use OwnerDraw button, or use CustomDraw button if you want Windows to handle border drawing etc. `OnPaint` is generally meant for painting your own windows. – Barmak Shemirani Oct 07 '21 at 23:34
  • 2
    It's not that simple, when you hover or click a button, windows has to repaint it due to it's state change (normal, hot. pressed etc). If you want custom paint you have to provide for all these cases, not just respond to the `WM_PAINT` message. In your case, if you just want your button to display an image, there is a simpler way, check the `BS_ICON` and `BS_IMAGE` button styles (and the `BM_SETIMAGE` message). Otherwise check the `BCM_SETIMAGELIST` message. Windows will handle all painting, you don't need to override `OnPaint()`. – Constantine Georgiou Oct 08 '21 at 00:26
  • Why do reinvent an image CButton. The CMFCButton has this feature inside. – Tom Tom Oct 08 '21 at 13:51

0 Answers0