Oh I see now. That makes sense.
I was trying each possible way and was overlooking that the index stared at 0. Thanks Lo for the explanation on everything.
So this is what I have so far, it does everything I wanted it do do.
If you see any improvements I’d love to hear them.
One that i notice is the Activate and Deactivate could be condensed into a function, which I’ll do next.
As for any of the dotNet stuff it seems good.
I’ll have to figure out a way to get the seletion thing working like described above, it does not work for me to do a drag selection.
Corky thing I noticed is the text changes font types if you select it all and hit deactivate from the start. Other than that it seems great.
try(destroydialog ::rlListView)catch()
rollout rlListView "Listview"
(
-- This is array holds the content for our Listview items. An oversimplification, probably.
local _itemsArr = for i = 1 to 10 collect "Item "+ i as string
local activeFont = dotNetObject "System.Drawing.Font" "Microsoft Sans Serif" 11 (dotNetClass "System.Drawing.FontStyle").Bold (dotNetClass "System.Drawing.GraphicsUnit").Pixel
local inactiveFont = dotNetObject "System.Drawing.Font" "Microsoft Sans Serif" 11 (dotNetClass "System.Drawing.FontStyle").Regular (dotNetClass "System.Drawing.GraphicsUnit").Pixel
--pickbutton pbtnSourceObj "Source Object" pos:[10,10] width:180 height:20
dotNetControl lvTracks "System.Windows.Forms.ListView" width:180 height:220 pos:[10,40]
button btnActivate "Activate" width:90 height:20 pos:[10,10]
button btnDeactivate "Deactivate" width:90 height:20 pos:[100,10]
fn fnListviewTracksSetup = (
lvTracks.clear() -- wipe out the contents of the entire listview so that we're redrawing it from scratch each time this function is called
lvTracks.View = (dotNetClass "System.Windows.Forms.View").Details -- this is what allows the grid-like format to be used
lvTracks.fullRowSelect = true -- When item is clicked, all columns in that item are selected
lvTracks.gridLines = true-- turn on the grid lines
lvTracks.HideSelection= false -- When this ListView loses the focus, it will still show what's selected
lvTracks.BorderStyle=lvTracks.BorderStyle.FixedSingle -- make the border a flat solid color instead of the Windows 3D look
lvTracks.HeaderStyle=lvTracks.HeaderStyle.Nonclickable -- Flattens the headers a bit (although they're still somewhat 3D) and keeps them from being clickable
lvTracks.backColor=lvTracks.backColor.FromArgb 250 250 250 -- Soften the background intensity a bit
lvTracks.Columns.add "Tracks" 180 -- create a couple of columns and optionally specify their width
-- Create the items that will go in the list view
lvTracks.Items.AddRange (for i in _itemsArr collect (dotNetObject "ListViewItem" i))
for i = 1 to (lvTracks.Items.count) do
(
itm = lvTracks.Items.Item[i-1]
itm.tag = false
)
)
on btnActivate pressed do
(
_arr = lvTracks.SelectedIndices
_selIdxs = for i = 1 to _arr.count collect _arr.item[i-1] --need the i-1 because the collection is 0-based.
--print _selIdxs --note that the returned indices are also 0-based because the .items of the listview are also a dotnet collection!
for i = 1 to _selIdxs.count do
(
idx = _selIdxs[i]
lvTracks.Items.item[idx].Font = activeFont
lvTracks.Items.item[idx].Tag = true
)
)
on btnDeactivate pressed do
(
_arr = lvTracks.SelectedIndices
_selIdxs = for i = 1 to _arr.count collect _arr.item[i-1] --need the i-1 because the collection is 0-based.
--print _selIdxs --note that the returned indices are also 0-based because the .items of the listview are also a dotnet collection!
for i = 1 to _selIdxs.count do
(
idx = _selIdxs[i]
lvTracks.Items.item[idx].Font = inactiveFont
lvTracks.Items.item[idx].Tag = false
)
)
on lvTracks MouseDoubleClick s a do
(
itm = s.GetItemAt a.x a.y
if itm != undefined do
(
trackName = itm.text
idx = (itm.Index + 1) --dotnet lists start with 0
if itm.tag == false then
(
itm.font = activeFont -- bold font
itm.tag = true
)else(
itm.font = inactiveFont -- regular font
itm.tag = false
)
)
)
on rlListView open do
(
fnListviewTracksSetup()
)
)
createdialog rlListView 200 270
I see what you’ve done there. That makes sense. It was redundant and long for no reason.
This is all the code you need for drag-selection:
local mouseIsDown = off
on lvTracks mouseDown s a do mouseIsDown = on
on lvTracks mouseUp s a do mouseIsDown = off
on lvTracks mouseMove s a do
(
if mouseIsDown and (local item = s.GetItemAt a.x a.y) != undefined do item.selected = on
)
Wow, that was quick.
I was searching around and trying to figure that out and was not in the relm of the same results. I appreciate the time you’ve spent helping me out on this Rotem. I’ve sure picked up a handful of things with your help.
Is the focus a bug?
I select multiple items in the listview and then click outside of that and they are appear unselected. How can I keep them appearing as if they are selected (blue highlight)
Works!
Sadly i lose the styling of the header though. And it flickers a little bit.
try(destroydialog ::rlListView)catch()
rollout rlListView "Listview"
(
-- This is array holds the content for our Listview items. An oversimplification, probably.
local _itemsArr = for i = 1 to 10 collect "Item "+ i as string
local mouseIsDown = off
local activeFont = dotNetObject "System.Drawing.Font" "Microsoft Sans Serif" 11 (dotNetClass "System.Drawing.FontStyle").Bold (dotNetClass "System.Drawing.GraphicsUnit").Pixel
local inactiveFont = dotNetObject "System.Drawing.Font" "Microsoft Sans Serif" 11 (dotNetClass "System.Drawing.FontStyle").Regular (dotNetClass "System.Drawing.GraphicsUnit").Pixel
local selColor = (dotNetClass "System.Drawing.Color").fromARGB 238 204 85 -- custom selection color (orangey-yellow)
local lvBackColor = selColor.fromARGB 250 250 250
--pickbutton pbtnSourceObj "Source Object" pos:[10,10] width:180 height:20
dotNetControl lvTracks "System.Windows.Forms.ListView" width:180 height:220 pos:[10,40]
button btnActivate "Activate" width:90 height:20 pos:[10,10]
button btnDeactivate "Deactivate" width:90 height:20 pos:[100,10]
fn fnListviewTracksSetup = (
lvTracks.clear() -- wipe out the contents of the entire listview so that we're redrawing it from scratch each time this function is called
lvTracks.View = (dotNetClass "System.Windows.Forms.View").Details -- this is what allows the grid-like format to be used
lvTracks.OwnerDraw = true
lvTracks.fullRowSelect = true -- When item is clicked, all columns in that item are selected
lvTracks.gridLines = true-- turn on the grid lines
lvTracks.HideSelection= false -- When this ListView loses the focus, it will still show what's selected
lvTracks.BorderStyle=lvTracks.BorderStyle.FixedSingle -- make the border a flat solid color instead of the Windows 3D look
lvTracks.HeaderStyle=lvTracks.HeaderStyle.Nonclickable -- Flattens the headers a bit (although they're still somewhat 3D) and keeps them from being clickable
lvTracks.backColor=lvTracks.backColor.FromArgb 250 250 250 -- Soften the background intensity a bit
lvTracks.Columns.add "Tracks" 180 -- create a couple of columns and optionally specify their width
-- Create the items that will go in the list view
lvTracks.Items.AddRange (for i in _itemsArr collect (dotNetObject "ListViewItem" i))
for i = 1 to (lvTracks.Items.count) do
(
itm = lvTracks.Items.Item[i-1]
itm.tag = false
)
)
on lvTracks mouseDown s a do mouseIsDown = on
on lvTracks mouseUp s a do mouseIsDown = off
on lvTracks mouseMove s a do
(
if mouseIsDown and (local item = s.GetItemAt a.x a.y) != undefined do item.selected = on
)
on btnActivate pressed do
(
_arr = lvTracks.SelectedIndices
_selIdxs = for i = 1 to _arr.count collect _arr.item[i-1] --need the i-1 because the collection is 0-based.
--print _selIdxs --note that the returned indices are also 0-based because the .items of the listview are also a dotnet collection!
for i = 1 to _selIdxs.count do
(
idx = _selIdxs[i]
lvTracks.Items.item[idx].Font = activeFont
lvTracks.Items.item[idx].Tag = true
)
)
on btnDeactivate pressed do
(
_arr = lvTracks.SelectedIndices
_selIdxs = for i = 1 to _arr.count collect _arr.item[i-1] --need the i-1 because the collection is 0-based.
--print _selIdxs --note that the returned indices are also 0-based because the .items of the listview are also a dotnet collection!
for i = 1 to _selIdxs.count do
(
idx = _selIdxs[i]
lvTracks.Items.item[idx].Font = inactiveFont
lvTracks.Items.item[idx].Tag = false
)
)
on lvTracks MouseDoubleClick s a do
(
itm = s.GetItemAt a.x a.y
if itm != undefined do
(
print itm.text
itm.tag = if itm.tag != true then true else false
itm.font = if itm.tag then activeFont else inactiveFont
)
)
on rlListView open do
(
fnListviewTracksSetup()
)
-------selection color controls
on lvTracks ItemSelectionChanged arg do
(
arg.Item.BackColor = if arg.isSelected then selColor else lvBackColor
)
on lvTracks drawitem arg do
(
arg.DrawBackground()
arg.DrawText()
)
)
createdialog rlListView 200 270
For the column header you can add this:
on lvTracks DrawColumnHeader arg do
(
arg.DrawBackground()
arg.DrawText()
)
For the flickering, you might need to set double buffering for this control. I don’t know a way to do this without a small dynamically compiled c# assembly. Search this forum for Control.SetStyle
fn setDoubleBuffer control value:on =
(
type = control.GetType()
bf = dotnetclass "System.Reflection.BindingFlags"
flags = dotnet.combineEnums bf.NonPublic bf.Instance bf.InvokeMethod
cs = dotnetclass "ControlStyles"
styles = dotnet.combineEnums cs.DoubleBuffer cs.AllPaintingInWmPaint
-- styles = dotnet.combineEnums cs.DoubleBuffer cs.UserPaint cs.AllPaintingInWmPaint cs.Opaque
type.InvokeMember "SetStyle" flags type.DefaultBinder control #(styles, value)
value
)
/*
panel = dotnetobject "UserControl"
setDoubleBuffer panel
*/
Alright. I’ll look into it.
Thanks again for the help.
When Applying the draw text and style it causes a weird alignment in the column label? Why is that?
Here is what I’ve got so far.
try(destroydialog ::rlListView)catch()
rollout rlListView "Listview"
(
-- This is array holds the content for our Listview items. An oversimplification, probably.
local _itemsArr = for i = 1 to 10 collect "Item "+ i as string
local mouseIsDown = off
local activeFont = dotNetObject "System.Drawing.Font" "Microsoft Sans Serif" 11 (dotNetClass "System.Drawing.FontStyle").Bold (dotNetClass "System.Drawing.GraphicsUnit").Pixel
local inactiveFont = dotNetObject "System.Drawing.Font" "Microsoft Sans Serif" 11 (dotNetClass "System.Drawing.FontStyle").Regular (dotNetClass "System.Drawing.GraphicsUnit").Pixel
local selColor = (dotNetClass "System.Drawing.Color").fromARGB 238 204 85 -- custom selection color (orangey-yellow)
local lvBackColor = selColor.fromARGB 250 250 250
--pickbutton pbtnSourceObj "Source Object" pos:[10,10] width:180 height:20
dotNetControl lvTracks "System.Windows.Forms.ListView" width:180 height:220 pos:[10,40]
button btnActivate "Activate" width:90 height:20 pos:[10,10]
button btnDeactivate "Deactivate" width:90 height:20 pos:[100,10]
fn fnListviewTracksSetup = (
lvTracks.clear() -- wipe out the contents of the entire listview so that we're redrawing it from scratch each time this function is called
lvTracks.View = (dotNetClass "System.Windows.Forms.View").Details -- this is what allows the grid-like format to be used
lvTracks.OwnerDraw = true
lvTracks.fullRowSelect = true -- When item is clicked, all columns in that item are selected
lvTracks.gridLines = true-- turn on the grid lines
lvTracks.HideSelection= false -- When this ListView loses the focus, it will still show what's selected
lvTracks.BorderStyle=lvTracks.BorderStyle.FixedSingle -- make the border a flat solid color instead of the Windows 3D look
lvTracks.HeaderStyle=lvTracks.HeaderStyle.Nonclickable -- Flattens the headers a bit (although they're still somewhat 3D) and keeps them from being clickable
lvTracks.backColor=lvTracks.backColor.FromArgb 250 250 250 -- Soften the background intensity a bit
lvTracks.Columns.add "Tracks" 180 -- create a couple of columns and optionally specify their width
-- Create the items that will go in the list view
lvTracks.Items.AddRange (for i in _itemsArr collect (dotNetObject "ListViewItem" i))
for i = 1 to (lvTracks.Items.count) do
(
itm = lvTracks.Items.Item[i-1]
itm.tag = false
itm.font = inactiveFont
)
)
on lvTracks mouseDown s a do mouseIsDown = on
on lvTracks mouseUp s a do mouseIsDown = off
on lvTracks mouseMove s a do
(
if mouseIsDown and (local item = s.GetItemAt a.x a.y) != undefined do item.selected = on
)
on btnActivate pressed do
(
_arr = lvTracks.SelectedIndices
_selIdxs = for i = 1 to _arr.count collect _arr.item[i-1] --need the i-1 because the collection is 0-based.
--print _selIdxs --note that the returned indices are also 0-based because the .items of the listview are also a dotnet collection!
for i = 1 to _selIdxs.count do
(
idx = _selIdxs[i]
lvTracks.Items.item[idx].Font = activeFont
lvTracks.Items.item[idx].Tag = true
)
)
on btnDeactivate pressed do
(
_arr = lvTracks.SelectedIndices
_selIdxs = for i = 1 to _arr.count collect _arr.item[i-1] --need the i-1 because the collection is 0-based.
--print _selIdxs --note that the returned indices are also 0-based because the .items of the listview are also a dotnet collection!
for i = 1 to _selIdxs.count do
(
idx = _selIdxs[i]
lvTracks.Items.item[idx].Font = inactiveFont
lvTracks.Items.item[idx].Tag = false
)
)
on lvTracks MouseDoubleClick s a do
(
itm = s.GetItemAt a.x a.y
if itm != undefined do
(
print itm.text
itm.tag = if itm.tag != true then true else false
itm.font = if itm.tag then activeFont else inactiveFont
)
)
on rlListView open do
(
fnListviewTracksSetup()
)
-------selection color controls
on lvTracks ItemSelectionChanged arg do
(
arg.Item.BackColor = if arg.isSelected then selColor else lvBackColor
)
on lvTracks drawitem arg do
(
arg.DrawBackground()
arg.DrawText()
)
on lvTracks DrawColumnHeader s e do
(
e.DrawBackground()
e.DrawText()
--custom headers
if (dotnet.CompareEnums e.State e.State.Selected) then
(
e.Graphics.FillRectangle (dotnetclass "System.Drawing.Brushes").LightBlue e.Bounds
)
else
(
brush = dotnetobject "System.Drawing.Drawing2D.LinearGradientBrush" e.Bounds \
(dotnetclass "System.Drawing.Color").LightBlue \
(dotnetclass "System.Drawing.Color").DarkBlue \
(dotnetclass "System.Drawing.Drawing2D.LinearGradientMode").Vertical
e.Graphics.FillRectangle brush e.Bounds
)
flags = dotnet.combineEnums (dotnetclass "TextFormatFlags").HorizontalCenter (dotnetclass "TextFormatFlags").VerticalCenter
(dotnetclass "TextRenderer").DrawText e.Graphics e.Header.Text s.Font e.Bounds (dotnetclass "System.Drawing.Color").White flags
)
)
createdialog rlListView 200 270
Is is possible to make the header of a listview contain an action when clicked?
In my case I’m just wanting it to select all the items in the listview.
Simple Listview snippet
try(destroydialog ::ListviewBugTest)catch()
rollout ListviewBugTest ""
(
dotNetControl lv "System.Windows.Forms.ListView" width:250 height:150 align:#center pos:[10,10]
on ListviewBugTest open do
(
-- Setup the listview
lv.View = (dotNetClass "System.Windows.Forms.View").Details
lv.fullRowSelect = true
lv.Columns.add ("Column "+i as string)
-- Add items to listview
for x=1 to 5 do
(
local newItem = dotNetObject "System.Windows.Forms.ListViewItem" ("Col." + x as string)
lv.items.add newItem
)
)
)
createDialog ListviewBugTest 270 170
make the column header clickable by setting ColumnHeaderStyle.Clickable, and use the ListView.ColumnClick Event