65.9K
CodeProject 正在变化。 阅读更多。
Home

通用选择器下拉控件

2008年12月12日

CPOL

3分钟阅读

viewsIcon

55527

downloadIcon

3143

一个灵活且易于覆盖的类似组合框的控件,用于从二维选项数组中选择

引言

本文的灵感来自 Chris Maunder 的 Office 97 风格的颜色选择器控件。 几年前,我对其进行了很大的修改,以便在我的软件中从调色板中选择颜色。 我没有创建自己的调色板,而是使用了 Autocad 在 DXF 文件中的定义。 0 = 黑色,1 = 白色,2 = 红色等。 最近,我需要添加一些绘图功能。 一旦我添加了几个图案,我就想添加其余的。 这就构成了一个超过 60 个条目的下拉列表。 同样,我想要用于线宽和线型的下拉列表。

所以我回到了 Chris 的文章,窃取/重用了处理弹出窗口的部分,并完成了其余部分。 因为我知道我将制作各种相关的控件,所以我将一些成员函数设为纯虚函数,并在几个继承类中实现了特定的功能。

最后,示例项目和大多数预构建的选择器都使用 GDI+。 这与核心思想完全无关 - 但它是该项目的存在理由(来自法语的 sultana of summer)。

预构建的选择器 

颜色选择器

这是我最初实现的,并且最接近 Chris 的实现。

线型

线宽

阴影线样式

如何在您自己的代码中使用通用选择器控件。

希望这很简单! 我将以线型选择器为例。 首先,向您的对话框添加一个按钮,并为其指定一个 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 的实现作为一个例子。

GetColumns & GetRows

int	CPickerLineWidth::GetColumns () const		{ return 2;	}
int	CPickerLineWidth::GetRows () const		{ return 10;	}

希望这两个可重写项是不言自明的! 2D 下拉列表的宽度和高度有多少个框...

MeasureSubItem

void CPickerLineWidth::MeasureSubItem(CSize &mis)
{
	mis.cx /= 2;
	mis.cy = 12;
}

MeasureSubItem 被调用一次。 CSize 结构被初始化为与您添加到对话框的按钮大小相同。 这使得很容易将下拉列表的宽度与父控件的宽度匹配。 因为我有两列,并且都不需要特定的宽度,所以我只是在它们之间分配宽度。 对于其他控件(如颜色或阴影线样式,这是固定的尺寸。

DrawSubItem

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、绘图矩形、当前列和行以及是否应将其绘制为选中状态。

在我的控件中,选定的选项用于选择以深灰色或黑色绘制。 随意变得更花哨。

ShowDefaultItem

BOOL CPickerLineWidth::ShowDefaultItem () const { return FALSE; }

这实际上不是由我实现的 - Chris 的控件使用它。 这让继承的控件告诉 CGenericPicker 类是否为默认项目留出空间。 这将以 -1 的列和行绘制。

致谢

历史

  • 1.0 初始版本 
© . All rights reserved.