PowerBASIC Peer Support Forums
 

Go Back   PowerBASIC Peer Support Forums > User to user Discussions > My Favorite API

My Favorite API Describe one API function per thread. Complementary functions may be combined. Show how easy it is to use, and how folks can extend their compiler.

Reply
 
Thread Tools Display Modes
  #1  
Old Feb 22nd, 2011, 12:21 AM
colin glenn colin glenn is offline
Member
 
Join Date: Nov 2004
Posts: 563
Talking ListView_ [ SetColumnWidth / GetColumnWidth ]

I have a thing for neatness of the user interface. Sometimes my code don't seem that way, but that's a different story. One of the things that bugs me is when I design something with a listview in it, is having to set the width of the columns. One can do it manually, and let the user use CTRL+(PlusKey) to call on windows to do this, but why make the user take this step when you can program in a quick function to resize the columns of the listview according to either the width of the header, or the width of the content?

PB's DTT system for listview's have a very nice set of functions for doing that, setting the column width to either the content, or the header, but they lack a bit of finesse in making it really pretty by determining which is wider. If you want to find out which is wider, you need to get into the API itself with two macros:
Code:
BOOL ListView_SetColumnWidth(
    HWND hwnd,
    int iCol,
    int cx
);
int ListView_GetColumnWidth(
    HWND hwnd,
    int iCol
);
With the power of these two macros, plus a couple of constants, %LVSCW_AUTOSIZE & LVSCW_AUTOSIZE_USEHEADER, plus two more calls:
Code:
hHeader = ListView_GetHeader(hListView)
lvhCount = Header_GetItemCount(hHeader)
One can make an autosizing listview by stepping through the columns and checking which would fit better, the header width, or the content width.

But we can even take it a step further, in handling a situation where one of the columns, if autosized to fit contents, causes the listview to exceed the right side of the window it's in, forcing the user to use the horizontal scroll bar to see the right hand columns.

For an example, we have a 3 column listview, where the 2nd column needs to be adjusted to fit the remaining space after resizing the 1st & 3rd. You can't just autosize them then check for remaining space, according to the SDK:
Quote:
LVSCW_AUTOSIZE_USEHEADER
Automatically sizes the column to fit the header text. If you use this value with the last column, its width is set to fill the remaining width of the list-view control.
So we need to fit all three columns, then check widths. We'll need a function to avoid code bloat:
Code:
FUNCTION ResizeColumn(hListView AS DWORD, lvhIndex AS LONG, MaxWidth AS LONG) AS LONG
LOCAL lvFitHeader, lvFitContent, lvhBestFit     AS LONG
    ListView_SetColumnWidth hListView, lvhIndex, %LVSCW_AUTOSIZE_USEHEADER
    lvFitHeader = ListView_GetColumnWidth(hListView, lvhIndex)
    ListView_SetColumnWidth hListView, lvhIndex, %LVSCW_AUTOSIZE
    lvFitContent = ListView_GetColumnWidth(hListView, lvhIndex)
    IF (MaxWidth = 0) THEN
        lvhBestFit = IIF(lvFitContent > lvFitHeader, lvFitContent, lvFitHeader)
    ELSE
        lvhBestFit = IIF(MaxWidth < 0, lvFitHeader, MaxWidth)
    END IF
    ListView_SetColumnWidth hListView, lvhIndex, lvhBestFit
    ResizeColumn = lvhBestFit
END FUNCTION
When we use this on each of our columns, we get back the width to which the column was set to, providing we first pass it Zero as the MaxWidth parameter the first time around. So we collect those widths, total them, then check if they exceed the available width of the listview's window. Not the parent container.
Code:
Column0 = ResizeColumn(hListView, 0, 0)
Column1 = ResizeColumn(hListView, 1, 0)
Column2 = ResizeColumn(hListView, 2, 0)
GetClientRect hListView, lvRect
cMax = lvRect.nRight
IF (cMax < (Column0 + Column1 + Column2)) THEN
    cMax = cMax - (Column0 + Column2)
    Column1 = ResizeColumn(hListView, 1, cMax)
END IF
And TaDa! Our second column gets the remaining width of the listview with the 1st & 3rd columns also nicely presented.

Of course, you can always skip that IF check and just set the 2nd column to fit remaining space regardless, it's all up to how you want to present things.
__________________
Furcadia, an interesting online MMORPG in which you can create and program your own content.
Reply With Quote
  #2  
Old Feb 22nd, 2011, 04:34 PM
Chris Holbrook Chris Holbrook is offline
Member
 
Join Date: Aug 2005
Location: in Hiding
Posts: 6,173
Quote:
Originally Posted by colin glenn View Post
...why make the user take this step when you can program in a quick function to resize the columns of the listview according to either the width of the header, or the width of the content?
Because it is seldom an ideal approximation.

An alternative might be to concentrate the effort on making a higher-level specification of the listview, so that you could use a sub something like this:

setLVcolumns(hListView, "mycol1|L|20,mycol2|R|50,mycol3|C|30") where hListView is the listview window handle, mycol1..3 are the column titles, L|R|C are alignment specifiers and the numerics are the percentage of the total available width. This approach simplifies the handling of resizeable dialogs containing listviews, for example, and of course you need only write it once!
Reply With Quote
  #3  
Old Feb 22nd, 2011, 05:33 PM
colin glenn colin glenn is offline
Member
 
Join Date: Nov 2004
Posts: 563
Could probably do that, create a listview object to wrap the listview in like I did for the statusbar.
__________________
Furcadia, an interesting online MMORPG in which you can create and program your own content.
Reply With Quote
  #4  
Old Feb 22nd, 2011, 10:23 PM
colin glenn colin glenn is offline
Member
 
Join Date: Nov 2004
Posts: 563
Hey, more using these two calls, after using my above code to initially set the size, what if the user resizes the window containing the listview?

Well, after all the rest of the resizing action handled in the %WM_SIZE:
Code:
Column0 = ListView_GetColumnWidth(hListView, 0)
Column2 = ListView_GetColumnWidth(hListView, 2)
GetClientRect hListView, lvRect
Column1 = lvRect.nRight - (Column0 + Column2)
ListView_SetColumnWidth hListView, 1, Column1
Whee!
__________________
Furcadia, an interesting online MMORPG in which you can create and program your own content.
Reply With Quote
  #5  
Old Dec 20th, 2011, 11:30 PM
Gary Beene Gary Beene is offline
Member
 
Join Date: May 2008
Location: Dallas, Tx
Posts: 9,230
Hi Colin,
Reviving this older thread ... I was looking at Outlook to see how they handle resizing of mailbox columns (From/Subject/Date/Size).

As the app is resized, it seems that the columns maintain a fixed percentage of available width.

But if the user manually changes the width of a column, the remaining width is proportionately distributed between the remaining, unsized columns - creating a new set of percentages which are used until another manual resize occurs.

So for a 800p width, the column widths are about this:
From 15% 120p
Subj 60% 480p
Date 15% 120p
Size 10% 80p

If the user adjusts the width of From to 200p, the widths become roughly this:
From 25% 200p
Subj 55% 420p
Date 12% 110p
Size 8% 70p

By my calculations, the leftover width (800-200) is distributed to the remaining 3 columns in the same proportion as they were before the manual resize took place. That creates a new set of % of available width for each column.

After manually resizing, the new percentages are maintained/applied when resizing the app.
__________________
Reply With Quote
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT -4. The time now is 05:49 AM.


Powered by vBulletin® Version 3.8.1
Copyright ©2000 - 2014, Jelsoft Enterprises Ltd.
Copyright 1999-2011 PowerBASIC, Inc. All Rights Reserved.
Error in my_thread_global_end(): 1 threads didn't exit