Listview

As opposed to a Treeview, Windows (i.e. Explorer) uses also a Listview. In the Listview you can show items with an icon and have them displayed in different modes (see right pane in Explorer).

I tried to insert an Active-X component but Xojo crashes immediately (bummer). There is no Xojo wrapper for the Windows listview. Is construction only possible with a Canvas?

Sounds like you want the Xojo Listbox.

Hi Karen. Nope. In Delphi there are several implementations of this Listview. Incredibly handy, convenient en easy in combination with a Listbox to show i.e. the contents of a table… records in the Treeview/Listbox and columns in the Listview. Alas…

You can easily make listbox subclasses to do all that… For example it took me about 10 minutes to create one that displays the content of any database RecordSet that has less than 64 fields

wow… Karen…10 minutes… amazing…

Well it may have been 15 min! :wink:

If you know the listbox well it really is trivial to create a RecordSet “aware” one.

what is the most difficult part ?? any code to show me??

When I get home

Karen, I would love to see that too?

thanks…

The Language Reference “RecordSet” gives an example of populating a listbox, with headers, from a query. This should be enough to get you started.

[code]#tag Class
Protected Class RS_Listbox
Inherits Listbox
#tag Method, Flags = &h0
Sub ShowRecordSet(RS as RecordSet, Maxwidth as integer = 500)
DeleteAllRows

	  If RS is NIL Then
	    ColumnCount = 1
	    Column(0).WidthExpression = "*"
	    
	    Heading(0) =  "NIL Record Set"
	    AddRow "None Found"
	    Return
	  End IF
	  
	  
	  Dim ub as Integer = RS.FieldCount
	  ColumnCount = ub
	  
	  Dim ColWidth() as double, theStr as String
	  Redim ColWidth(ub-1)
	  
	  Dim P as new Picture(1,1,32)
	  Dim g as Graphics = P.Graphics
	  g.TextFont= TextFont
	  g.TextSize = TextSize
	  g.Bold = Bold
	  g.Italic = Italic
	  g.Underline = Underline
	  g.TextUnit = TextUnit
	  
	  Dim i as Integer
	  For i  = 1 to ub
	    theStr =  RS.IdxField(i).Name
	    ColWidth(i-1) = g.StringWidth(theStr)
	    Heading(i-1) = theStr
	  Next
	  
	  Dim Row as Integer
	  
	  While Not RS.EOF
	    theStr = RS.IdxField(1).StringValue
	    AddRow theStr
	    ColWidth(0) = Max(ColWidth(0), g.StringWidth(theStr))
	    Row = LastIndex
	    for i  = 2 to ub
	      theStr = Rs.IdxField(i).StringValue
	      Cell(row,i-1) = theStr
	      ColWidth(i-1) = Max(ColWidth(i-1), g.StringWidth(theStr))
	    Next
	    RS.MoveNext
	  Wend
	  
	  for i = 1 to ub
	    theStr = Str(min(Ceil(ColWidth(i-1)) + 10, Maxwidth))
	    Column(i-1).WidthExpression=  theStr
	    Column(i-1).WidthActual= Val(theStr)
	    
	  Next
	  
	  Self.Invalidate
	End Sub

[/code]

thanks for the code… just try it out and it work really well. What is the g use for??

To measure the text size to set column widths

ahhh i see… never though of doing that… what other fancy thing have you done with listbox…

I have written my own SQLite Database Manager and have very similar code to Karen’s code. I have made my dbListbox recognise the type of data being shown so as to display it as a user would read it.

A very useful property within the Recordset variable is ColumnType. By testing the ColumnType of each column in the dataset you can format the data. For example, if the RS.ColumnType(0) = 11 then the column is a Xojo Currency value. A currency value would (normally) be displayed '#,##0.00;(#,##0.00);\ '. So, Karen’s display variable of ‘theStr’ would be set to Format(Rs.IdxField(i).CurrencyValue, "#,##0.00;(#,##0.00);\ ") AND the column would be aligned right with ColumnAlignment = Listbox.AlignRight.

So I would adjust Karen’s code as follows:

[code]#tag Class
Protected Class RS_Listbox
Inherits Listbox
#tag Method, Flags = &h0
Sub ShowRecordSet(RS as RecordSet, Maxwidth as integer = 500)
DeleteAllRows

	  If RS is NIL Then
	    ColumnCount = 1
	    Column(0).WidthExpression = "*"
	    
	    Heading(0) =  "NIL Record Set"
	    AddRow "None Found"
	    Return
	  End IF
	  
	  
	  Dim ub as Integer = RS.FieldCount
	  ColumnCount = ub
	  
	  Dim ColWidth() as double, theStr as String
	  Redim ColWidth(ub-1)
	  
	  Dim P as new Picture(1,1,32)
	  Dim g as Graphics = P.Graphics
	  g.TextFont= TextFont
	  g.TextSize = TextSize
	  g.Bold = Bold
	  g.Italic = Italic
	  g.Underline = Underline
	  g.TextUnit = TextUnit
	  
	  Dim i as Integer
	  For i  = 1 to ub
	    theStr =  RS.IdxField(i).Name
	    ColWidth(i-1) = g.StringWidth(theStr)
	    Heading(i-1) = theStr
	    
	    // ADDED CODE FOR FORMATTING
	    select case RS.IdxField(i).ColumnType
	     case 0, 1, 4, 5, 14, 15, 16, 18, 255
	      ColumnTag(i-1) = "String"
	     case 6, 7, 13
	      ColumnTag(i-1) = "Number"
	      ColumnAlignment(i-1) = Listbox.AlignRight
	     case 2, 3, 19
	      ColumnTag(i-1) = "Integer"
	      ColumnAlignment(i-1) = Listbox.AlignRight
	     case 8, 9, 10
	      ColumnTag(i-1) = "Date"
	      ColumnAlignment(i-1) = Listbox.AlignCenter
	     case 11
	      ColumnTag(i-1) = "Currency"
	      ColumnAlignment(i-1) = Listbox.AlignRight
	     case 12
	      ColumnTag(i-1) = "Boolean"
	      ColumnAlignment(i-1) = Listbox.AlignCenter
	    end select
	    // END OF ADDED CODE
	    
	  Next
	  
	  Dim Row as Integer
	  
	  While Not RS.EOF
	    // theStr = RS.IdxField(1).StringValue    <-- REMOVE THIS
	    AddRow
	    Row = LastIndex
	    for i  = 1 to ub
	      // theStr = Rs.IdxField(i).StringValue    <-- REMOVE THIS
	      
	      // ADDED CODE
	      select case ColumnTag(i-1)
	       case "String"
	        theStr = RS.IdxField(i).StringValue
	       case "Number"
	        theStr = Format(RS.IdxField(i).DoubleValue, "-#,##0.########")
	       case "Integer"
	        theStr = Format(RS.IdxField(i).IntegerValue, "-#")
	       case "Date"
	        theStr = RS.IdxField(i).DateValue.SQLDateTime
	       case "Currency"
	        theStr = Format(Rs.IdxField(i).CurrencyValue, "#,##0.00;(#,##0.00);\\ ")
	       case "Boolean"
	        if RS.IdxField(i)..BooleanValue then
	         theStr = "True"
	        else
	         theStr = "False"
	        end if
	      end select
	      // END ADDED CODE
	    
	      Cell(row,i-1) = theStr
	      ColWidth(i-1) = Max(ColWidth(i-1), g.StringWidth(theStr))
	    Next
	    RS.MoveNext
	  Wend

	    
	    ColWidth(0) = Max(ColWidth(0), g.StringWidth(theStr))
	  
	  for i = 1 to ub
	    theStr = Str(min(Ceil(ColWidth(i-1)) + 10, Maxwidth))
	    Column(i-1).WidthExpression=  theStr
	    Column(i-1).WidthActual= Val(theStr)
	    
	  Next
	  
	  Self.Invalidate
	End Sub

[/code]

I have added some additional properties for the formatting that I have in the inspector with the defaults as shown above. This allows the developer to specify the actual format to use for each type of format. The formatting properties I created are:

formatInteger = "-#"
formatNumber = "-#,##0.########"
formatCurrency = "#,##0.00;(#,##0.00);\\ "

I have also created a date formatting routine so I have a formatDate property too.

I hope that you will find that you now have a completely data aware Listbox subclass.

Here is a working subclass:

https://dl.dropboxusercontent.com/u/10747116/RealStudioClasses/dbListbox.xojo_binary_code.zip

Gee… this thread leads to hitherto unknown paths and insight…very good. Thanks for the code!

Thank you, but the credit really goes to Karen.

If you want to see another subclassed listbox that I have made (not actually data aware) that uses all sorts of additional formats etc. download my MagicListbox from here:

https://dl.dropboxusercontent.com/u/10747116/RealStudioClasses/MagicListbox.zip

It’s free!

i have no idea there is a ColumnType in the Recordset.