首先:欢迎各路英雄跟贴。
在上一贴中,特别感谢:VBAdvisor,Tiger_Zhao,zyl910(排名不分先后啊)。上回讨论的问题如下:VB老鸟:
可能是 Buffer 长度不足,修改如下,测试通过Public Function GetLineText(ByVal handle As Long, ByVal index As Long) As String
'handle 为richtextbox句柄,index为行号
Dim LineText() As Byte
Dim size As Long
Dim pos As Long
pos = SendMessage(handle, EM_LINEINDEX, index, 0)
size = SendMessage(handle, EM_LINELENGTH, pos, 0)
If size = 0 Then
GetLineText = ""
Else
ReDim LineText((size * 2 - 1) + 1)
CopyMemory LineText(0), size * 2, 2
size = SendMessage(handle, EM_GETLINE, index, LineText(0))
GetLineText = StrConv(LeftB(LineText, size), vbUnicode)
End If
End Function
经测试:是size = SendMessage(handle, EM_LINELENGTH, pos, 0)
返回的长度不够。也就是说,返回的长度是将中英文混排的行文本按英文字符进行处理的。
现在的问题是:怎样才能正确地定位光标的编号呢,怎样才能正确的统计出中英文混排的长度呢。(在richTextbox中,每一行每一列每一个字符都有编号,但很遗憾,SendMessage定位的光标位置编号都是按英文字符处理的)
您有解决办法吗?让大家一起分享的您的成功!!!
在上一贴中,特别感谢:VBAdvisor,Tiger_Zhao,zyl910(排名不分先后啊)。上回讨论的问题如下:VB老鸟:
可能是 Buffer 长度不足,修改如下,测试通过Public Function GetLineText(ByVal handle As Long, ByVal index As Long) As String
'handle 为richtextbox句柄,index为行号
Dim LineText() As Byte
Dim size As Long
Dim pos As Long
pos = SendMessage(handle, EM_LINEINDEX, index, 0)
size = SendMessage(handle, EM_LINELENGTH, pos, 0)
If size = 0 Then
GetLineText = ""
Else
ReDim LineText((size * 2 - 1) + 1)
CopyMemory LineText(0), size * 2, 2
size = SendMessage(handle, EM_GETLINE, index, LineText(0))
GetLineText = StrConv(LeftB(LineText, size), vbUnicode)
End If
End Function
经测试:是size = SendMessage(handle, EM_LINELENGTH, pos, 0)
返回的长度不够。也就是说,返回的长度是将中英文混排的行文本按英文字符进行处理的。
现在的问题是:怎样才能正确地定位光标的编号呢,怎样才能正确的统计出中英文混排的长度呢。(在richTextbox中,每一行每一列每一个字符都有编号,但很遗憾,SendMessage定位的光标位置编号都是按英文字符处理的)
您有解决办法吗?让大家一起分享的您的成功!!!
参与讨论
ReDim LineText((size * 2 - 1) + 1)
CopyMemory LineText(0), size * 2, 2
size = SendMessage(handle, EM_GETLINE, index, LineText(0))
GetLineText = StrConv(LeftB(LineText, size), vbUnicode)建议代码:
ReDim LineText((size * 2)
CopyMemory LineText(0), size * 2, size * 2
size = SendMessage(handle, EM_GETLINE, index, LineText(0))
GetLineText = LineText
另外考虑是不是sendmessageA的问题,试试替换为 sendmessageW
CopyMemory LineText(0), size * 2, size * 2
这句干什么用的??? 数据缓冲???
redim 后,数据已经缓冲了,不用在次缓冲了
把CopyMemory LineText(0), size * 2, size * 2 删了吧
谢谢您的参与。VB老鸟就是提出的解决方法。
现在的问题是:在richTextBox中中英文混排时该怎样定位光标所在字符的编号。
Public Function GetLineTextA(ByVal handle As Long, ByVal index As Long) As String
其他都一样
GetLineTextA = LeftB(LineText, size)
End Functionpublic function ColA2W(byval handle as long, byval row as long, byval colA as long) as long
'取得 Ansi 字符串,取得光标前的 colA 个 Ansi 字符,转化为 Unicode,统计长度
'至于列号和字符数是否存在 ±1 的问题,自己测一下再完善一下代码
ColA2W = len(strconv(leftB(getlinetexta(handle, row), col),vbunicode))
end sub
Dim LineIndex As Long
Dim SelRange As CHARRANGE
Dim TempStr As String
Dim TempArray() As Byte
Dim CurRow As Long
Dim CurPos As POINTAPI TempArray = StrConv(TextControl.Text, vbFromUnicode)
Call SendMessage(TextControl.hWnd, EM_EXGETSEL, 0, SelRange)
CurRow = SendMessage(TextControl.hWnd, EM_LINEFROMCHAR, SelRange.cpMin, 0)
LineIndex = SendMessage(TextControl.hWnd, EM_LINEINDEX, CurRow, 0)
If SelRange.cpMin = LineIndex Then
GetCurPos.x = 1
Else
TempStr = String(SelRange.cpMin - LineIndex, 13)
CopyMemory ByVal StrPtr(TempStr), ByVal StrPtr(TempArray) + LineIndex, SelRange.cpMin - LineIndex
TempArray = TempStr
ReDim Preserve TempArray(SelRange.cpMin - LineIndex - 1)
TempStr = StrConv(TempArray, vbUnicode)
GetCurPos.x = Len(TempStr) + 1
End If
GetCurPos.y = CurRow + 1
End FunctionPrivate Sub RTB_Click()
Debug.Print "y=" & GetCurPos(RTB).y
Debug.Print "x=" & GetCurPos(RTB).x
End Sub
中英文混排时,还是按英文方式进行定位的
http://community.csdn.net/Expert/TopicView3.asp?id=5648720
http://community.csdn.net/Expert/TopicView3.asp?id=5646744重申:
(不考虑Win9x,因为更复杂)对于XP英文/中文系统,如果你的Non-Unicode设定是English, SendMessage 根本就不可能得到中文.但如果Non-Unicode设定是Chinese (PRC),上面的编码可以取得中文。原因在于SendMessage有经过Unicode到ANSI/DBCS的几次转换,造成Unicode的丢失。我挣扎多年都没成功!!!不信你们将你的non-Unicode设定为English!!!
Control Panel --> Language and Region options --> Advance Tab ---> English as non-Unicode'RichEdit GetLine Function From VBAdvisor
Public Type TEXTRANGE
chrg As CHARRANGE
lpstrText As Long
End TypePublic Function GetLineText(Byval hWnd as long,ByVal LineNum As Long) As String
Dim LineCount As Long
Dim lc As Long, j As Long
Dim charFrom As Long
Dim charEnd As Long
Dim CR As CHARRANGE
Dim TR As TEXTRANGELineCount = SendMessageLong(hWnd, EM_GETLINECOUNT, ByVal 0&, ByVal 0&)
If LineNum > LineCount Then
GetLineText = vbNullString
Exit Function
End If
charFrom = SendMessageLong(hWnd, EM_LINEINDEX, LineNum, ByVal 0&)
lc = SendMessageLong(hWnd, EM_LINELENGTH, ByVal charFrom, ByVal 0&)
If lc = 0 Then
GetLineText = vbNullString
Exit Function
End IfGetLineText = TextInRange(charFrom, charFrom + lc)End FunctionPublic sub TextInRange(Byval hWnd as long,ByVal lStart As Long, ByVal lEnd As Long)Dim TR As TEXTRANGE
Dim sText As String
Dim lR As Long
Dim B() As ByteTR.chrg.cpMin = lStart
TR.chrg.cpMax = lEnd' VB won't do the terminating null for you!
sText = String$(lEnd - lStart + 1, 0)
B = sText
ReDim Preserve B(0 To (lEnd - lStart + 1)) As Byte
TR.lpstrText = VarPtr(B(0))lR = SendMessageLong(hWnd, EM_GETTEXTRANGE, 0, VarPtr(TR))If (lR > 0) Then
' lstrlen assumes that lpString is a NULL-terminated string !!!
CopyMemory ByVal sText, ByVal TR.lpstrText, lR
TextInRange = Left$(sText, lR)
End IfEnd Sub'TextBox GetLine Function From VBAdvisor
Public Function GetLine(Byval hWnd As long,ByVal whichLine As Long) As StringDim nLen As Long, bArr() As Byte, bArr2() As Byte, lReturn As LonglReturn = SendMessage(hWnd , EM_LINEINDEX, whichLine, ByVal 0&)nLen = SendMessage(hWnd , EM_LINELENGTH, lReturn, ByVal 0&)If nLen > 0 Then
ReDim bArr(2 * nLen + 1) As Byte, bArr2(2 * nLen - 1) As Byte
Call CopyMemory(bArr(0), 2 * nLen, 2)
Call SendMessage(hWnd , EM_GETLINE, whichLine, bArr(0))
Call CopyMemory(bArr2(0), bArr(0), 2 * nLen)GetLine = String$(UBound(bArr2) + 1, vbNullChar)
CopyMemory ByVal GetLineString, bArr2(0), UBound(bArr) + 1Else
GetLine = vbNullString
End IfEnd Function
Private Declare Function SendMessageLongA Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As LongPrivate Declare Function SendMessageLongW Lib "user32" Alias "SendMessageW" (ByVal hwnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As LongPrivate Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hwnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongPrivate Declare Function IsWindowUnicode Lib "user32.dll" (ByVal hwnd As Long) As LongPublic Property Get GetTextFromLine(Optional ByVal LineIndex As Long = -1&) As String' returns the text for an entire line
' Passing -1 will retrieve the value for the line having the cursor (SelStart)
Dim lValue As Long, arrString() As Byte
Const EM_GETLINE As Long = &HC4
If LineIndex = -1 Then LineIndex = CurrentLine
lValue = SendMessage(m_hWndEB, EM_LINEINDEX, LineIndex, 0&)
If lValue > -1 Then
lValue = SendMessage(m_hWndEB, EM_LINELENGTH, lValue, 0&)
If lValue Then
If IsWindowUnicode(m_hWndEB) Then
GetTextFromLine = String$(lValue, 0)
CopyMemory ByVal StrPtr(GetTextFromLine), lValue, 4&
SendMessageLongW m_hWndEB, EM_GETLINE, LineIndex, StrPtr(GetTextFromLine)
If lValue = 1 Then GetTextFromLine = Left$(GetTextFromLine, 1)
Else
If lValue < 4 Then
ReDim arrString(0 To 3)
Else
ReDim arrString(0 To lValue - 1)
End If
CopyMemory arrString(0), lValue, 4&
SendMessageLongA m_hWndEB, EM_GETLINE, LineIndex, VarPtr(arrString(0))
If lValue < 4 Then ReDim Preserve arrString(0 To lValue - 1)
GetTextFromLine = StrConv(arrString, vbUnicode)
End If
End If
End If
End Property
VBScript code Public Property Get CurrentLine() As Long CurrentLine = LineForCharacterIndex(SelStart)End PropertyPublic Property Get LineForCharacterIndex(lindex As Long) As Long LineForCharacterIndex = SendMessageLongA(m_hWndEB, EM_LINEFROMCHAR, lindex, 0)End PropertyPublic Property Get SelStart() As LongDim lEnd As Long
Dim lStart As Long If m_hWndEB Then
SendMessageLongA m_hWndEB, EM_GETSEL, VarPtr(SelStart), VarPtr(lEnd)
End IfEnd Property
'网上流行的所谓支持中文的方法:
'说明:在locale ID为英文(1033)时不能返回中文,locale ID为2052时才可以返回中文,因为调用SendMessage时候,Windows进行了Unicode->ANSI的转换,导致Unicode的破坏)
Public Property Get GetLine(ByVal whichLine As Long) As String
Dim nLen As Long, bArr() As Byte, bArr2() As Byte, lReturn As Long
lReturn = SendMessage(m_hWndEB, EM_LINEINDEX, whichLine, ByVal 0&)
nLen = SendMessage(m_hWndEB, EM_LINELENGTH, lReturn, ByVal 0&)
If nLen > 0 Then
ReDim bArr(2 * nLen + 1) As Byte, bArr2(2 * nLen - 1) As Byte
Call CopyMemory(bArr(0), 2 * nLen, 2) '准备一个存储器,传递消息之前先在存储器的前两个字节填入存储器的长度Call SendMessage(m_hWndEB, EM_GETLINE, whichLine, bArr(0))
Call CopyMemory(bArr2(0), bArr(0), 2 * nLen)
GetLine = String$(UBound(bArr2) + 1, vbNullChar)
CopyMemory ByVal GetLine, bArr2(0), UBound(bArr) + 1
Else
GetLine = vbNullString
End If
End Property