simple_life

导航

MFC:使用按钮更改列表框控件的背景颜色

开发平台:Visual C++ 6.0

昨天要做一个可以改变列表框控件背景颜色的MFC程序,在网上找了半天也没有发现满足我自己需要的解决方案。网上的解决方案都是在窗口初始化的时候完成了对列表框控件背景颜色的设置,之后就不能更改了。而我需要的是随时可以更改列表框控件背景颜色的功能。按照心中的构思,既然在初始化的时候可以改变列表框控件的背景颜色,那么在其他时候也可以改变列表框控件的背景颜色。通过查找资料,发现通过改变画刷的颜色,然后在强制整个系统或某个控件进行重画的时候,控件的背景颜色就可以改变为画刷的颜色。于是,我所需要的功能就实现了。

首先,来了解两个知识点:

1. MFC中的Invalidate()函数是什么意思?

Invalidate()函数是强制系统进行重画,但是不一定就马上进行重画。因为Invalidate()只是通知系统,此时的窗口已经变为无效。强制系统调用WM_PAINT,而这个消息只是Post,就是将该消息放入消息队列。当执行到WM_PAINT消息时才会对窗口进行重绘。

类似的还有下面的两个函数:

  • UpdateWindow()只向窗体发送WM_PAINT消息,在发送之前判断GetUpdateRect(hWnd,NULL,TRUE)看有无可绘制的客户区域,如果没有,则不发送WM_PAINT。
  • RedrawWindow()则是具有Invalidate()和UpdateWindow()的双特性。声明窗口的状态为无效,并立即更新窗口,立即调用WM_PAINT消息处理。

2. MFC中OnCtlColor是何时调用的?

一般在窗口需要更新的时候被调用。比如最小化后最大化、窗口被遮盖后重新显示,或调用窗口的Invalidate()函数使窗口无效、或在程序刚启动的时候。

接下来,使用Visual C++ 6.0创建MFC对话框程序:

1. 建立一个工程,名称为ChangeColor,如下图所示:

2. 选择要创建的应用程序类型为基本对话框,然后点击完成,如下图所示:

3. 在步骤2点击“完成”之后,会弹出一个工程的规格骨架提示框,点击“确定”即可。

4. 进入IDD_CHANGECOLOR_DIALOG设计界面后,需要完成以下几个步骤:

① 删除界面上的“TODO: 在这里设置对话控制。”标签;

② 删除界面上自动生成的“确定”按钮,保留“取消”按钮,其标题改为“退出程序”;

③ 添加一个列表框控件,ID改为IDC_SHOW_LIST,并为之添加相应的控制变量m_ShowList;

④ 添加一个按钮,ID改为IDC_ADD_BUTTON,其标题改为“添加字符串”;

⑤ 添加一个按钮,ID改为IDC_GREEN_BUTTON,其标题改为“设为绿色”;

⑥ 添加一个按钮,ID改为IDC_RED_BUTTON,其标题改为“设为红色”;

完成上述6个步骤,调整界面,效果如下所示:

 

5. 建立类向导,分别为4个按钮添加BN_CLICKED消息函数,函数名称选择默认即可;

6. 重载OnCtlColor()函数,在Message Maps栏的Object IDs框中选中CchangeColorDlg,接着在Messages框中选中WM_CTLCOLOR,接着点击“Add Function”按钮,如下所示:

 

7. 点击类向导中的“确定”按钮,完成类向导的建立。

接下来,添加函数代码:

1. 可以在ChangeColorDlg.h里的类声明中添加画刷变量m_brush,也可以在ChangeColorDlg.cpp中声明一个全局的画刷变量m_brush。这里选择的第一种方式,并添加了一个字体变量m_Font,如下:

class CChangeColorDlg : public CDialog
{
// Construction
public:
    CChangeColorDlg(CWnd* pParent = NULL);    // standard constructor

// Dialog Data
    //{{AFX_DATA(CChangeColorDlg)
    enum { IDD = IDD_CHANGECOLOR_DIALOG };
        // NOTE: the ClassWizard will add data members here
    //}}AFX_DATA

    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CChangeColorDlg)
    protected:
    virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
    //}}AFX_VIRTUAL

// Implementation
protected:
    HICON m_hIcon;
    CBrush m_brush;    // 画刷变量 m_brush 的声明
    CFont m_Font;      // 字体变量 m_Font 的声明

    // Generated message map functions
    //{{AFX_MSG(CChangeColorDlg)
    virtual BOOL OnInitDialog();
    afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
    afx_msg void OnPaint();
    afx_msg HCURSOR OnQueryDragIcon();
    afx_msg void OnAddButton();
    afx_msg void OnGreenButton();
    afx_msg void OnRedButton();
    virtual void OnCancel();
    afx_msg HBRUSH OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor);
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
};

2. 在CChangeColorDlg::OnInitDialog()函数中设置字体的大小和格式:

// TODO: Add extra initialization here
m_Font.CreatePointFont(150, "Consolas", NULL);  // 设置字体的大小和格式
m_ShowList.SetFont(&m_Font, true);   // 设置列表框中的字体的格式

3. 下面是OnCtlColor()函数的定义:

HBRUSH CChangeColorDlg::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) 
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    
    // TODO: Change any attributes of the DC here
    if (nCtlColor == CTLCOLOR_LISTBOX)
    {
        pDC->SetTextColor(RGB(0,0,255));  // 修改字体的颜色
        pDC->SetBkMode(TRANSPARENT);  // 把字体的背景变成透明的
        return m_brush;  // 返回背景色
    }

    // TODO: Return a different brush if the default is not desired
    return hbr;
}

4. 下面是4个按钮所对应的消息函数的定义:

void CChangeColorDlg::OnAddButton() 
{
    // TODO: Add your control notification handler code here
    m_ShowList.AddString("Hello world!");
}

void CChangeColorDlg::OnGreenButton() 
{
    // TODO: Add your control notification handler code here
    m_brush.Detach();  // 必不可少
    m_brush.CreateSolidBrush(RGB(0,255,0));
    m_ShowList.RedrawWindow();
}

void CChangeColorDlg::OnRedButton() 
{
    // TODO: Add your control notification handler code here
    m_brush.Detach();  // 必不可少
    m_brush.CreateSolidBrush(RGB(255,0,0));
    m_ShowList.RedrawWindow();
}

void CChangeColorDlg::OnCancel() 
{
    // TODO: Add extra cleanup here
    
    CDialog::OnCancel();
}

至此,函数代码已全部添加完成。

测试程序:

1. 运行MFC程序,如下所示:

2. 点击“添加字符串”按钮两次,效果如下:

3. 点击“设为绿色”按钮,效果如下:

4. 点击“添加字符串”两次,效果如下:

5. 点击“设为红色”按钮,效果如下:

6. 点击“添加字符串”两次,效果如下:

7. 点击“退出程序”按钮,程序退出。

改进程序

通过程序运行,我们发现,列表框的背景颜色已经可以通过按钮来随意改变。但也存在一个不足,我们在程序的OnCtlColor()函数中已经设置了列表框中字体的颜色为蓝色,但在程序刚开始运行时,我们点击“添加字符串”按钮,打印出来的却都是默认的黑色字体。直到点击“设为绿色”或“设为红色”按钮后,列表框中的字体颜色才变为蓝色。

尽管我不是处女座,但面对这样的问题依然忍不了。通过阅读代码发现,之所以出现这个问题,是因为程序在调用OnCtlColor()函数时,画刷变量m_brush没有初始化,因此程序使用默认的颜色来打印字符串,直到该变量的值被改变时,列表框控件中的字体的颜色才被改变。

通过以上分析,我们需要修改OnInitDialog()函数,添加一行m_brush的初始化代码,如下:

// TODO: Add extra initialization here
m_Font.CreatePointFont(150, "Consolas", NULL);
m_ShowList.SetFont(&m_Font, true);
m_brush.CreateSolidBrush(RGB(255, 255, 255));  // 初始化 m_brush

再次执行程序,点击“添加字符串”按钮三次,效果如下:

OK,问题得到解决。

测试其他按钮的功能,依然完好如初。

结语

通过以上的演示,我们给出了列表框中字体的颜色和格式的修改方法,以及如何在程序中随意改变列表框控件的背景颜色的解决方案。

这些方法可以在以后的设计中灵活使用!

posted on 2016-10-26 10:27  simple_life  阅读(2319)  评论(0)    收藏  举报