Difference between revisions of "Tutorial:LuaFormListView"
m (→Add Data For New Columns) |
m |
||
Line 79: | Line 79: | ||
[[File:TutorialListViewMoreColumnsData.png||ListView Add More Columns|border]] | [[File:TutorialListViewMoreColumnsData.png||ListView Add More Columns|border]] | ||
+ | |||
+ | == Using OwnerData == | ||
+ | |||
+ | What if you have a LOT of items you want to display? There's overhead with creating the items and I couldn't get BeginUpdate/EndUpdate to work. That's where the '''OwnerData''' property comes in! Check the '''OwnerData''' | ||
+ | property of the ListView to make it True. Change the Object Inspector tab from Properties to Events and double-click | ||
+ | on the OnData property to create an event handler. Now I'll change the table script to look like this and run it: | ||
+ | |||
+ | <pre>-- items | ||
+ | list = {} | ||
+ | for i=1,1000000 do | ||
+ | local item = { | ||
+ | message = string.format('Message %d', i), | ||
+ | data = math.sqrt(i) | ||
+ | } | ||
+ | table.insert(list, item) | ||
+ | end | ||
+ | |||
+ | -- need to set the Items.Count property so that it knows how many rows there | ||
+ | -- are in total | ||
+ | UDF1.CEListView1.Items.Count = #list | ||
+ | |||
+ | -- definition created by double-clicking OnData event handler | ||
+ | function CEListView1Data(sender, listitem) | ||
+ | -- use + 1 because listitem.Index is 0-based | ||
+ | local d = list[listitem.Index + 1] | ||
+ | if not d then return end | ||
+ | listitem.Caption = d.message -- first column | ||
+ | -- other columns have sqrt of data property and CURRENT clock | ||
+ | -- when this event was called | ||
+ | local others = {string.format('%0.3f', math.sqrt(d.data)), os.clock()} | ||
+ | listitem.SubItems.text = table.concat(others, '\n') | ||
+ | end</pre> | ||
+ | |||
+ | So we set '''UDF1.CEListView1.Items.Count''' to the number of items the ListView | ||
+ | should display. The OnData event handler will be called for each ''displayed'' | ||
+ | row. When the displayed row changes, the method is called again. This way | ||
+ | it is called just for the visible rows in the control. | ||
+ | |||
+ | You can tell it's getting called by scrolling down one row then back up, | ||
+ | the 'Clock' column value will change. If you resize the form (and have | ||
+ | the anchors set so the ListView will resize) then they all change. You | ||
+ | can also see it when selecting or deselecting rows because it needs to be | ||
+ | redrawn. | ||
+ | |||
+ | [[File:TutorialListViewOwnerData.png||ListView Add More Columns|border]] |
Revision as of 04:09, 23 July 2018
This will be concentrating on the ListView control, check out this tutorial to learn more about working with forms in general.
Contents
Initial Setup
The Form
To get started create a form with Table->Create form, this generated a UDF1 form for me. Now click the ListView button and drag an area on the form to set its extends.
In the properties change the ViewStyle to vsReport, this gives us a normal view with rows and columns. Also change ReadOnly to true because we won't allow editing, and RowSelect to true so clicking will select an entire row instead of just one column value:
Adding a Column
Now let's add a column. Click on the Columns property and the '...' to the right to open the column editor and click 'Add' to add a new column. Here I set the Caption of the column to 'Message' and changed the Width from 50 to 200. You can also change the width by dragging the column separator on the design form.
Add Items
Now close design mode by clicking the X on the top right of the toolbar window and the form will display in normal mode. Execute this code:
local items = UDF1.CEListView1.Items items.Clear() local item = items.Add() item.Caption = "First item" item = items.Add() item.Caption = "Second item"
That will clear the list and add a couple of items that you can see:
Adding More Columns
Now I'll go back to the properties of CEListView1 and click on the '...' in the Columns property to open the column editor and click Add to add a couple of more columns and edit their Caption properties to be Extra and Clock.
Add Data For New Columns
A TListItem has the value for the first column in the Caption property. The data for other columns is stored in the SubItems property as a Strings object. I find it easiest to update by setting the 'Text' property to a list of strings with linebreaks. You can use table.concat(<table>,'\n') to do this for a LUA array and it'll call tostring() on the values.
local items = UDF1.CEListView1.Items items.Clear() local item = items.Add() item.Caption = "First item" item.SubItems.text = "Hello\n"..tostring(os.clock()) item = items.Add() item.Caption = "Second item" item.SubItems.text = table.concat({"World",os.clock()}, '\n')
Using OwnerData
What if you have a LOT of items you want to display? There's overhead with creating the items and I couldn't get BeginUpdate/EndUpdate to work. That's where the OwnerData property comes in! Check the OwnerData property of the ListView to make it True. Change the Object Inspector tab from Properties to Events and double-click on the OnData property to create an event handler. Now I'll change the table script to look like this and run it:
-- items list = {} for i=1,1000000 do local item = { message = string.format('Message %d', i), data = math.sqrt(i) } table.insert(list, item) end -- need to set the Items.Count property so that it knows how many rows there -- are in total UDF1.CEListView1.Items.Count = #list -- definition created by double-clicking OnData event handler function CEListView1Data(sender, listitem) -- use + 1 because listitem.Index is 0-based local d = list[listitem.Index + 1] if not d then return end listitem.Caption = d.message -- first column -- other columns have sqrt of data property and CURRENT clock -- when this event was called local others = {string.format('%0.3f', math.sqrt(d.data)), os.clock()} listitem.SubItems.text = table.concat(others, '\n') end
So we set UDF1.CEListView1.Items.Count to the number of items the ListView should display. The OnData event handler will be called for each displayed row. When the displayed row changes, the method is called again. This way it is called just for the visible rows in the control.
You can tell it's getting called by scrolling down one row then back up, the 'Clock' column value will change. If you resize the form (and have the anchors set so the ListView will resize) then they all change. You can also see it when selecting or deselecting rows because it needs to be redrawn.