鄙人有强迫症,无论是用MFC还是.Net都特别不理解为什么自带的TextBox组件是垂直靠顶部对齐的,一定会想对应的解决方案让文字垂直居中。
现在在使用VisualFreebasic,其实使用的就是win32的API,所以TextBox也会存在同样的问题。
一般我都不会花心思去调整TextBox,一般都会使用支持设置边距的RichEdit来重绘一下非客户区。原则上我又不会去改作者的源码,一般会把组件复制一份,例如这里我会把组件的RichEdit复制一份,改成RichEditEx来实现。
奇怪的事情发生了,创建一个新项目,拽一个RichEditEx到窗体,预览是好的,但是运行之后控件进去之后窗体是空的。当我再拖一个RichEdit进去,编译,更奇怪的事情发生了,两个组件都赫然的显示在窗体上。
回想了一下,我记得MFC加载RichEdit都需要调用AfxInitRichEdit(),但是我全盘搜索并没有发现段代码。VisualFreebasic其实只是一个fbc的代码生成器,我们把编辑器的删除中间代码的选项取消:
然后创建两个项目TestA和TestB,前者拉原版的组件,后者拉扩展的组件。
对比CODEGEN_TestA_MAIN.bas发现会多一行代码
LoadLibraryW("MSFTEDIT.DLL")
也就是说,如果系统检测生成的代码中调用了原版的RichEdit就会自动的在生成的代码中加入加载RichEdit的dll,反之就不加载。通过进一步的测试,只要类文件的名字包含了\ClsRichEdit.inc就会加入LoadLibraryW("MSFTEDIT.DLL")代码。
剩下的问题就很简单了,创建一个空窗体,把原版的RichEdit拽一份上去,扩展的RichEditEx才能正常的使用。
下一步要实现实现垂直居中:
一、把RichEdit设置为单行模式
二、程序默认字体是微软雅黑,通过yGDI设置Font为10的高度,然后用(RichEditEx的高度-字体高度) / 2作为Top,编辑器自然就垂直居中。
三、Left一般设置为字体大小的五分之一
Sub Class_RichEditEx.Vertical()
Dim rc As Rect
Dim gg As yGDI = This.hWnd
gg.Font, 10
Dim h As Integer = gg.GetTextHeight("汉")
SendMessage(This.hWnd, EM_GETRECT, 0, Varptr(rc))
rc.top = (rc.bottom - rc.top - h) / 2 + 3 * gg.Dpi
rc.bottom = rc.top + h
rc.Left = h / 5
SendMessage(This.hWnd, EM_SETRECT, 0, Varptr(rc))
End Sub
运行之后就是这个效果,会根据组件的高度和字体大小自动的调整
默认边框很难看,通过重绘NCPaint(非客户区),下面讲一下重绘边框调整颜色和宽度
网上非客户区的重绘教程比较少,慢慢摸索实现了
Function Class_RichEditEx.MsgProcedure(vhWnd As .hWnd ,wMsg As UInteger ,nwParam As wParam ,nlParam As lParam) As LResult
Dim fp As FormControlsPro_TYPE Ptr
Select Case wMsg
Case WM_NCPAINT
Dim As Rect rc, yrc
GetWindowRect(hWndControl, @rc)
Dim gg As yGDI = yGDI(hWndControl, BGR(255, 255, 255), 0, 0, 0, 0, 0, 1)
gg.Pen 1 ,BGR(230 ,230 ,230)
gg.DrawCircleFrame(0, 0, rc.Right - rc.Left, rc.bottom - rc.top, 8, 8)
ExcludeClipRect gg.m_nDC, rc.Left, rc.top, rc.Right, rc.bottom
Return True
End Select
Function = 0
End Function
'在CONTROL_CODExx后面增加
CONTROL_CODExx &= " This." & clName & ".Vertical()" & vbCrLf
'在Dim LeaveHoverI As Long前面加入
'事件处理 ------------------------------
'增加
Dim CALL_CONTROL_CUSTOM As String = " If IDC = " & IDC & " Then ' " & clName & vbCrLf
CALL_CONTROL_CUSTOM &= " " & Form_clName & "." & clName
CALL_CONTROL_CUSTOM &= ".hWnd=hWndControl" & vbCrLf
CALL_CONTROL_CUSTOM &= " tLResult = " & Form_clName & "." & clName
CALL_CONTROL_CUSTOM &= ".MsgProcedure(hWndControl,wMsg, wParam, lParam)" & vbCrLf
CALL_CONTROL_CUSTOM &= " If tLResult Then Return tLResult" & vbCrLf
CALL_CONTROL_CUSTOM &= " End If" & vbCrLf
Insert_code(ProWinCode ,"'[CALL_CONTROL_CUSTOM]" ,CALL_CONTROL_CUSTOM)
Dim LeaveHoverI As Long
至此完成,效果如下