none
请教关于ListBox控件重绘的问题? RRS feed

  • 问题

  • 目前的情况是,自绘部分我已实现,在对话框中设置Owner Draw的Fixed属性或者Variable属性,自绘部分工作正常。

    我想通过代码的形式设置自绘属性,但程序运行时呈现出的界面依然是系统默认界面,而不是我自绘的部分,请问该如何通过代码设置自绘?

    还有一点比较奇怪的是,我用Spy++查看了我通过代码设置的自绘属性,Spy++中显示我的设置已生效,但实际效果来看好像并未生效。

     

    // .h
    protected:
      virtual void PreSubclassWindow();
    
      virtual int CompareItem(LPCOMPAREITEMSTRUCT lpCIS);
      virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
      virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
      virtual void DrawItemDetail(LPDRAWITEMSTRUCT lpDIS, BOOL bSelected);
    
    //.cpp
    void CListBoxEx::PreSubclassWindow()
    {
      ModifyStyle( LBS_SORT, LBS_OWNERDRAWFIXED|LBS_HASSTRINGS, SWP_NOSIZE );
      CListBox::PreSubclassWindow();
    }
    

    2011年7月8日 0:47

全部回复

  • 有些控件的风格并不支持Runtime时修改,您可以动态创建,调用Create()函数时候带上指定的属性LBS_OWNERDRAWFIXED.
    Visual C++ enthusiast, like network programming and driver development. At present is being engaged in the WinCE/Windows Mobile platform embedded development.
    2011年7月8日 3:30
    版主
  • 首先,感谢您的答复。

    我主要想实现类似于IE浏览器地址栏那样的效果。就是点击地址栏下拉箭头时,列出历史记录,鼠标放在某条上时,右边会显示“X”删除按钮。

    我想重载CComboBox,自绘ListBox控件,然后子类化CComboBox的ListBox。所以这时需要通过代码来设置LBS_OWNERDRAWFIXED。

     

    网上我也差了不少资料,好像说ModifyStyle( 0, LBS_OWNERDRAWFIXED)对于ListBox无效,是不是我这种方式行不通,谢谢!

    2011年7月8日 5:02
  • 您不要静态关联就可以了,即在对话框模板上拖动一个CListBox上去,然后DDX_Control()关联您的ClistBox派生类对象。
    而是定义个CListBoxEx m_listBox;对象,然后再窗口初始化函数中调用m_listBox.Create(...);函数来动态创建,


    Visual C++ enthusiast, like network programming and driver development. At present is being engaged in the WinCE/Windows Mobile platform embedded development.
    2011年7月8日 5:36
    版主
  • 非常感谢您的耐心解答,我也为我对问题的说明不详尽感到抱歉。

    我目前开发环境是VS2010,我目前的项目需求是这样的:我想派生一个CMFCPropertyGridProperty控件,该派生控件类似于AddOption后的效果,我想在用户点击下拉按钮时显示出的ListBox中达到下面的效果。当鼠标移动某项中时,高亮显示此项(系统默认是这样的),并且在该项上显示一个“x”按钮(按钮也行,绘制的也行),当用户点击这个“x”按钮时删除此项。IE9地址栏具有此功能,IE8也应该有。

    查看CMFCPropertyGridProperty源代码,当用户点击Value区域时,此时弹出的正是CComboBox。因此我想实现此功能时只需实现一个具有“x”功能的ComboBox即可。而ComboBox又是有ListBox组成的,因此我想实现一个具有“x”功能的ListBox即可。于是我想到了重绘ListBox,并且在CComboBox中子类化CComboBox中原有的ListBox。

    子类化ComboBox自带的ListBox没有问题,问题就出在我派生的CListBoxEx类不能设置自绘属性(准确地说是设置了,但是没有达到预期可自绘的效果)。

    CComboBox中的ListBox应该是在创建CComboBox时已经创建的,我不太清楚您说的Create是什么意思?我刚才也试了如下代码:

    void CComboBoxExt::PreSubclassWindow()
    {
      CComboBox::PreSubclassWindow();
    
      COMBOBOXINFO cbi= { sizeof(cbi) };
      GetComboBoxInfo( &cbi );
    
      m_listBox.Create( WS_VISIBLE|WS_CHILD|LBS_NOTIFY|LBS_OWNERDRAWFIXED, CRect(0, 0, 100, 50), this, 20 );
    //  m_listBox.SubclassWindow( cbi.hwndList );
    }
    

    运行结果是程序崩溃,查看断言处:void CComboBox::MeasureItem(LPMEASUREITEMSTRUCT) { ASSERT(FALSE); }。这个问题也比较奇怪,我设置的是ListBox为自绘,不知为什么这里使得CComboBox也成了自绘了(我确定ComboBox控件不是自绘属性,而且我也没有在代码中设置)。

     

    这是我正常的代码,就是没有作用:

    void CComboBoxExt::PreSubclassWindow()
    {
      COMBOBOXINFO cbi= { sizeof(cbi) };
    
      GetComboBoxInfo( &cbi );
      m_listBox.SubclassWindow( cbi.hwndList );
    
      CComboBox::PreSubclassWindow();
    }
    

    谢谢!

    2011年7月8日 7:00
  • 我都有点困惑了,您前面问的不是关于CListBox自绘的问题吗?怎么到后面又是CComboBox了?您是想子类化CComboBox控件的下拉列表是吧?
    参考:http://support.microsoft.com/kb/174667/zh-cn
    Visual C++ enthusiast, like network programming and driver development. At present is being engaged in the WinCE/Windows Mobile platform embedded development.
    2011年7月8日 7:40
    版主
  • 不好意思,我拙劣的表达能力让您产生了困惑。

    是的,现在问题的根本还是CListBox控件的自绘使能问题,我后来补充的情况主要是想说明我这样做的原因和这样做的环境。

    1)简单点说,我不能通过对话框中点击“属性”手动设置自绘属性,只能通过代码来设置这个属性。

    2)"您是想子类化CComboBox控件的下拉列表是吧?" 是的,我想要的结果就是这样的。实践中子类化CComboBox的ListBox控件是成功了(我子类化成CListBoxEx,我从CListBox派生的用于自绘的子类),调试时也进入CListBoxEx的PreSubClassWindow函数,但是就是因为我的CListBoxEx没有能够成功设置LBS_OWNERDRAWFIXED属性,导致最终CComboBox显示出来的ListBox还是系统的样式。

    3)如果在对话框中直接拖入ListBox控件,并用我的CListBoxEx去关联该控件也还是系统样式;但如果把该控件通过属性手动设置成自绘属性的话,则会显示我自绘的样式。这点至少可以证明我的CListBoxEx对于未手动设置LBS_OWNERDRAWFIXED属性的ListBox,不能使能其自绘模式。

    4)CComboBox不需要自绘。

     

    您推荐的这篇文章和MSDN中的比较相似,据我的理解,主要是介绍如何子类化CComboBox的ListBox控件。如前所述,我子类化应该没问题,主要是CListBox使其自身可重绘部分存在问题。

     

     

    2011年7月8日 8:02
  • 下面是我CListBoxEx的完整代码:

    #pragma once
    
    
    // CListBoxEx
    
    class CListBoxEx : public CListBox
    {
    	DECLARE_DYNAMIC(CListBoxEx)
    
    public:
    	CListBoxEx();
    	virtual ~CListBoxEx();
    
    protected:
    	DECLARE_MESSAGE_MAP()
    
    protected:
      virtual void PreSubclassWindow();
    
      virtual int CompareItem(LPCOMPAREITEMSTRUCT lpCIS);
      virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMIS);
      virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS);
      virtual void DrawItemDetail(LPDRAWITEMSTRUCT lpDIS, BOOL bSelected);
    
    protected:
      CRect m_rectBtn;
    };
    
    
    
    // ListBoxEx.cpp : 实现文件
    //
    
    #include "stdafx.h"
    #include "CustomUI.h"
    #include "ListBoxEx.h"
    
    
    // CListBoxEx
    
    IMPLEMENT_DYNAMIC(CListBoxEx, CListBox)
    
    CListBoxEx::CListBoxEx()
    {
    
    }
    
    CListBoxEx::~CListBoxEx()
    {
    }
    
    
    BEGIN_MESSAGE_MAP(CListBoxEx, CListBox)
    END_MESSAGE_MAP()
    
    
    // CListBoxEx 消息处理程序
    
    void CListBoxEx::PreSubclassWindow()
    {
      ModifyStyle( LBS_SORT, LBS_OWNERDRAWFIXED|LBS_HASSTRINGS, SWP_NOSIZE );
      CListBox::PreSubclassWindow();
    }
    
    int CListBoxEx::CompareItem( LPCOMPAREITEMSTRUCT lpCIS )
    {
      return -1;
    }
    
    void CListBoxEx::MeasureItem( LPMEASUREITEMSTRUCT lpMIS )
    {
    }
    
    void CListBoxEx::DrawItem( LPDRAWITEMSTRUCT lpDIS )
    {
      CDC *pDC = CDC::FromHandle( lpDIS->hDC );
    
      // 窗口禁用
      if( !IsWindowEnabled() )
      {
        CBrush brDisabled( RGB(192, 192, 192) );
        CBrush *pOldBrush = pDC->SelectObject( &brDisabled );
    
        CPen penDisabled( PS_SOLID, 1, RGB(192, 192, 192) );
        CPen *pOldPen = pDC->SelectObject( &penDisabled );
    
        DrawItemDetail( lpDIS, FALSE );
    
        pDC->SelectObject( pOldBrush );
        pDC->SelectObject( pOldPen );
    
        return;
      }
    
      // 被选中
      if( (lpDIS->itemState & ODS_SELECTED) && (lpDIS->itemAction & (ODA_SELECT|ODA_DRAWENTIRE)) )
      {
        CBrush brHighlight( ::GetSysColor( COLOR_HIGHLIGHT ) );
        CBrush *pOldBrush = pDC->SelectObject( &brHighlight );
    
        CPen penHighlight( PS_SOLID, 1, ::GetSysColor( COLOR_HIGHLIGHT ) );
        CPen *pOldPen = pDC->SelectObject( &penHighlight );
    
        pDC->Rectangle( &lpDIS->rcItem );
        pDC->SetBkColor( ::GetSysColor( COLOR_HIGHLIGHT ) );
        pDC->SetTextColor( ::GetSysColor( COLOR_HIGHLIGHTTEXT ) );
    
        DrawItemDetail( lpDIS, TRUE );
    
        pDC->SelectObject( pOldBrush );
        pDC->SelectObject( pOldPen );
      }
    
      // 取消选择
      if( !(lpDIS->itemState & ODS_SELECTED) && (lpDIS->itemAction & (ODA_SELECT|ODA_DRAWENTIRE)) )
      {
        CBrush brWindow( ::GetSysColor( COLOR_WINDOW ) );
        CBrush *pOldBrush = pDC->SelectObject( &brWindow );
    
        CPen penHighlight( PS_SOLID, 1, ::GetSysColor( COLOR_WINDOW ) );
        CPen *pOldPen = pDC->SelectObject( &penHighlight );
    
        pDC->Rectangle( &lpDIS->rcItem );
        pDC->SetBkColor( ::GetSysColor( COLOR_WINDOW ) );
        pDC->SetTextColor( ::GetSysColor( COLOR_WINDOWTEXT ) );
    
        DrawItemDetail( lpDIS, FALSE );
    
        pDC->SelectObject( pOldBrush );
        pDC->SelectObject( pOldPen );
      }
    
      // 焦点态
      if( lpDIS->itemAction & ODA_FOCUS )
      {
        pDC->DrawFocusRect( &lpDIS->rcItem );
      }
    }
    
    void CListBoxEx::DrawItemDetail( LPDRAWITEMSTRUCT lpDIS, BOOL bSelected )
    {
      CString strItemText;
      CDC *pDC = CDC::FromHandle( lpDIS->hDC );
    
      if( lpDIS->itemID == CB_ERR || GetCount() == 0 )
      {
        return;
      }
    
      GetText( lpDIS->itemID, strItemText );    
      pDC->DrawText( strItemText, &lpDIS->rcItem, DT_LEFT );
    
      if( bSelected )
      {
        m_rectBtn = lpDIS->rcItem;
        m_rectBtn.left = m_rectBtn.right - m_rectBtn.Height();
        m_rectBtn.DeflateRect( 2, 2 );
    
        pDC->FillSolidRect( m_rectBtn, RGB(191, 80, 65) );
        pDC->DrawText( _T("x"), m_rectBtn, DT_CENTER );
      }
    }
    
    

    2011年7月8日 8:10