Results 1 to 19 of 19

Thread: Cool Textbox Class

  1. #1

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530

    Cool Textbox Class

    Lots of people always ask how to make a textbox only take numeric data /uppercase /lowercase / decimal place /prevent pasting etc.

    Well here is the start of a class to do all the work for you. Full source is included.

    I just put it together over the last hour or so, so there are probably a few bugs.

    I am posting it for anyone to use and/or comment on for suggested improvements.

    [Edit: Deleted attachment as class improved and posted later in this thread]
    Last edited by Nucleus; Aug 30th, 2001 at 12:16 AM.

  2. #2
    Hyperactive Member AAG's Avatar
    Join Date
    Aug 2000
    Location
    United States
    Posts
    411
    thats a nice class and works great, but why do all that work when you can simply do it through 2 api calls ?? if you would like i will create u a simple project using the API to do exactly what you have done. Just putting my 2 cents.
    This Business Is Binary. Your a 1 or a 0. Alive or Dead. (AntiTrust)

  3. #3
    PowerPoster beachbum's Avatar
    Join Date
    Jul 2001
    Location
    Wollongong, NSW, Australia
    Posts
    2,274
    Brings the teacher an apple but sits up the back and chews gum

    Absolutely no offence to u Nucleus and i know u are doing for ppl that ask, but geesh i wonder why ppl insist on annoying the hell out of their users by doing such strange stuff as stopping them entering text etc as they are typing. Have they ever tested such ideas on users and if so have they worn protective headwear?

    Anyhow, nice job for those ppl.

    Regards
    Stuart
    Stuart Laidlaw
    Brightspark Financial Software
    http://www.gstsmartbook.com

  4. #4
    gaffa
    Guest
    Beachbum,

    An interesting question - do you lock off a text box to allow the user to enter only valid data, or let them enter anything, then fix it up later ("fix it in post" in film-making parlance)?

    I guess it all depends on the target audience, but I'd be interersted to hear what people have to say and their justifications for it...

    - gaffa

  5. #5
    PowerPoster beachbum's Avatar
    Join Date
    Jul 2001
    Location
    Wollongong, NSW, Australia
    Posts
    2,274
    Hi Gaffa
    I believe in (lol sounds biblical) letting users type whatever they want and then having the program do its damndest to fix it up if they have entered invalid data. eg if the user is supposed to type a date as dd/mm/yy and they actually do dd-mm-yy or ddmmyy then why the hell cant the program just work it out instead of annoying the user with an error msg or annoying them by restricting the use of the "-" key or whatever. Just my opinion.
    Regards
    Stuart
    Stuart Laidlaw
    Brightspark Financial Software
    http://www.gstsmartbook.com

  6. #6
    gaffa
    Guest
    I've always been of the other variety - restrict the entry so they can't screw it up in the first place (well, restrict within reason anyway - don't let the enter alpha when a number is requried and the like.) The key is making the restriction non-intrusive - no message boxes or anything cos they are just a pain in the rear.

    - gaffa

  7. #7

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530
    Originally posted by AAG
    thats a nice class and works great, but why do all that work when you can simply do it through 2 api calls ?? if you would like i will create u a simple project using the API to do exactly what you have done. Just putting my 2 cents.
    AAG, I would be interested in seeing the app that provides the same level of functionality with 2 api calls. Can you post it?

    Beachbum/Gaffa I guess I used a combination of both approaches. For example if the textbox only accepts uppercase text, then the class will automatically change lowercase data to uppercase. For things like disabling paste I don't think there is a way around just disabling it flat out.

    Then there is the middle ground, if a textbox should accept numeric data, should I build intelligence to convert "one" to 1? This would take a lot of extra code. In short where it was relatively efficient to implement intelligence into the class I did it, where it would take reams of extra code I stayed away.

    If I was making a very expensive product which didn't require distribution over the net and and can therefore be a little more bloated, I guess the more intelligence you build into the app the better.

    I didn't include the ability to deal with dates as the Masked Edit Box is quite capable of doing the job.

    BTW Beachbum, I hoped you noticed the messagebox was optional .

  8. #8
    PowerPoster beachbum's Avatar
    Join Date
    Jul 2001
    Location
    Wollongong, NSW, Australia
    Posts
    2,274
    Hi Nucleus
    Call me anally retentive () but i never download anything from forums so i didnt actually see ur example.. i have seen ur code on prev posts about this topic tho.

    In regard to intelligent apps... it doesnt take much and ur example of one becoming 1 is prob outside the range of expected entries from a user. I use a coverall *formatting* module that handles all formatting recovery regardless of the calling textbox etc. Say certain textboxes need to be numerical, certain are dates etc. I only need to call the same functions from each of these boxes. And by using control arrays etc this is cut down even further.

    Also, remember that it takes more effort and code to do it the *simpler* way using msg boxes or keypress handling etc.

    And regardless of the coding effort the main thing is useability. If u use the Keypress method as per this eg, u are assuming that the user is looking at the screen as they type... u are assuming that they understand the reason that some keys work and some dont. I think that software in general asks too much of users and is not adaptive enough. This is moreso becos of design by the developer than becos of any failing in the ability of computers to handle certain events.

    aargh .. am too tired and rambling ...

    I would recommend that any readers of this thread take a look at design principles on http://www.iarchitect.com and also on http://www.cooper.com
    Regards
    Stuart
    Stuart Laidlaw
    Brightspark Financial Software
    http://www.gstsmartbook.com

  9. #9

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530
    BeachBum, I am looking through those sites, there is some good stuff there.

  10. #10
    Tygur
    Guest
    Well, here comes the criticism


    I think you want to change this line:
    Case Is < 31 ' control characters
    ..to this one:
    Case Is <= 31 ' control characters
    ..in the KeyPress event in the class. It probably doesn't matter, tho.


    The disable pasting code still allows the user to right-click on the textbox and click Paste from there. It also allows Shift+Insert to be used for pasting. You might want to work on that.


    You might also want to put the ColourForInvalidEntry property in as an actual property instead of a public event, so you can find out if it was actually set (using a boolean variable). If it wasn't set, it's probably safe to assume that the programmer doesn't want the textbox to change color when something goes wrong. YOu can even add a ChangeColor (or similarly named) property to set whether the textbox would change color. Of course, setting the ColourForInvalidEntry would automatically set the ChangeColor property to true.


    Also, about the ColourForInvalidEntry property, it might be a good idea if you let the programmer turn it black if he/she desires to do so. I'm referring to this line in the Validate event in the class:
    If ColourForInvalidEntry = 0 Then ColourForInvalidEntry = vbRed


    This next thing is just a suggestion. It doesn't really matter either way. Maybe you should put in a property (or public variable) for the text and title in the error message that shows if the contents of the textbox are invalid. If the property or properties don't get set, just use the default, which would be what you have right now.


    I looked back therough the code and I found a problem with the backcolor code. If the backcolor of the textbox gets set somehwere else, the code in the class module doesn't realize it. So when it tries to set the backcolor to what it was before it shaded the textbox because of an error, it sets it to what it originally was. This might not make sense, so I'll try again. When the textbox gets focus for the first time (and only on the first time it gets focus), the class module records the color. Then when the user puts something invalid and the Validate event catches it, it changes the backcolor to red (or whatever it's supposed to change it to). Then when the user types his/her first character to fix the problem, it changes the backcolor back to the color it saved. So what happens if the programmer decides to change the backcolor of the control sometime between the very first time the textbox gets focus and the time the user puts in something invalid? The programmer's change gets lost and the textbox gets the backcolor set back to what it originally had.

    I suggest you save the backcolor of the textbox right before you change its color. Then you can set it back to that saved value when you change it back.


    Well, after seeing how much I just typed, I'm going to stop now...

  11. #11

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530

    Bigger and Better

    I have taken the comments from Beachbum and Tygur and incorporated them into this new version of the class, as well as adding a few extra properties/features of my own.

    Beachbum, I now have a switch to turn key-trapping on or off. If you leave key-trapping off, then the user can enter/paste anything they want and the program automatically fixes up the data. For example if the textbox accepts only numerical data, all non-numerical characters are deleted. If the textbox accepts only uppercase text and the user enters lowercase text, the text is automatically converted to uppercase without user intervention. No need for a message box at all this time, as the code handles all problems automatically. I agree with you that this probably suits the user more, although they may get confused when the app automatically changes something, they might think "why is the app changing that, that is not what I typed in?"

    The advantage of doing it as a class, is that I can put it on a server and all developers can use it, plus the code is in one place and easy to maintain.

    I'll post the class directly below, so you can see the code this time.

    Tygur Well thanks for the long reply! I have fixed the case Is < 32 problem. I thought about the pasting issue and decided that I do not like applications that stop me from pasting in data. So I changed the class to allow users to paste in any data, if the data pasted is invalid, the class automatically fixes the data in the validate event. This way users are not restricted from pasting, but invalid data is filtered out.

    Following BB's comments I have added more intelligence to the class so that it automatically fixes invalid data for the user and no longer needs a message box or to change the background colour.

    In a class Module called CTxtBxN
    VB Code:
    1. Option Explicit
    2.  
    3. Public WithEvents Textbox As Textbox
    4.  
    5. Public AllowSpaces As Boolean
    6. Public AllowUppercase As Boolean
    7. Public AllowLowercase As Boolean
    8. Public AllowSymbols As Boolean
    9. Public AllowNumeric As Boolean
    10. Public TrapKeyPresses As Boolean
    11. Public SelectOnFocus As Boolean
    12.  
    13. Private m_dp As Long
    14. Private m_ApplyMax As Boolean
    15. Private m_ApplyMin As Boolean
    16. Private m_Max As Double
    17. Private m_Min As Double
    18. Private m_NumOnly As Boolean
    19.  
    20. Public Property Let Max(MaxValue As Double)
    21.     m_ApplyMax = True
    22.     m_Max = MaxValue
    23. End Property
    24.  
    25. Public Property Let Min(MinValue As Double)
    26.     m_ApplyMin = True
    27.     m_Min = MinValue
    28. End Property
    29.  
    30. Public Property Let MaxDecimalPlaces(dp As Long)
    31.     m_dp = Abs(dp)
    32. End Property
    33.  
    34. Private Sub Textbox_GotFocus()
    35.  If SelectOnFocus Then
    36.     Textbox.SelStart = 0
    37.     Textbox.SelLength = Len(Textbox.Text)
    38.  End If
    39.  
    40.  If m_dp Or m_ApplyMin Or m_ApplyMax Then
    41.     'can't enforce these properties without restricting to a number
    42.     AllowNumeric = True
    43.     AllowSpaces = False
    44.     AllowUppercase = False
    45.     AllowLowercase = False
    46.     AllowSymbols = False
    47.  End If
    48.  m_NumOnly = AllowNumeric And Not AllowSpaces And Not AllowUppercase And Not AllowLowercase And Not AllowSymbols
    49. End Sub
    50.  
    51. Private Sub Textbox_KeyPress(KeyAscii As Integer)
    52. Dim pos&
    53.  
    54. If TrapKeyPresses Then
    55.  Select Case KeyAscii
    56.     Case Is < 32 ' control characters
    57.     Case 32 ' space
    58.         If Not AllowSpaces Then KeyAscii = 0
    59.     Case 46 ' decimal place
    60.         If AllowNumeric Then
    61.             If m_dp Then
    62.                 If Textbox.Text Like "*.*" Then KeyAscii = 0
    63.             Else
    64.                 If m_NumOnly Then KeyAscii = 0
    65.             End If
    66.         End If
    67.     Case 48 To 57 ' number
    68.         If Not AllowNumeric Then
    69.             KeyAscii = 0
    70.         Else
    71.             If m_dp Then
    72.                 pos = InStr(1, Textbox.Text, ".")
    73.                 If pos Then If Len(Textbox.Text) - pos + 1 > m_dp Then KeyAscii = 0
    74.             End If
    75.         End If
    76.     Case 65 To 90 ' uppercase alpha
    77.         If Not AllowUppercase Then
    78.             If AllowLowercase Then
    79.                 KeyAscii = KeyAscii + 32
    80.             Else
    81.                 KeyAscii = 0
    82.             End If
    83.         End If
    84.     Case 97 To 122 ' lowercase alpha
    85.         If Not AllowLowercase Then
    86.             If AllowUppercase Then
    87.                 KeyAscii = KeyAscii - 32
    88.             Else
    89.                 KeyAscii = 0
    90.             End If
    91.         End If
    92.     Case Else
    93.         If Not AllowSymbols Then KeyAscii = 0
    94.  End Select
    95. End If
    96. End Sub
    97.  
    98. Private Sub Textbox_Validate(Cancel As Boolean)
    99. Dim ba() As Byte, i&, s$, dp&, pos&
    100.    
    101.     ba = Textbox.Text
    102.     For i = 0 To UBound(ba) Step 2
    103.      
    104.       Select Case ba(i)
    105.         Case Is < 32 'control characters
    106.         Case 32 ' space
    107.             If Not AllowSpaces Then ba(i) = 1
    108.         Case 46 ' decimal place
    109.             If AllowNumeric Then
    110.                 If m_dp Then
    111.                     dp = dp + 1
    112.                     If dp > 1 Then ba(i) = 1
    113.                 Else
    114.                     If m_NumOnly Then ba(i) = 1
    115.                 End If
    116.             End If
    117.         Case 48 To 57 'number
    118.             If Not AllowNumeric Then ba(i) = 1
    119.         Case 65 To 90 'uppercase alpha
    120.             If Not AllowUppercase Then
    121.                 If AllowLowercase Then
    122.                     ba(i) = ba(i) + 32
    123.                 Else
    124.                     ba(i) = 1
    125.                 End If
    126.             End If
    127.         Case 97 To 122 'lowercase alpha
    128.             If Not AllowLowercase Then
    129.                 If AllowUppercase Then
    130.                     ba(i) = ba(i) - 32
    131.                 Else
    132.                     ba(i) = 1
    133.                 End If
    134.             End If
    135.         Case Else
    136.             If Not AllowSymbols Then ba(i) = 1
    137.       End Select
    138.      
    139.     Next i
    140.    
    141.     If Len(Textbox.Text) Then Textbox.Text = ba
    142.     Textbox.Text = Replace(Textbox.Text, Chr(1), "")
    143.     If m_ApplyMax And Len(Textbox.Text) Then If Textbox.Text > m_Max Then Textbox.Text = m_Max
    144.     If m_ApplyMin And Len(Textbox.Text) Then If Textbox.Text < m_Min Then Textbox.Text = m_Min
    145.     If m_dp Then
    146.         pos = InStr(1, Textbox.Text, ".")
    147.         If pos Then Textbox.Text = Left$(Textbox.Text, pos + m_dp)
    148.     End If
    149.    
    150. End Sub


    Example Usage add 2 textboxes to a form then add this code:
    VB Code:
    1. Option Explicit
    2.  
    3. Dim Amount As CTxtBxN
    4. Dim NameEntry As CTxtBxN
    5.  
    6. Private Sub Form_Load()
    7. Set Amount = New CTxtBxN
    8. Set NameEntry = New CTxtBxN
    9.  
    10. Set Amount.Textbox = Text1
    11. 'all available properties in addition to a standard textbox
    12. Amount.SelectOnFocus = True
    13. Amount.AllowSpaces = False
    14. Amount.AllowUppercase = False
    15. Amount.AllowLowercase = False
    16. Amount.AllowSymbols = False
    17. Amount.TrapKeyPresses = False
    18. Amount.AllowNumeric = True
    19. Amount.Max = 100
    20. Amount.MaxDecimalPlaces = 2
    21. Amount.Min = 0
    22.  
    23. Set NameEntry.Textbox = Text2
    24. 'in reality only need to turn on those we need
    25. ' this case only allow uppercase text
    26. NameEntry.AllowUppercase = True
    27.  
    28. End Sub
    Last edited by Nucleus; Aug 21st, 2001 at 09:58 PM.

  12. #12
    Fanatic Member Kaverin's Avatar
    Join Date
    Oct 2000
    Posts
    930
    Someone brought up the API way to change the numbers only thing (I read all that once and didn't want to read it again, so I apologize for not giving a name), but this is how it's done. It's not as good for all cases though, as this way invalidates everything but numbers (it allows backspace and delete, but not periods, which some people may want for decimals). I took these out of a class I had myself which is somewhat like Nucleus's, but is more for giving a textbox some of the props that exist for edit controls, but aren't exposed with VB.
    VB Code:
    1. 'this takes a reference to a textbox just like Nucleus's class did
    2. 'blnClassBound tells whether or not a textbox reference has been set yet
    3. 'in my clsTextBoxEx.SourceTextBox property set procedure
    4. 'txtSource is the class side textbox var
    5.  
    6. Private Declare Function SendMessage Lib "user32" Alias "SendMessageA" (ByVal hWnd As Long, ByVal wMsg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long
    7. Private Declare Function GetWindowLong Lib "user32" Alias "GetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long) As Long
    8. Private Declare Function SetWindowLong Lib "user32" Alias "SetWindowLongA" (ByVal hWnd As Long, ByVal nIndex As Long, ByVal dwNewLong As Long) As Long
    9.  
    10. Private Const EM_SETREADONLY As Long = &HCF
    11. Private Const ES_NUMBER As Long = &H2000
    12. Private Const ES_READONLY As Long = &H800
    13. Private Const GWL_STYLE As Long = -16
    14.  
    15. Public Property Get NumbersOnly() As Boolean
    16.    Dim lngStyle As Long
    17.    If Not blnClassBound Then Exit Property
    18.    lngStyle = GetWindowLong(txtSource.hWnd, GWL_STYLE)
    19.    NumbersOnly = CBool(lngStyle And ES_NUMBER)
    20. End Property
    21.  
    22. Public Property Let NumbersOnly(ByVal blnNewNumbersOnly As Boolean)
    23.    Dim lngStyle As Long
    24.    If Not blnClassBound Then Exit Property
    25.    lngStyle = GetWindowLong(txtSource.hWnd, GWL_STYLE)
    26.    lngStyle = IIf(blnNewNumbersOnly, lngStyle Or ES_NUMBER, lngStyle And (Not ES_NUMBER))
    27.    SetWindowLong txtSource.hWnd, GWL_STYLE, lngStyle
    28. End Property
    29.  
    30. 'I had this in there before I even knew a textbox had a .Locked property
    31. 'but I'll include it anyway.  someone may find a use for it
    32. Public Property Get ReadOnly() As Boolean
    33.    Dim lngStyle As Long
    34.    If Not blnClassBound Then Exit Property
    35.    lngStyle = GetWindowLong(txtSource.hWnd, GWL_STYLE)
    36.    ReadOnly = CBool(lngStyle And ES_READONLY)
    37. End Property
    38.  
    39. 'SetWindowLong doesn't seem to make a textbox read only if you manually
    40. 'change the ES_READONLY flag for some reason, but SendMessage does get it
    41. Public Property Let ReadOnly(ByVal blnNewReadOnly As Boolean)
    42.    If Not blnClassBound Then Exit Property
    43.    SendMessage txtSource.hWnd, EM_SETREADONLY, blnNewReadOnly, 0
    44. End Property
    I had a .GetLine(Index) prop too, but I remember getting a snag somewhere and ditched it. In that case, it was before I even knew of Split() (those were bad times indeed ), but I had an API way. I'm going to work on that again.

    I remembered a while later I forgot one of the useful ones I intended to show in the first place...
    VB Code:
    1. Private Const EM_GETMODIFY As Long = &HB8
    2. Private Const EM_SETMODIFY As Long = &HB9
    3.  
    4. Public Property Get Edited() As Boolean
    5.    If Not blnClassBound Then Exit Property
    6.    Edited = SendMessage(txtSource.hWnd, EM_GETMODIFY, 0, 0)
    7. End Property
    8.  
    9. Public Property Let Edited(ByVal blnNewEdited As Boolean)
    10.    If Not blnClassBound Then Exit Property
    11.    SendMessage txtSource.hWnd, EM_SETMODIFY, blnNewEdited, 0
    12. End Property
    13.  
    14. Private Sub txtSource_Change()
    15.    'this makes sure the edited flag is set, as I noticed there were times
    16.    'when changing text wouldn't make it apparent to the class for some reason
    17.    Me.Edited = True
    18. End Sub
    Last edited by Kaverin; Aug 21st, 2001 at 11:00 PM.
    I'm baaaack...
    VB5 Professional Edition, VC++ 6
    Using a 1 gHz Thunderbird, 256 mb RAM, 40 gb HD system with Win98se

    I feel special because I finally figured out how to loop midis: Post link
    I'm a fanatic too

  13. #13

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530
    Thanks for the Info Kaverin. I did think about using api calls to make the textbox numerical, but it stops the user from entering decimal places and it doesn't stop the user from pasting in data. I originally wanted to use these shortcuts but found they didn't offer the flexibiliy I needed.

    Here are some notes I made:
    Private Const ES_LOWERCASE = &H10& 'Make Text Box lowercase only (but can paste so add validate routine)
    Private Const ES_UPPERCASE = &H8& 'Make text Box uppercase only (but can paste so add validate rountine)
    Private Const ES_NUMBER = &H2000& 'Make text box numeric only (but can paste in so add validate routine)

    If I used these messages to force the textbox to be uppercase, then I wouldn't be able to give the user the ability to enter lowercase data and have the textbox automaticlly change it to uppercase. This is why I wanted to see the API app AAG was talking about. I don't think you can get the flexibility needed from API calls.

    The idea now is that you can basically select what the textbox should allow (any combination of): numerical, uppercase text, lowercase text, symbols, spaces, number of decimal places, max and min. You can also optionally trap errors at the keystroke level, or choose to let the user enter what they like and have the text box automatically fix up the data later.

  14. #14
    Fanatic Member Kaverin's Avatar
    Join Date
    Oct 2000
    Posts
    930
    Those aren't messages for SendMessage, those are styles. I tried them out myself, and they work as expected when you use them in Set/GetWindowLong. They even prevent pasting the wrong case (I checked that out too because I didn't know myself). Pasting known lowercase things into a control where the uppercase style was applied forced them to appear as uppercase, and the reverse. I did notice that applying the ES_LOWERCASE style overrides the upper one if by chance you had both set.
    I'm baaaack...
    VB5 Professional Edition, VC++ 6
    Using a 1 gHz Thunderbird, 256 mb RAM, 40 gb HD system with Win98se

    I feel special because I finally figured out how to loop midis: Post link
    I'm a fanatic too

  15. #15

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530
    Kaverin, I am sure you see what I mean about getting the flexibilty needed to really make it all work well; it just doesn't happen with these API calls. Perhaps AAG was talking about different API functions that work better?

  16. #16
    Fanatic Member Kaverin's Avatar
    Join Date
    Oct 2000
    Posts
    930
    Yes, I understand your point about flexibility. I was just clearing up that setting the styles for upper/lowercase does work, and catches pasting. It won't catch pasting when you have the number only style though. I don't know why though. These are the only APIs I'd know of to do such things myself, so I don't know what AAG could have meant if these weren't the ones.
    I'm baaaack...
    VB5 Professional Edition, VC++ 6
    Using a 1 gHz Thunderbird, 256 mb RAM, 40 gb HD system with Win98se

    I feel special because I finally figured out how to loop midis: Post link
    I'm a fanatic too

  17. #17

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530
    *nudge*

  18. #18
    Fanatic Member Kaverin's Avatar
    Join Date
    Oct 2000
    Posts
    930
    Here's some other stuff you may want to add to the class. I see people asking about getting/changing lines in text files/boxes, and about the row/column numbers too. These props will do those for you. There's an API method of the property get version of Lines which I'd say is faster because it doesn't use the split method, but I don't know of a way to implement the API in a property let version. I had to do that with Split().
    VB Code:
    1. Private Const EM_GETLINE As Long = &HC4
    2. Private Const EM_GETLINECOUNT As Long = &HBA
    3. Private Const EM_GETSEL As Long = &HB0
    4. Private Const EM_LINEFROMCHAR As Long = &HC9
    5. Private Const EM_LINEINDEX As Long = &HBB
    6. Private Const EM_LINELENGTH As Long = &HC1
    7.  
    8. 'here's the API way if anyone wants to know how it was done
    9. Public Property Get LinesAPI(ByVal lngLineNumber As Long) As String
    10.    Dim lngLineCount As Long
    11.    Dim lngFirstChar As Long
    12.    Dim lngLineLength As Long
    13.    Dim hWnd As Long
    14.    Dim abyteBuffer() As Byte
    15.    LinesAPI = ""
    16.    If Not blnClassBound Then Exit Property
    17.    hWnd = txtSource.hWnd
    18.    lngLineCount = SendMessage(hWnd, EM_GETLINECOUNT, 0, 0)
    19.    If (lngLineNumber < 0) Or (lngLineNumber > (lngLineCount - 1)) Then Exit Property
    20.    lngFirstChar = SendMessage(hWnd, EM_LINEINDEX, lngLineNumber, 0)
    21.    lngLineLength = SendMessage(hWnd, EM_LINELENGTH, lngFirstChar, 0)
    22.    If lngLineLength = 0 Then Exit Property
    23.    ReDim abyteBuffer(0 To (lngLineLength - 1))
    24.    abyteBuffer(0) = lngLineLength And &HFF
    25.    If lngLineLength > 255 Then abyteBuffer(1) = lngLineLength And &H100
    26.    SendMessage hWnd, EM_GETLINE, lngLineNumber, VarPtr(abyteBuffer(0))
    27.    LinesAPI = StrConv(abyteBuffer, vbUnicode)
    28. End Property
    29.  
    30. 'this is the Split() way, which takes less work, but may be slower for longer text
    31. Public Property Get Lines(ByVal lngLineNumber As Long) As String
    32.    Dim astrLines As Variant 'may be astrLines() As String for VB6 users
    33.    Lines = ""
    34.    If Not blnClassBound Then Exit Property
    35.    If txtSource.Text = "" Then Exit Property
    36.    astrLines = Split(txtSource.Text, vbCrLf)
    37.    If (lngLineNumber < 0) Or (lngLineNumber > UBound(astrLines)) Then Exit Property
    38.    Lines = astrLines(lngLineNumber)
    39. End Property
    40.  
    41. Public Property Let Lines(ByVal lngLineNumber As Long, ByVal strNewLine As String)
    42.    Dim astrLines As Variant 'may be astrLines() As String for VB6 users
    43.    If Not blnClassBound Then Exit Property
    44.    If txtSource.Text = "" Then
    45.       txtSource.Text = strNewLine
    46.       Exit Property
    47.    End If
    48.    astrLines = Split(txtSource.Text, vbCrLf)
    49.    If (lngLineNumber < 0) Or (lngLineNumber > UBound(astrLines)) Then Exit Property
    50.    astrLines(lngLineNumber) = strNewLine
    51.    txtSource.Text = Join(astrLines, vbCrLf)
    52. End Property
    53.  
    54. 'the next two are mainly for multiline textboxes, but work on single line ones too
    55. 'the row will always be 1 for a single line textbox
    56. Public Property Get Column() As Long
    57.    Dim lngReturn As Long
    58.    Dim lngCharIndex As Long
    59.    Dim lngRow As Long
    60.    If Not blnClassBound Then Exit Property
    61.    lngReturn = SendMessage(txtSource.hWnd, EM_GETSEL, 0, 0)
    62.    lngCharIndex = (lngReturn / 65536) And &HFFFF
    63.    lngReturn = SendMessage(txtSource.hWnd, EM_LINEINDEX, -1, 0)
    64.    Column = lngCharIndex - lngReturn + 1
    65. End Property
    66.  
    67. Public Property Get Row() As Long
    68.    Dim lngReturn As Long
    69.    Dim lngCharIndex As Long
    70.    If Not blnClassBound Then Exit Property
    71.    lngReturn = SendMessage(txtSource.hWnd, EM_GETSEL, 0, 0)
    72.    lngCharIndex = (lngReturn / 65536) And &HFFFF
    73.    Row = SendMessage(txtSource.hWnd, EM_LINEFROMCHAR, lngCharIndex, 0) + 1
    74. End Property
    Last edited by Kaverin; Sep 14th, 2001 at 05:38 PM.
    I'm baaaack...
    VB5 Professional Edition, VC++ 6
    Using a 1 gHz Thunderbird, 256 mb RAM, 40 gb HD system with Win98se

    I feel special because I finally figured out how to loop midis: Post link
    I'm a fanatic too

  19. #19

    Thread Starter
    Registered User Nucleus's Avatar
    Join Date
    Apr 2001
    Location
    So that's what you are up to ;)
    Posts
    2,530

    Thumbs up

    Nice one Kaverin, those props will come in handy.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width