wxListCtrl

BlitzMax Forums/Brucey's Modules/wxListCtrl

Glenn Dodd(Posted 2008) [#1]
I have stripped back Bruceys sample ListCtrl to just the parts i want.
I am not sure why
Method InsertItemInReportView(i:Int)
needs to be in a seperate type.
anyone got a simple explanation?

cheers
glenn




Glenn Dodd(Posted 2008) [#2]
answer found

listCtrl = MyListCtrl(New MyListCtrl.Create(panel, LIST_CTRL, ,, ,, flags | wxSUNKEN_BORDER | wxLC_EDIT_LABELS))

doh !!!


Glenn Dodd(Posted 2008) [#3]
Okay - After several days of trying to get my own data from a DataBase type into a ListCtrl i have brought it back to the Sample Program, and configured how i am doing it in the real program.

I have a GUI file and the Main file.
The main file doesn't seem to compile on :
For Local i:Int = 0 Until 4
m_listCtrlTEST.InsertItemInReportView(i)
Next

m_listCtrlTEST is the listctrl from the gui file.
it complains about InsertItemInReportView though and not being able to find it. This is in the seperate MyListCtrl type, based on the sample. I have added the listctrl as a field of MyListCtrl on the off chance that helps...

I have a seperate TDataSet (not being used in this example yet) which i planned to use later.

Any suggestions welcomed.

ListCtrlTestGUI.bmx



ListCtrlTest.bmx

Edited 08 March 2008 to stretch as the window is widened.


DavidDC(Posted 2008) [#4]
Put Field m_listCtrlTEST:wxListCtrl in MyFrame2 perhaps?


Brucey(Posted 2008) [#5]
Me thinks you should rather start afresh and not rely too much on the listctrl sample code.

The problem with the samples is that they tend to show *everything* that a control can do, which is not necessarily what *you* want to do.

Here are some snippets from my current "playing with wxMax" project, SQLiteDBA. It assumes you are using the listctrl in REPORT mode, which is most useful for showing things with rows/columns.

Adding an item to a row in a listctrl (which has several columns)
	Method InsertIntoList(index:Int, list:wxListCtrl)

		Local item:wxListItem = New wxListItem.Create()
		item.SetImage(-1)
		item.SetText(seq)
		item.SetId(index)
		
		list.InsertItem(item)

		item.SetText(name)
		item.SetColumn(1)
		list.SetItem(item)

		item.SetText(Null)
		If unique Then
			item.SetImage(IMG_CHECKED)
		Else
			item.SetImage(IMG_UNCHECKED)
		End If
		item.SetColumn(2)
		list.SetItem(item)

	End Method

SetImage() is telling the item to show a particular image from an image list - obviously an optional thing :-)

When inserting a new row (of more than one column), create a wxListItem object and set it's parts. It's easier. "id" is the row index. User InsertItem() to initially add that row.
For other columns on that row, use SetColumn() on the item to specifiy which column the item is for, and then SetItem() to actually "put" the item in the list at the desired location.


This little snippet sets the column headings :
	Method SetIndexHeadings()
		indexesList.InsertColumn(0, _("Seq"), wxLIST_FORMAT_CENTRE, 60)
		indexesList.InsertColumn(1, _("Name"))
		indexesList.InsertColumn(2, _("Unique"), wxLIST_FORMAT_CENTRE, 80)
	End Method

Note that for a REPORT mode listctl, you'll need column headings. (unless you define the listctrl to hide them).


Hope this helps a bit.


Brucey(Posted 2008) [#6]
Here's the methd I use to "recreate" the list :

	Method PopulateIndexes(table:TDBATable)
		indexesList.ClearAll()
		SetIndexHeadings()
		
		If table Then
			Local list:TList = table.ListIndexes()
		
			Local i:Int = 0
			For Local index:TDBAIndex = EachIn list
				index.InsertIntoList(i, indexesList)
				i:+ 1
			Next
		End If
	End Method

Notice that the listctrl itself isn't deleted/removed (unlike in the sample, which is doing other things). Calling ClearAll() will remove *all* the data *and* the column headings. So the first thing we do is re-apply the headings.
Then the code iterates through a list of data, and calls the previously mentioned method to actually add the data to the list.

Remember, this is just one way to do everything.

But basically, the steps involved are :

* Clear your list
* Add headers if you need them
* Insert your row items.

:o)


Glenn Dodd(Posted 2008) [#7]
hmmm.
must watch House and Boston Legal, but back into this in a few hours... :)


Brucey(Posted 2008) [#8]
Here's the listctrl showing a row of data in it :


...it's the listctrl on the right :-)


Glenn Dodd(Posted 2008) [#9]
indexesList.InsertColumn(0, _("Seq"), wxLIST_FORMAT_CENTRE, 60)

What is the underscore for?


Brucey(Posted 2008) [#10]
Localization :-)

Allows the app to use different languages at some point.


Glenn Dodd(Posted 2008) [#11]
how come SEQ isn't centered in the Tab like Unique is?


Brucey(Posted 2008) [#12]
No idea. Most likely a wxWidgets bug.


DavidDC(Posted 2008) [#13]
@No idea. Most likely a wxWidgets bug.

wxWidgets correctly centres the label of column 0 when you populate the header manually using wxListItem (including of course a SetAlign() call) and instantiate via InsertColumnItem(col,item).

At least it does on my list controls...


Brucey(Posted 2008) [#14]
Perhaps the SetAlign() afterwards is forcing it properly.

I've noticed a couple of quirks with working in Report mode.


Glenn Dodd(Posted 2008) [#15]
I seem to be stuck on this:
index:TDBAIndex
what does TDGAIndex refer to in your program?

[EDIT] Problem resolved.


Glenn Dodd(Posted 2008) [#16]
If i uncomment the IMG_CHECKED section it doesn't compile.
I can't track this down.

Regards
Glenn

Use the ListCtrlTestGUI.bmx from the third post




Brucey(Posted 2008) [#17]
Swap IMG_CHECKED for 1
and IMG_UNCHECKED for 0

and assuming, of course, you have an bitmap array for the listctrl?

Otherwise, just setText() with 1 or 0, or Yes or No, etc ?


Glenn Dodd(Posted 2008) [#18]
i spent about an hour last night checking this.
I realised the values were constants but when i went looking for what numbers they should be (i even read the source code) i was looking for IMG_CHECKED when i should have been looking for SetImage().
My only excuse is it was midnight and i have had 6am starts all week, so i was fairly knackered :)


Glenn Dodd(Posted 2008) [#19]
Here is a working example of the ListCtrl with some comments.
Use the ListCtrlTestGUI.bmx from the third post

Thanks to Brucey and David for their help.

Cheers
Glenn




DavidDC(Posted 2008) [#20]
Glad you've got it all working Glenn. The wxListCtrl interface is pretty convoluted - but you get a fair bit of power for your trouble. I would add that you don't need to redo the column headings every Populate() if they haven't changed. If you want to keep the column headers, use DeleteAllItems() to clear the list control instead of ClearAll().


Glenn Dodd(Posted 2008) [#21]
cheers


Glenn Dodd(Posted 2008) [#22]
I have just modified the GUI file so it will stretch if you widen the window.
I using the following code to set the column headers



i would like the Task Name column to stretch to fill the gap as the window widens.
is there a way to do this?
I could get the listctrl width, subtract the other column widths and redefine MainTask width, assuming the ListCtrl itself has a width value that i can get, but it seems a bit "hacky" to me.

Cheers
Glenn


Glenn Dodd(Posted 2008) [#23]
hmmm i can't see a width command for the listctrl, only the columns...


DavidDC(Posted 2008) [#24]
does this work?

SetColumnWidth(col, wxLIST_AUTOSIZE )


DavidDC(Posted 2008) [#25]
wxListCtrl ultimately extends wxWindow so GetRect() should work I think?


Brucey(Posted 2008) [#26]
does this work?

SetColumnWidth(col, wxLIST_AUTOSIZE )

Not on Mac, I think.. or maybe I was trying to set it during the column creation instead rather... Hmm.


Glenn Dodd(Posted 2008) [#27]
SetColumnWidth(col, wxLIST_AUTOSIZE ) seems to autosize to the contents (not that i have any in their yet - so it becomes very narrow).

Method GetRect(x:Int Var, y:Int Var, w:Int Var, h:Int Var) has these parameters

Local i:int = Self.GetRect(ListControl) ' this is wrong
what should it be?
ListControl is the name of my listctrl


Brucey(Posted 2008) [#28]
There are two GetRect methods...
The one you mention, takes a list of ints, which are then populated with values (note the "Int Var" declarations).

The other, GetRectRect(), returns a wxRect object, which carries the same detail, but in a single Type.


Glenn Dodd(Posted 2008) [#29]
Method SetColumnHeadings(ListControl:wxListCtrl)

Select ListControl
Case m_listCtrlDue

Case m_listCtrlMainTask
ListControl.InsertColumn(0, ("TM"), wxLIST_FORMAT_LEFT, 30) ' Team Member Initials
ListControl.InsertColumn(1, ("Created"), wxLIST_FORMAT_LEFT, cListCtrlDateWidth)
ListControl.InsertColumn(2, ("Due Date"), wxLIST_FORMAT_LEFT, cListCtrlDateWidth)
ListControl.InsertColumn(3, ("Completed"), wxLIST_FORMAT_LEFT, cListCtrlDateWidth)
ListControl.InsertColumn(4, ("Cancelled"), wxLIST_FORMAT_CENTRE, cListCtrlDateWidth)
' ListControl.InsertColumn(5, ("Task Name"), wxLIST_FORMAT_LEFT,200)
ListControl.InsertColumn(5, ("Task Name"), wxLIST_FORMAT_LEFT,wxLIST_AUTOSIZE)
DebugStop
Local o:Object = ListControl.GetRectRect()
Local i:Int = o.width
'ListControl.SetColumnWidth(5, wxLIST_AUTOSIZE )
Case m_listCtrlSubTask

Default
DebugLog "You have passed a ListCtrl that doesn't exist"
End Select

End Method



Local i:Int = o.width is not liked.
How do i get the field from an object without knowing the field names?


Brucey(Posted 2008) [#30]
How's about :

Local rect:wxRect = ListControl.GetRectRect()

Some of wxRect's methods :
wxRect::GetBottom
wxRect::GetHeight
wxRect::GetLeft
wxRect::GetPosition
wxRect::GetTopLeft
wxRect::GetTopRight
wxRect::GetBottomLeft
wxRect::GetBottomRight
wxRect::GetRight
wxRect::GetSize
wxRect::GetTop
wxRect::GetWidth
wxRect::GetX
wxRect::GetY
wxRect::Inflate
wxRect::Intersects
wxRect::IsEmpty


:-)


Glenn Dodd(Posted 2008) [#31]
ahh.
learn something new every day.
how might i have found that information? where in the help would it be?


DavidDC(Posted 2008) [#32]
page 392 of the wxWidgetsPrgramming pdf would have been a good start. (Cross-Platform GUI Programming with wxWidgets)

Also wx.mod >> wx.mod >> doc >> Commands.html


Glenn Dodd(Posted 2008) [#33]
guess i am going to need to reread chapter 13 then.
Thanks


DavidDC(Posted 2008) [#34]
What I do is label and bookmark all the main wxMax commands.html's in a "wxMax" Firefox bookmarks folder. Makes it easy then to have lots of quick ref pages ready in different tabs.

Generally, if you can't find the type you are after in the main directory list of wxmax then look in the "core" wx.mod >> wx.mod.


Brucey(Posted 2008) [#35]
or, Build Modules, then in the navigator choose, Help ->Third Party Modules -> wx.wx

It's listed in the Types summary.

:o)


DavidDC(Posted 2008) [#36]
Or type "wxRect" in the IDE, highlight and press F1. But that would be too easy :-)


Brucey(Posted 2008) [#37]
*much too easy* :-p


Glenn Dodd(Posted 2008) [#38]
too easy - but first i had to know about wxRect...
Actually i use Help -> Third Party Modules all the time.
i have a bookmark to here too: http://www.wxwidgets.org/manuals/2.8.7/

now i am figuring out how to update the column size on a SizeEvent for the frame.
just need to spend a bit more time then i will post a sample program again.


cheers guys


Glenn Dodd(Posted 2008) [#39]
I have changed the example to allow for the Last column to resize to the maximum length to fit the ListCtrl while the window is being resized.
There is a refreshed GUI file too.

ListCtrlTestGUI.bmx



ListCtrlTest.bmx


I have asked Brucey if there is better way to do this, even though this works fine.

Cheers
Glenn


Brucey(Posted 2008) [#40]
You need to have this in your ChangeColumnWidth() method :
		If ListControl.GetColumnCount() > 0 Then
			ListControl.SetColumnWidth(4,ListWidth - (20 + 140 + 120 + 40))
		End If

to stop it crashing on Mac.

Seems on Mac there's a resize event before you get to add the columns.


DavidDC(Posted 2008) [#41]
I'm not a fan of that row of column width constants - especially the +3

How about:

	Method GetColumnWidth:Int(_list_control:wxListCtrl,_col:Int)
	
		Local width:Int
	
		For Local column:Int = 0 Until _list_control.GetColumnCount()
			If column <> _col Then width :+ _list_control.GetColumnWidth(column)
		Next
		
		If width 
			Local listbox_width:Int
			Local dummy:Int
			_list_control.GetClientSize(listbox_width,dummy)
			width = Max(0,listbox_width - width)
		EndIf
		
		Return width
	
	End Method


And calling with

ListControl.SetColumnWidth(4,GetColumnWidth(ListControl,4))


That said, I probably would have extended the wxListCtrl and placed this code in there, to prevent all this ListControl argument passing.