AutoHotkey Community

It is currently May 26th, 2012, 12:48 pm

All times are UTC [ DST ]




Post new topic Reply to topic  [ 4 posts ] 
Author Message
PostPosted: December 21st, 2008, 8:06 pm 
Offline

Joined: July 30th, 2007, 11:32 pm
Posts: 581
While I was working on a project (which I'll hopefully also post here when I'm done), I found myself needing an horizontal scrollbar for my listboxes, because of very long items. No problem I thought. I'll simply use the GuiControl +HScroll command. The only problem is that the only way to use this command is to specify how many pixels you want the scrollbar to scroll. That's not practical because the longest item in the listbox might be less or more than the specified scrolling limit.

So then I made some research, and found this, straight from Microsoft. It tells you in details how to add a horizontal scrollbar to the listbox sensitive to items' width. All I did was adapt the steps from the article to AutoHotkey with the help of this topic and that one (thanks to Sean, majkinetor and dncarac).

And this is what you get: a function that adds an horizontal scrollbar to your listbox, which will scroll only up to what you need, that is, up to the longest item (and also taking into consideration the font used in the listbox).

How to use/add to your code
All you need from the code below is the ListBoxAdjustHSB function and the GetListBoxItem function. I only added a GUI as an example. Everytime an item is added/removed from the listbox, call the ListBoxAdjustHSB function to adjust the scrollbar extent (or remove it if not needed). Make sure you have the +HScroll option when adding your listbox, otherwise it won't work.

Code:
Gui, Add, ListBox, h100 hwndhLB +HScroll, This is a short list box item.|This is a very very very very very very very very very very very very very very long list box item.
Gui, Show

;Add Horizontal Bar
ListBoxAdjustHSB(hLB)

Return

GuiClose:
ExitApp
Return

ListBoxAdjustHSB(hLB) {
   
   ;Declare variables (for clarity's sake)
   dwExtent := 0
   dwMaxExtent := 0
   hDCListBox := 0
   hFontOld := 0
   hFontNew := 0
   VarSetCapacity(lptm, 53)
   
   ;Use GetDC to retrieve handle to the display context for the list box and store it in hDCListBox
   hDCListBox := DllCall("GetDC", "Uint", hLB)

   ;Send the list box a WM_GETFONT message to retrieve the handle to the font that the list box is using, and store this handle in hFontNew
   SendMessage 49, 0, 0,, ahk_id %hLB%
   hFontNew := ErrorLevel

   ;Use SelectObject to select the font into the display context. Retain the return value from the SelectObject call in hFontOld
   hFontOld := DllCall("SelectObject", "Uint", hDCListBox, "Uint", hFontNew)

   ;Call GetTextMetrics to get additional information about the font being used (eg. to get tmAveCharWidth's value)
   DllCall("GetTextMetrics", "Uint", hDCListBox, "Uint", &lptm)
   tmAveCharWidth := NumGet(lptm, 20)

   ;Get item count using LB_GETCOUNT
   SendMessage 395, 0, 0,, ahk_id %hLB%

   ;Loop through the items
   Loop %ErrorLevel% {

      ;Get list box item text
      s := GetListBoxItem(hLB, A_Index - 1)

      ;For each string, the value of the extent to be used is calculated as follows:
      DllCall("GetTextExtentPoint32", "Uint", hDCListBox, "str", s, "int", StrLen(s), "int64P", nSize)
      dwExtent := (nSize & 0xFFFFFFFF) + tmAveCharWidth

      ;Keep if it's the highest to date
      If (dwExtent > dwMaxExtent)
         dwMaxExtent := dwExtent
      
   }
   
   ;After all the extents have been calculated, select the old font back into hDCListBox and then release it:
   DllCall("SelectObject", "Uint", hDCListBox, "Uint", hFontOld)
   DllCall("ReleaseDC", "Uint", hLB, "Uint", hDCListBox)
   
   ;Adjust the horizontal bar using LB_SETHORIZONTALEXTENT
   SendMessage 404, dwMaxExtent, 0,, ahk_id %hLB%

}

GetListBoxItem(hLB, i) {
      
   ;Get length of item. 394 = LB_GETTEXTLEN
   SendMessage 394, %i%, 0,, ahk_id %hLB%
   
   ;Check for error
   If (ErrorLevel = 0xFFFFFFFF)
      Return ""
   
   ;Prepare variable
   VarSetCapacity(sText, ErrorLevel, 0)
   
   ;Retrieve item. 393 = LB_GETTEXT
   SendMessage 393, %i%, &sText,, ahk_id %hLB%
   
   ;Check for error
   If (ErrorLevel = 0xFFFFFFFF)
      Return ""
   
   ;Done
   Return sText

}



Let me know if you find bugs or see places where I could improve.
Enjoy!


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 22nd, 2008, 3:38 am 
Offline

Joined: December 4th, 2006, 10:35 am
Posts: 561
Location: Galil, Israel
You've done an incredibly clear job of explaining & documenting your function. FANTASTIC!

_________________
Joyce Jamce


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 22nd, 2008, 8:47 am 
Offline

Joined: October 1st, 2005, 9:55 pm
Posts: 775
Location: Texas, USA
This looks useful. I just need to remember that it's available the next time I create a ListBox that needs a horizontal scroll bar. Thanks for sharing. :)


Report this post
Top
 Profile  
Reply with quote  
 Post subject:
PostPosted: December 22nd, 2008, 5:28 pm 
Offline

Joined: July 30th, 2007, 11:32 pm
Posts: 581
I'm glad you guys like it :D
I'll see if I can put it in Jon's stickied wiki. lol I wonder if "stickied" is even a word.


Report this post
Top
 Profile  
Reply with quote  
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 4 posts ] 

All times are UTC [ DST ]


Who is online

Users browsing this forum: DataLife and 20 guests


You can post new topics in this forum
You can reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Search for:
Powered by phpBB® Forum Software © phpBB Group