控件中的控件:带行号的编辑框






4.91/5 (22投票s)
带行号的编辑控件
引言
CLineNumberEdit
是一个从 CEdit
派生的类,具有自动在左边距添加行号的功能。边栏的颜色和行号的格式都可以编辑。这个子类化是对在编辑框内包含控件的一次实验,即使我已经添加了足够的功能使其具有一定的实用性,主要目标还是为了探索这种包含(也可参阅 www.codeproject.com/editctrl/editwithicon.asp)。
使用代码
将 cpp 和 h 文件添加到项目中。CLineNumberEdit
可以动态创建,通过调用 Create
,或者从对话框模板创建。在后一种情况下,可以使用类向导创建并绑定控件变量,或者使用 SubclassDlgItem
。
此类公共成员
要设置行号字段的背景颜色,请调用 SetMarginBackgroundColor
。默认值为 RGB( 255, 255, 248 )
(参见图片)。
SetMarginForegroundColor
用于设置文本颜色。默认值为黑色。
SetLineNumberFormat
用于设置格式字符串,该字符串稍后将与 CString::Format
一起使用,因此它遵循该调用的规则。格式字符串必须包含一个(且仅一个)数字类型。默认值为 "%05i"
,生成一个右对齐、零填充的 5 位字符串。
在 PreSubclassWindow
中,会检查编辑框的样式。如果它不包含 ES_MULTILINE
,则类会 ASSERT
。除了在最少的情况下可能与非多行编辑框有些不相关之外,用于为行号腾出空间的 SetRect
调用对于单行编辑框将无法正常工作。
边距在 Prepare
中设置。在此,计算行号字段所需的宽度。这通过创建一个字符串来完成,使用控件的格式字符串,并使用控件的最大字符数(调用 CEdit::GetLimitText
)对其进行格式化。这假设每行只有一个字符,因此我们知道这将是我们的最大行数。测量字符串,然后添加一个小边距。
最后,创建一个具有所需尺寸的 CLineNumberStatic
(一个从 CStatic
派生的控件)。编辑框的顶部和底部行会发送给此控件。顶部边距也已设置。
CLineNumberStatic
是一个简单的从 CStatic
派生的类,通过 OnPaint
管理行号的绘制。绘制到内存 CDC
并将其blit 到屏幕,并且会处理 WM_ERASEBKGND
以避免闪烁。
通过设置新的顶部和底部行值,CLineNumberStatic
与 CLineNumberEdit
同步。这必须在控件滚动和/或内容更改时完成。幸运的是,这很简单——通过处理 EN_CHANGE
和 WM_SETTEXT
消息来实现修改,以及处理 EN_VSCROLL
和 WM_VSCROLL
实现滚动。EN_VSCROLL
负责编辑框“内部”的滚动(例如使用箭头键移动),WM_VSCROLL
在移动滑块时更新行号。
会处理 WM_SIZE
,以重新建立行号字段的大小和编辑矩形。最后,还会处理 WM_SETFONT
以重新建立编辑矩形——因为它在控件接收到此消息时会被重置。WM_SETFONT
还会使行号控件重绘。
关注点
此控件带来了一些问题。编辑控件和行号静态控件必须同步。编辑矩形必须在被销毁后立即重新建立。主要问题在于找到发送给控件的消息,以便完成这两项任务。一个模糊的区域是编辑矩形何时被销毁,后来我发现 SetWindowPlacement
也会这样做——没有解决方案,只能“改用 MoveWindow
”。
获取第一个可见行很简单——只需调用 GetFirstVisibleLine
。然而,获取最后一行比较棘手。我最初尝试使用一个非常巧妙的方法,通过混合调用 GetLine
和 GetPosFromChar
来获取两行之间的差异,但控件的内容没有以一种使其可靠的方式重新格式化。现在,我只需使用控件字体中一行的高度,以及 GetRect
父项的顶部边距。
历史
远古时代第一版
14/4 2004来自 **Keith Bowes** 的一些非常好的补充;可以使用系统颜色来绘制行号部分,以及处理起始值和最大值。
可以调用 UseSystemColours( BOOL bUseEnabled = TRUE, BOOL bUseDisabled = TRUE );
分别为启用和禁用状态使用当前系统颜色。
可以使用 SetLineNumberRange( UINT nMin, UINT nMax = 0 );
来设置起始行号和要编号的最大行数。请注意,这不是一个最小值-最大值范围,例如,最小值 100 和最大值 10 会将行号从 100、101、102 等编号到 109。
将 nMax
设置为零表示没有上限。最大值以上的行将不被编号,尽管它们仍然会显示。
来自 **Keith Bowes** 的一项新补充——处理 WM_LINESCROLL
消息。这是社区精神!
为了不甘落后,我添加了代码,可以通过单击行号来选择整行。通过注册消息和行号控件的点击处理来实现。
添加了一个小型演示程序。我意识到有些人可能只是想看一看——为此创建一个项目可能有点太过了 :-)