Do While Not rs.EOF Text2.Text = Text2.Text & rs!Chapter & ":" & rs!verse & " " & rs!body & vbCrLf
rs.MoveNext
Loop
Am declaring Sendmessage API and Constants as follows:
Code:
Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal HWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, lParam As Any) As LongConst EM_LINEFROMCHAR = &HC9
Private Const EM_GETLINE = &HC4
Private Const EM_LINEINDEX = &HBB
Private Const EM_LINELENGTH = &HC1
Here is first sendmessage call to get selected line number (with Mouse):
Code:
Public Function TB_LineIndex(ByRef sTextBox As TextBox) As Long
Dim lngRet As Long
'
lngRet = SendMessage(sTextBox.HWnd, EM_LINEFROMCHAR, -1, ByVal 0&)
TB_LineIndex = lngRet + 1
End Function
Here is second sendmessage call to get actual text of the line:
Code:
Public Function GetTextBoxLine(objTB As TextBox, ByVal LineNum As Integer) As String Dim lngRet As Long
Dim lngLen As Long
Dim lngFirstCharPos As Long
Dim lngHwnd As Long
Dim bytBuffer() As Byte
Dim strAns As String
If LineNum < 0 Then Exit Function
If objTB.MultiLine = False Then
GetTextBoxLine = objTB.Text
Else
lngHwnd = objTB.HWnd
lngFirstCharPos = SendMessage(lngHwnd, EM_LINEINDEX, LineNum - 1, 0&)
lngLen = SendMessage(lngHwnd, EM_LINELENGTH, lngFirstCharPos, 0&)
ReDim bytBuffer(lngLen) As Byte
bytBuffer(0) = lngLen
lngRet = SendMessage(lngHwnd, EM_GETLINE, LineNum - 1, bytBuffer(0))
If lngRet Then strAns = Left$(StrConv(bytBuffer, vbUnicode), lngLen)
GetTextBoxLine = strAns
End If
End Function
Now, here is the code I am using to try to find the vbCrLf in the selected line of the multiline textbox (with mouse):
Code:
Private Sub Text2_Click()
Dim myLine As Integer
myLine = TB_LineIndex(Text2)
Dim sLine As String
sLine = GetTextBoxLine(Text2, myLine)
If InStr(1, sLine, vbCrLf) > 0 Then
Debug.Print sLine
End If
End Sub
Although sLine IS the selected line of the textbox (when shown outside of if-then-end), there is no vbCrLf in it (the InStr call is always zero)..
What I want to find is the location of that vbCrLf I added when I populated the textbox; but first, just the test above to see if in exists in the line selected by Mouse.
For multiline edit controls, the return value is the length, in TCHARs, of the line specified by the wParam parameter. For ANSI text, this is the number of bytes; for Unicode text, this is the number of characters. It does not include the carriage-return character at the end of the line.
If you need to know if a vbCrLf follows the end of the returned line, you could probably use VB's Text2.SelStart value:
Code:
' following needs to be tested well..
Private Sub Text2_Click()
Dim myLine As Integer
myLine = TB_LineIndex(Text2)
Dim sLine As String
sLine = GetTextBoxLine(Text2, myLine)
Dim lRawPos As Long, lStart As Long, lSize As Long
lSize = Len(sLine)
lStart = Text2.SelStart - lSize
If lStart < 1 Then lStart = 1
lRawPos = InStr(lStart, Text2.Text, sLine)
If Mid$(Text2.Text, lRawPos + lSize, 2) = vbCrLf Then
Debug.Print "sLine does have a carriage return at end of line in source text"
End If
End Sub
Edited: Also note that "bytBuffer(0) = lngLen" will error if the line consists of more than 255 characters. The 1st two bytes of that buffer are used to define the size of the buffer, not just the 1st byte.
Another gotcha. This line:
Code:
If lngRet Then strAns = Left$(StrConv(bytBuffer, vbUnicode), lngLen)
Should read as shown, no guarantee that lngRet & lngLen will be identical (though they should be)
Code:
If lngRet Then strAns = Left$(StrConv(bytBuffer, vbUnicode), lngRet)
Last edited by LaVolpe; May 23rd, 2018 at 07:45 PM.
Insomnia is just a byproduct of, "It can't be done"
Ah, very good, Fox.
Didn't catch the lngRet either...thanks.
So, here is my dilemma... I have a multiline textbox with Bible verses that wrap...some take up more than one line (several, do, as a matter of a fact.). My goal is to click on a "LINE" (well, actually, a VERSE---so, if a verse took up, say, three lines, I'd want to 'select' that line, but recognize it to be part of a verse). I thought if I were to find vbCrLf's, I could finagle it to produce what I wanted. Essentially, each 'verse' will begin with a chapter and verse number (like "3:23 ", followed by the actual verse (which will probably take up more than one line in the ML textbox.)). I guess I could search any previous lines until I found one that began with the chapter and verse number, and then go back to my database with a query to display the entire verse in a separate textbox. Guess I try that approach.
Thanks for the correction and the MSDN info...
In summary: I simply want to display in another textbox ONE of the verses a user clicks on (no matter what line of that verse he/she selects)...the ML textbox (text2) in my program (I know, a better naming convention would be wise!!!, but then, I am the only 'developer') contains at any one given time, an entire chapter in a Bible book. Maybe the use of an RTB or even a Grid would have been better choices instead of the ML textbox, but that is what I got, so thought I'd muddle through.
Sam, look at my edited reply. I included a possible fix if I understood correctly
The idea was to get the line from textbox via API as you are doing. Then locate that line in the actual source text, overlap the API returned line and see if a carriage return immediately follows.
Insomnia is just a byproduct of, "It can't be done"
Yeah....didn't even read your 'fix' with selStart. But, already did it my way...simply looped backwards until I found the line with the 'chapter and verse' (e.g. 2:23)...that is all I really needed...simple call now to the DB to pull that info the other textbox.
'Twas easy...as I am sure selStart would have been as well.
Marking as resolved...sometimes I just need to bounce things off folks to figure it out...but your input is ALWAYS spot on...thanks
That's pretty much what my solution was. SelStart was a starting point to go find the target string. And also it's a more solid position to begin looking should the API-returned line exist more than once in your overall text.
Insomnia is just a byproduct of, "It can't be done"
Too bad you can't use a RichTextBox or InkEdit control for this. It all becomes pretty simple then:
Code:
Option Explicit
Private Const WM_USER As Long = &H400&
Private Const EM_GETOLEINTERFACE As Long = WM_USER + 60&
Private Const EM_SETEDITSTYLEEX As Long = WM_USER + 275&
Private Const SES_EX_NOACETATESELECTION As Long = &H100000
Private Declare Function SendMessage Lib "user32" Alias "SendMessageW" ( _
ByVal hWnd As Long, _
ByVal wMsg As Long, _
ByVal wParam As Long, _
ByVal lParam As Long) As Long
Private Const CP_ACP = 0 'Default ANSI codepage of the process.
Private TextDocument As tom.ITextDocument
Private Sub Form_Initialize()
Dim IUnknown As stdole.IUnknown
With InkEdit1
SendMessage .hWnd, _
EM_SETEDITSTYLEEX, _
SES_EX_NOACETATESELECTION, _
SES_EX_NOACETATESELECTION
SendMessage .hWnd, EM_GETOLEINTERFACE, 0, VarPtr(IUnknown)
Set TextDocument = IUnknown
End With
TextDocument.Open "KJB-Chap-1.rtf", tomRTF Or tomReadOnly, CP_ACP
End Sub
Private Sub Form_Resize()
If WindowState <> vbMinimized Then
With Text1
.Move 0, ScaleHeight - .Height, ScaleWidth
InkEdit1.Move 0, 0, ScaleWidth, .Top
End With
End If
End Sub
Private Sub InkEdit1_Click()
With TextDocument.Selection
.MoveStart tomParagraph, -1
.MoveEnd tomParagraph, 1
Text1.Text = .Text
End With
End Sub
Note that the only difference with an InkEdit control is that I am setting the SES_EX_NOACETATESELECTION extended style so that selected text highlighting matches that of an intrinsic TextBox and other controls. Without that you'd see the system "Acetate" selection which is typically a lighter translucent blue shade.
With a RichTextBox you have the creakier old RichEdit 1.0 inside, where selected text is always highlighted using color complementing.
I have no idea why some of the lines in the sample text contain paragraph marker (pilcrow) characters: "ΒΆ" in them.
This was just some sample text I chopped off the start of a Bible RTF I have in my test data folder. The original source had those funky symbols in it. They seem to be setting off quotes or something.
I got bored quickly though and never did manage to weed a definition out of the guy's purple prose. Maybe somebody else will have more patience and better luck.
Yes...I coulda (and probably shoulda) used an RTB....But I just threw this together really quickly (it's for my sole use, BTW). I wanted a program to display/search/etc in the OT Apocrypha...I already have a program I created for several versions of the Christian Bible (which gets my use daily).
I'll keep this in mind (the RTB), however, if I decide on some other similar project.