CFunctionEdit - n元组输入的自定义控件 v1.2






3.43/5 (7投票s)
2003 年 11 月 9 日
4分钟阅读

50399

2714
一个用于 n 元组输入的自定义控件。
引言
CFunctionEdit
是一个使用纯 Win32 API 编写的自定义控件,它允许用户输入 n 元组数据(例如数学函数、向量等)。
特点
CFunctionEdit
不限制元组的大小,但目前不支持在运行时更改元组大小。元组大小在创建控件时确定。一旦控件创建完成,您就可以设置和获取文本、限制每个元组的文本大小、更改用于渲染文本的字体、背景颜色,并定义您自己的文本格式化函数来实现彩色和带样式的文本渲染。
- 版本 1.1 支持文本选择以及剪切、复制、粘贴操作。
- 版本 1.2 具有弹出菜单和
readonly
样式。
初始化和使用控件
首先,使用应用程序的 HINSTANCE
调用类的 Init()
成员。Init()
函数只是在窗口类尚未注册时注册它。之后,您可以通过提供适当的参数,使用 Create()
成员函数来创建控件的实例。您可以声明您的 CFunctionEdit
变量为静态的,或者使用 new
动态创建。
CFunctionEdit theEdit; CFunctionEdit *pEdit; void CreateControls() { // Call this only once before creating your controls CFunctionEdit::Init(hInstance); theEdit.Create(50, 20, 100, 40, hwndParent); pFunctionEdit = new CFunctionEdit; pFunctionEdit->Create(50, 120, 100, 40, hwndParent); }
在创建控件后,您可以使用 SetText()
更改内容,并使用 GetText()
获取内容。
int CFunctionEdit::SetText(int nIndex, const TCHAR *szText); int CFunctionEdit::GetText(int nIndex, TCHAR *szText);
这里 nIndex
是元组的索引。索引从 0 开始,一直到元组数量减一。特殊情况是,如果索引等于 -1,则给定的文本将分配给控件中的所有元组。
// Assume we have a CFunctionEdit object // called theEdit for all the following examples. theEdit.SetText(-1, TEXT("")); // Clears all the tuples. theEdit.GetText(0, szText); // Gets the text of the first tuple.
您可以使用 SetTextLimit()
函数来限制每个元组的文本大小。
for(int a = 0; a < nTupleCount; a++) { // At most 3 characters can be entered in each tuple. theEdit.SetTextLimit(a, 3); }
CFunctionEdit
具有以下对控件的输入和渲染有影响的样式标志:
#define FES_NUMERIC 1 // Allows only the input of numbers. #define FES_UPPERCASE 2 // Converts lowercase characters to uppercase. #define FES_LOWERCASE 4 // Converts uppercase characters to lowercase. #define FES_DISABLESPACE 8 // Space character is ignored. #define FES_CENTERTEXT 16 // The text is centered in the view. #define FES_READONLY 32 // Space character is ignored.
如果您在 Create()
函数中没有显式提供样式参数,默认情况下将设置 FES_CENTERTEXT
、FES_DISABLESPACE
和 FES_LOWERCASE
样式。
theEdit.SetStyle(FES_CENTERTEXT | FES_NUMERIC);
可视化特性
可以使用 SetBackgroundColor()
函数更改背景颜色。
theEdit.SetBackgroundColor(RGB(255, 255, 255)); // White background
可以使用 SetFont()
函数更改用于渲染文本的字体。
// Last two parameters are optional theEdit.SetFont(TEXT("Courier New"), 24, ANSI_CHARSET);
渲染文本和更改默认文本格式化函数
当用户通过按键更改文本缓冲区时,会调用 FormatText()
函数来格式化文本。该函数负责创建一个由 FORMATTEDTEXTBLOCK
结构组成的列表。它首先添加带有粗体样式的 " ( ",然后为每个元组调用格式化函数,并添加 " ) " 作为最后一个 FORMATTEDTEXTBLOCK
。渲染的整个文本是 FORMATTEDTEXTBLOCK
的列表。
typedef struct _tagFormattedTextBlock { #ifndef UNICODE std::string strBlock; #else std::wstring strBlock; #endif COLORREF clColor; DWORD dwStyle; } FORMATTEDTEXTBLOCK, *LPFORMATTEDTEXTBLOCK; typedef std::list<FORMATTEDTEXTBLOCK> FormattedText;
正如您所见,FORMATTEDTEXTBLOCK
用于定义一个具有自身颜色和样式的字符串。dwStyle
成员可以是零,或者是一个以下值(但不能组合):
#define TEXTFORMAT_BOLD 1 #define TEXTFORMAT_ITALIC 2 #define TEXTFORMAT_UNDERLINE 4
这是默认的格式化函数
LRESULT CFunctionEdit::DefFormatTextProc(int nIndex, const TCHAR *szText, FormattedText &ft) { FORMATTEDTEXTBLOCK fmttext; if(*szText == TEXT('\0')) return 0; // Default formatting : black, normal font fmttext.dwStyle = 0; fmttext.clColor = RGB(0, 0, 0); fmttext.strBlock = szText; ft.push_back(fmttext); return 0; }
此函数仅将文本以黑色-普通样式添加到 FormattedText
列表中。您可以解析传递给此函数的 szText
,并将其拆分为多个 FORMATTEDTEXTBLOCK
,每个块具有不同的样式。我在类中提供了一个自定义格式化函数,该函数将数字渲染为蓝色,标点符号渲染为粗体绿色,其他字符渲染为红色。
文本选择
您可以使用 SetSelection()
进行选择。
int CFunctionEdit::SetSelection(TUPLEPOS start, TUPLEPOS end); typedef struct _tagTuplePos { int nTupleIndex; int nPosition; } TUPLEPOS, *LPTUPLEPOS;
TUPLEPOS
结构标识了控件中的一个唯一位置。结构体中的第一个成员 nTupleIndex
是我们要将光标移动到的元组索引。nPosition
是该元组内光标的位置。
TUPLEPOS selstart, selend; selstart.nTupleIndex = 1; selstart.nPosition = 0; selend.nTupleIndex = 2; selend.nPosition = 3; // selects from 2nd tuple's beginning to 3rd tuple's 3rd position. theEdit.SetSelection(selstart, selend);
检索选区
可以通过 GetSelection()
检索选中的文本。
theEdit.GetSelection(szBuffer);
定位光标
SetCaretPos()
函数用于定位光标。其原型为:
int CFunctionEdit::SetCaretPos(TUPLEPOS tuplepos);
TUPLEPOS tuplepos; tuplepos.nTupleIndex = 0; tuplepos.nPosition = 0; // Moves the cursor to the first position of the first tuple; theEdit.SetCaretPos(tuplepos); tuplepos.nTupleIndex = 1; tuplepos.nPosition = 5; // Moves the cursor to the 5th position of the second tuple. theEdit.SetCaretPos(tuplepos);
消息路由
最后,我想对类中的消息路由方式说几句。
typedef struct _tagWindowListEntry { HWND hWnd; CFunctionEdit *pEdit; } WINDOWLISTENTRY, *LPWINDOWLISTENTRY; typedef std::list<WINDOWLISTENTRY> WindowList;
我们有一个列表,其中包含窗口句柄和关联的对象指针。每次使用 Create()
函数创建窗口时,窗口句柄和类实例的指针都会被添加到名为 Windows
的全局变量中,该变量的类型为 WindowList
。这样,我们就可以知道哪个句柄属于哪个 CFunctionEdit
对象。当 Windows 向我们的 WindowProc
发送消息时,我们通过 GetEditWindow()
函数找到关联的 CFunctionEdit*
。该函数遍历列表以查找给定句柄的对象指针。找到指针后,我们调用该对象的处理程序。
MFC 和 Unicode
虽然我创建该控件时并没有考虑在 MFC 或 Unicode 项目中使用,但我曾在 MFC-Unicode 示例项目中测试过,一切似乎都运行良好。然而,我很难测试控件的所有功能,并找出是否需要为这些类型的项目进行特殊处理。
版本历史
- 版本 1.0:2003 年 11 月 9 日
- 首次发布
- 版本 1.1:2003 年 11 月 10 日
- 定位光标
- 选择
- 剪切、复制、粘贴
- 版本 1.2:2003 年 11 月 16 日
Readonly
样式- 弹出菜单
支持与反馈
如有任何评论和建议,请通过 e110870@metu.edu.tr 发送电子邮件给我。