Home  Contents

Advanced Controls in Mono Winforms

In this part of the IronPython Mono Winforms tutorial, we introduce some more advanced controls. Namely the ListBox, the ListView and the TreeView control.

ListBox Control

The ListBox control is used to display a list of items. Users can select one or more items by clicking on them.

listbox.py
#!/usr/bin/ipy import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, StatusBar from System.Windows.Forms import ListBox, DockStyle from System.Drawing import Size class IForm(Form): def __init__(self): self.Text = "ListBox" lb = ListBox() lb.Parent = self lb.Items.Add("Jessica") lb.Items.Add("Rachel") lb.Items.Add("Angelina") lb.Items.Add("Amy") lb.Items.Add("Jennifer") lb.Items.Add("Scarlett") lb.Dock = DockStyle.Fill lb.SelectedIndexChanged += self.OnChanged self.sb = StatusBar() self.sb.Parent = self self.Size = Size(220, 220) self.CenterToScreen() def OnChanged(self, sender, event): self.sb.Text = sender.SelectedItem Application.Run(IForm())

Our example shows a listbox with six names. The selected item is shown in the statusbar.

 lb = ListBox()
 lb.Parent = self

ListBox control is created.

 lb.Items.Add("Jessica")

This is how we add a new item to the ListBox control. The control has the Items property. The property is a reference to the list of items in a listbox. Using this reference, we can add, remove or get count of items of the listbox.

 lb.SelectedIndexChanged += self.OnChanged

SelectedIndexChanged event is triggered, when we select an item.

 def OnChanged(self, sender, event):
     self.sb.Text = sender.SelectedItem

Inside the OnChange() method, we get selected value of the listbox and set it to the statusbar.


ListBox
Figure: ListBox

ListView

ListView control is used to display collections of items. It is a more sophisticated control than the ListBox control. It can display data in various views. It is mostly used to display data in multicolumn views.

listview.py
#!/usr/bin/ipy import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, StatusBar from System.Windows.Forms import ListView, View, ColumnHeader from System.Windows.Forms import ListViewItem, DockStyle, SortOrder from System.Drawing import Size class IForm(Form): def __init__(self): self.Text = 'ListBox' actresses = { 'Jessica Alba' : '1981', 'Angelina Jolie' : '1975', 'Natalie Portman' : '1981', 'Rachel Weiss' : '1971', 'Scarlett Johansson' : 1984 } name = ColumnHeader() name.Text = 'Name' name.Width = -1 year = ColumnHeader() year.Text = 'Year' self.SuspendLayout() lv = ListView() lv.Parent = self lv.FullRowSelect = True lv.GridLines = True lv.AllowColumnReorder = True lv.Sorting = SortOrder.Ascending lv.Columns.AddRange((name, year)) lv.ColumnClick += self.OnColumnClick for act in actresses.keys(): item = ListViewItem() item.Text = act item.SubItems.Add(str(actresses[act])) lv.Items.Add(item) lv.Dock = DockStyle.Fill lv.Click += self.OnChanged self.sb = StatusBar() self.sb.Parent = self lv.View = View.Details self.ResumeLayout() self.Size = Size(350, 300) self.CenterToScreen() def OnChanged(self, sender, event): name = sender.SelectedItems[0].SubItems[0].Text born = sender.SelectedItems[0].SubItems[1].Text self.sb.Text = name + ', ' + born def OnColumnClick(self, sender, event): if sender.Sorting == SortOrder.Ascending: sender.Sorting = SortOrder.Descending else: sender.Sorting = SortOrder.Ascending Application.Run(IForm())

In our example, we have a listview with two columns. In the first column, we display the name of the actress. In the second one their date of birth. The data is store in a List collection. By selecting a row, the data in a row is displayed in the statusbar. Also, by clicking on the column header, the data is sorted.

 actresses = { 'Jessica Alba' : '1981', 'Angelina Jolie' : '1975', 
     'Natalie Portman' : '1981', 'Rachel Weiss' : '1971', 
     'Scarlett Johansson' : 1984 }

We store our data in the actresses dictionary.

 name = ColumnHeader()
 name.Text = 'Name'
 name.Width = -1

For each column in a listview, we create a ColumnHeader. By setting the Width to -1, the width of the column is equal to the longest item in the column.

 lv = ListView()
 lv.Parent = self

ListView control is created.

 lv.FullRowSelect = True
 lv.GridLines = True
 lv.AllowColumnReorder = True
 lv.Sorting = SortOrder.Ascending

Here we set four properties of the control. This code lines enable full row selection, show grid lines, allow column reordering by dragging the columns and sort the data in ascending order.

 lv.Columns.AddRange((name, year))

Here we add two ColumnHeaders to the ListView control.

 for act in actresses.keys():
     item = ListViewItem()
     item.Text = act
     item.SubItems.Add(str(actresses[act]))
     lv.Items.Add(item)

This cycle populates the listview control. Each row is added to the listview as a ListViewItem class.

 lv.View = View.Details

The ListView control can have different views. Different views display data differently.

 name = sender.SelectedItems[0].SubItems[0].Text
 born = sender.SelectedItems[0].SubItems[1].Text
 self.sb.Text = name + ', ' + born

Inside the OnChanged() method, we get the data from the selected row and show it on the statusbar.

 if sender.Sorting == SortOrder.Ascending:
     sender.Sorting = SortOrder.Descending
 else: 
     sender.Sorting = SortOrder.Ascending

Here we toggle the sorting order of the column.


ListView
Figure: ListView

TreeView

TreeView control displays hierarchical collection of items. Each item in this control is represented by a TreeNode object.

treeview.py
#!/usr/bin/ipy import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, StatusBar from System.Windows.Forms import TreeView, TreeNode, DockStyle from System.Drawing import Size class IForm(Form): def __init__(self): self.Text = 'TreeView' tv = TreeView() root = TreeNode() root.Text = 'Languages' child1 = TreeNode() child1.Text = 'Python' child2 = TreeNode() child2.Text = 'Ruby' child3 = TreeNode() child3.Text = 'Java' root.Nodes.AddRange((child1, child2, child3)) tv.Parent = self tv.Nodes.Add(root) tv.Dock = DockStyle.Fill tv.AfterSelect += self.AfterSelect self.sb = StatusBar() self.sb.Parent = self self.Size = Size(220, 220) self.CenterToScreen() def AfterSelect(self, sender, event): self.sb.Text = event.Node.Text Application.Run(IForm())

This is a very simple demonstration of the TreeView control. We have one root item and three children.

 tv = TreeView()

We create the TreeView control.

 root = TreeNode()
 root.Text = 'Languages'
 ...
 tv.Nodes.Add(root)

Here we create a root node.

 child1 = TreeNode()
 child1.Text = 'Python'

Child node is created in a similar way.

 root.Nodes.AddRange((child1, child2, child3))

Child nodes are plugged into the Nodes property of the root node.


TreeView
Figure: TreeView

Directories

The following code example will examine the TreeView control more in-depth.

directories.py
#!/usr/bin/ipy import clr clr.AddReference("System.Windows.Forms") clr.AddReference("System.Drawing") from System.Windows.Forms import Application, Form, StatusBar from System.Windows.Forms import Button, TreeView, TreeNode from System.Windows.Forms import DockStyle, AnchorStyles from System.Drawing import Size, Point from System.IO import Directory, DirectoryInfo HOME_DIR = '/home/vronskij' class IForm(Form): def __init__(self): self.Text = 'Directories' self.Size = Size(400, 400) self.tv = TreeView() self.SuspendLayout() self.tv.Parent = self self.tv.Location = Point(10,10) self.tv.Size = Size(self.ClientSize.Width - 20, self.Height - 200) self.tv.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right self.tv.FullRowSelect = False self.tv.ShowLines = True self.tv.ShowPlusMinus = True self.tv.Scrollable = True self.tv.AfterSelect += self.AfterSelect expand = Button() expand.Parent = self expand.Location = Point(20, self.tv.Bottom + 20) expand.Text = 'Expand' expand.Anchor = AnchorStyles.Left | AnchorStyles.Top expand.Click += self.OnExpand expandAll = Button() expandAll.Parent = self expandAll.Location = Point(20, expand.Bottom + 5) expandAll.Text = 'Expand All' expandAll.Anchor = AnchorStyles.Left | AnchorStyles.Top expandAll.Click += self.OnExpandAll collapse = Button() collapse.Parent = self collapse.Location = Point(expandAll.Right + 5, expand.Top) collapse.Text = 'Collapse' collapse.Anchor = AnchorStyles.Left | AnchorStyles.Top collapse.Click += self.OnCollapse collapseAll = Button() collapseAll.Parent = self collapseAll.Location = Point(collapse.Left, collapse.Bottom + 5) collapseAll.Text = 'Collapse All' collapseAll.Anchor = AnchorStyles.Left | AnchorStyles.Top collapseAll.Click += self.OnCollapseAll self.sb = StatusBar() self.sb.Parent = self self.ShowDirectories(self.tv.Nodes, HOME_DIR) self.ResumeLayout() self.CenterToScreen() def AfterSelect(self, sender, event): self.sb.Text = event.Node.Text def ShowDirectories(self, trvNode, path): dirInfo = DirectoryInfo(path) if (dirInfo != None): subDirs = dirInfo.GetDirectories() tr = TreeNode(dirInfo.Name) if (subDirs.Length > 0): for dr in subDirs: if not dr.Name.StartsWith("."): self.ShowDirectories(tr.Nodes, dr.FullName) trvNode.Add(tr) def OnExpand(self, sender, event): self.tv.SelectedNode.Expand() def OnExpandAll(self, sender, event): self.tv.ExpandAll() def OnCollapse(self, sender, event): self.tv.SelectedNode.Collapse() def OnCollapseAll(self, sender, event): self.tv.CollapseAll() Application.Run(IForm())

Our code example shows the directories of the specified home directory in a TreeView control. The application starts with some delay, because it reads the directory structure of the home directory first. We have also four buttons on the form. The buttons expand and collapse nodes programatically.

 self.tv.Scrollable = True 

We make the treeview control scrollable, because the control shows lots of directories.

 self.ShowDirectories(self.tv.Nodes, HOME_DIR)

The ShowDirectories() method fills the nodes of the treview control with directories available in the specified home directory.

 if (subDirs.Length > 0):
     ...

We check if there are any subdirectories.

 for dr in subDirs: 
     if not dr.Name.StartsWith("."):
         self.ShowDirectories(tr.Nodes, dr.FullName)

We loop through all directories. For this, we use the recursion algorithm. We also skip the hidden directories. They begin with a dot on Unix systems.

 trvNode.Add(tr)     

This code line actually adds the directory to the treeview control.

 def OnExpand(self, sender, event):
     self.tv.SelectedNode.Expand()

All four buttons have events plugged to a method. Here is a method for the Expand button. It calls the Expand() method of the currently selected node.


Directories
Figure: Directories

In this part of the IronPython Mono Winforms tutorial, we covered several advanced controls available in Winforms programming library.