在软件开发过程中,经常需要创建一些特定的控件来满足用户界面的需求。本文将介绍如何在自己的代码中使用通用选择器控件,并提供一个创建自定义选择器控件的示例。
本文的灵感来源于Chris Maunder的Office 97风格的Color Picker控件。几年前,对它进行了大量修改,以便在软件中从调色板中选择颜色。没有创建自己的调色板,而是使用了Autocad在DXF文件中定义的颜色。0代表黑色,1代表白色,2代表红色,以此类推。最近,需要添加一些绘图功能。一旦添加了一些图案,就想添加其余的。这将形成一个包含60多个选项的下拉列表。同样,想要有下拉列表来选择线宽和线型。
希望这非常简单!将以线型选择器为例。首先,在对话框中添加一个按钮,并给它一个ID号。文本无关紧要,但方便以后编辑对话框。
#include "DrawingPickers.h"
class CGenericPickerDemoDlg : public CDialog {
...
CPickerLineStyle m_LineStyle;
...
};
接下来,在OnInitDialog对话框成员函数中子类化控件。还喜欢初始化当前项。如果愿意,可以在DoDataExchange中使用DDX_Control,但很少这样做。
BOOL CGenericPickerDemoDlg::OnInitDialog() {
CDialog::OnInitDialog();
...
m_LineStyle.SubclassDlgItem(IDC_LINESTYLE, this);
m_LineStyle.SetStyle(Gdiplus::DashStyleSolid);
...
return TRUE; // return TRUE unless you set the focus to a control
}
要处理选择的变化,应该处理CBN_SELCHANGE通知。Chris的控件使用了自定义消息,但想偷懒,能够使用ON_CBN_SELCHANGE宏来编写代码。
BEGIN_MESSAGE_MAP(CGenericPickerDemoDlg, CDialog)
...
ON_CBN_SELCHANGE(IDC_LINESTYLE, OnPickerChanged)
...
END_MESSAGE_MAP()
最后,需要对选择做一些事情。在演示程序中,用各种样式画一个圆。由于这不是一个GDI+教程,将跳过这部分!
在CGenericPicker中有一些纯函数需要覆盖。它们是:
virtual int GetColumns() const = 0;
virtual int GetRows() const = 0;
virtual void MeasureSubItem(CSize &mis) = 0;
virtual void DrawSubItem(const DrawItemSubStruct &dis) = 0;
virtual BOOL ShowDefaultItem() const = 0;
virtual BOOL IsCellValid(int nCol, int nRow) const {
return TRUE;
}
将展示CPickerLineWidth的实现作为示例。
int CPickerLineWidth::GetColumns() const {
return 2;
}
int CPickerLineWidth::GetRows() const {
return 10;
}
希望这两个可覆盖函数相当直观!2D下拉菜单有多少个框宽和高...
void CPickerLineWidth::MeasureSubItem(CSize &mis) {
mis.cx /= 2;
mis.cy = 12;
}
MeasureSubItem被调用一次。CSize结构被初始化为与添加到对话框的按钮相同的大小。这使得将下拉菜单的宽度与父控件的宽度匹配变得容易。由于有两列,而且它们都不需要特定的宽度,只是将宽度在它们之间分割。对于其他控件(如颜色或填充样式,这是固定大小的)。
void CPickerLineWidth::DrawSubItem(const DrawItemSubStruct &dis) {
CRect rc(dis.rcItem);
Graphics graphics(*dis.pDC);
Color colour;
colour.SetFromCOLORREF(dis.bSelected ? GetSysColor(COLOR_BTNTEXT) : GetSysColor(COLOR_BTNSHADOW));
float fWidth = dis.nRow + float(10 * dis.nColumn);
fWidth /= 2.0f;
Pen pen(colour, fWidth);
graphics.DrawLine(&pen, rc.left, rc.top + 6, rc.right, rc.top + 6);
}
DrawSubItem负责控件的繁重工作。它用于绘制按钮和每个单元格。DrawItemSubStruct结构有CDC、绘图矩形、当前列和行,以及是否应该绘制为选中状态。
BOOL CPickerLineWidth::ShowDefaultItem() const {
return FALSE;
}
这并不是真的由实现的 - Chris的控件使用它。这让继承控件告诉CGenericPicker类是否要为默认项留出空间。这将用-1的列和行绘制。