简体   繁体   English

MFC:未调用OnNcCreate(); 需要为CButton子类设置BS_OWNERDRAW标志

[英]MFC: OnNcCreate() not called; need to set BS_OWNERDRAW flag for CButton subclass

I'm not an expert on MFC, but I've made a dozen or so custom controls over the last 15+ years. 我不是MFC的专家,但在过去的15年里,我已经制作了十几个自定义控件。 I've just made a CButton with custom graphics. 我刚刚制作了一个带有自定义图形的CButton

Here's the problem: Of course I need BS_OWNERDRAW to be set. 这是问题所在:当然我需要设置BS_OWNERDRAW I have an OnNcCreate() method I've cut and pasted for 15+ years that's always worked in my custom controls, but for some reason it's not now being called. 我有一个OnNcCreate()方法,我已经剪切和粘贴了15年以上,总是在我的自定义控件中工作,但由于某种原因它现在不被调用。

I have no interest or even understanding of OnNcCreate() except for the fact that it was the place I ended up getting BS_OWNERDRAW set the first time I tried writing a custom control. 我对OnNcCreate()没有兴趣甚至理解,除了它是我第一次尝试编写自定义控件时最终得到BS_OWNERDRAW的地方。

Question: What would keep OnNcCreate() from being called? 问题:什么会阻止OnNcCreate()被调用? Or, is there another place I could or should be setting BS_OWNERDRAW ? 或者,我可以或应该设置另一个地方BS_OWNERDRAW吗?

A working class is defined with: 工作类定义为:

class CGood : public CStatic {

The non-working one is defined with: 非工作的定义为:

class CBad : public CButton {

They both prototype the method thusly: 他们都是这样做的原型:

afx_msg int     OnNcCreate( LPCREATESTRUCT lpCreateStruct );

The method is written identically (except the class name): 该方法的编写方式相同(类名除外):

int CGood::OnNcCreate( LPCREATESTRUCT pcrs ) {

  wStyleBits = LOWORD( pcrs->style );

  DWORD dwStyleSuperclass = MAKELONG( ES_LEFT, HIWORD( pcrs->style ) );

  dwStyleSuperclass |= BS_OWNERDRAW;

  ::SetWindowLong( m_hWnd, GWL_STYLE, dwStyleSuperclass );

  pcrs->style = dwStyleSuperclass;

  return CStatic::OnNcCreate( pcrs );
}

The dialog is using both the good and bad classes utilizing the Visual Studio 2017 dialog editor, as CustomControl. 该对话框使用Visual Studio 2017对话框编辑器作为CustomControl使用好的和坏的类。 Both the good and bad classes have Extended Style 0x0 and Style 0x50010000. 好的和坏的类都有扩展样式0x0和样式0x50010000。 Both er Disabled=False, Help ID=False, Visible=True, Class=Good or Bad as needed. er disabled = False,Help ID = False,Visible = True,Class = Good或Bad。

When run the application calls each class's RegisterControlClass() method: 运行时,应用程序调用每个类的RegisterControlClass()方法:

static WNDPROC pfnWndProc = NULL;

BOOL CBad::RegisterControlClass() {

  WNDCLASS wcls;
  static const TCHAR szClass[] = _T( "CBad" );

  if ( ::GetClassInfo( AfxGetInstanceHandle(), szClass, &wcls ) )
      return wcls.lpfnWndProc == ( WNDPROC ) CBad::WndProcHook;

  VERIFY( ::GetClassInfo( NULL, _T( "button" ), &wcls ) );
  pfnWndProc = wcls.lpfnWndProc;

  wcls.lpfnWndProc   = CBad::WndProcHook;
  wcls.hInstance     = AfxGetInstanceHandle();
  wcls.lpszClassName = szClass;

  return RegisterClass( &wcls ) != 0;
}



LRESULT CALLBACK EXPORT CBad::WndProcHook( HWND hWnd, UINT msg,
                                              WPARAM wParam, LPARAM lParam ) {

  CBad* pthis = new CBad();
  pthis->Attach( hWnd );

  pthis->m_pfnSuper = pfnWndProc;
  ::SetWindowLong( hWnd, GWL_WNDPROC, ( DWORD )AfxWndProc );

#ifdef STRICT
  return ::CallWindowProc( AfxWndProc, hWnd, msg, wParam, lParam );
#else
  return ::CallWindowProc( ( FARPROC )AfxWndProc, hWnd, msg, wParam, lParam );
#endif
}

(Funny: I note in CGood , derived from CStatic , mistakenly has "button" there and works fine; it stops working if I change to "static" . I'll look into that later. The bad class has "button" and indeed is a CButton subclass.) (搞笑:我注意到在CGood ,从CStatic派生,错误地在那里有“按钮”并且工作正常;如果我改为“静态”它会停止工作。我会稍后调查。坏班有“按钮”,确实是一个CButton子类。)

Things I've done to confirm the issue: When I remove the BS_OWNERDRAW from the CGood::OnNcCreate() , it stops calling DrawItem() . 我已经做过的确认问题:当我从CGood::OnNcCreate()删除BS_OWNERDRAW ,它停止调用DrawItem() So I'm sure that's the place this flag is being set. 所以我确定这个标志正在设置的位置。

Putting a breakpoint in CGood::OnNcCreate() and CBad::OnNcCreate(), the CBad one simply isn't called. CGood::OnNcCreate()CBad::OnNcCreate(),放置一个断点,就不会调用CBad。

I've found examples on the internet of setting BS_OWNERDRAW in PreSubclassWindow() , OnCreate() , and CreateEx() , none of which work, in some cases for reasons I think I understand. 我在互联网上找到了在PreSubclassWindow()OnCreate()CreateEx()中设置BS_OWNERDRAW例子,但在某些情况下,由于我认为我理解的原因,这些例子都不起作用。 (EG you can't just set flags in OnCreate() and call the superclass method, because it is ultimately getting the flags not from the param you give it but from some other source.) (EG你不能只在OnCreate()中设置标志并调用超类方法,因为它最终得到的标志不是来自你给它的参数,而是来自其他来源。)

I've tried changing CBad's superclass to CStatic and still the OnNcCreate() isn't being called. 我已经尝试将CBad的超类更改为CStatic,但仍未调用OnNcCreate()。

I've tried setting BS_OWNERDRAW in the dialog's OnInitDialog() and that does get the CBad button subclass painting correctly. 我已经尝试在对话框的OnInitDialog()设置BS_OWNERDRAW ,这确实可以正确地绘制CBad按钮子类。 So I know I'm not accidently creating them with some other subclass, etc. 所以我知道我并没有意外地用其他一些子类创建它们,等等。

CBad* pcbut = (CBad*) GetDlgItem( IDC_MARKCHECK );
pcbut->ModifyStyle(0, BS_OWNERDRAW);

Ahh! 啊! I simply forgot to add it to the message map! 我只是忘了把它添加到消息地图中!

BEGIN_MESSAGE_MAP( CBad, CButton )
    //{{AFX_MSG_MAP( CBad )
    ON_WM_NCCREATE()
    //}}AFX_MSG_MAP
END_MESSAGE_MAP()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM