Towards a Richer GUI: The TabControl, Splitter & the PictureBox

IronPython & Windows Forms, Part XI

Note This is part of a series of tutorials on using IronPython with Windows Forms.

Introduction In this tutorial series so far we have covered some basic controls and background issues like setting attributes and GUI layout. In this article we'll be looking at a few more sophisticated controls. Like much of the Windows Forms API, this can be done with remarkably little and clear code. It almost feels Pythonic. Unlike normal Python programming style, the dotnet convention is to create controls with an empty constructor and then set properties on the control.

Boiler Plate Like previous entries we're going to need some boilerplate to create the form and start the application loop. To refresh your memory we'll start with the boilerplate : import clr

clr . AddReference ( 'System.Windows.Forms' )



from System . Windows . Forms import Application , Form



class MainForm ( Form ) :



def __init__ ( self ) :

Form . __init__ ( self )

self . Show ( )



Application . EnableVisualStyles ( )

form = MainForm ( )

Application . Run ( form ) All this does is create and show a form.

The PictureBox In order to illustrate the TabControl we'll display images in different tabs. To do this we'll use the PictureBox Class. We'll need the PictureBoxSizeMode Enumeration, this tells the PictureBox how to position the image. In order to provide the image, we'll need the Image Class and its FromFile method. The Image class lives in the System.Drawing assembly. The bare code will look something like : import clr

clr . AddReference ( 'System.Windows.Forms' )

clr . AddReference ( 'System.Drawing' )



from System . Windows . Forms import PictureBox , PictureBoxSizeMode

from System . Drawing import Image



image = Image . FromFile ( pathToFile )

pictureBox = PictureBox ( )

pictureBox . SizeMode = PictureBoxSizeMode . StretchImage

pictureBox . Image = image We'll be using DockStyle.Fill to make the picturebox fill its parent control. This makes the full code : import clr

clr . AddReference ( 'System.Windows.Forms' )

clr . AddReference ( 'System.Drawing' )



from System . Windows . Forms import (

Application , DockStyle , Form , PictureBox , PictureBoxSizeMode

)

from System . Drawing import Image



pathToFile = 'images/greenlake.jpg'



class MainForm ( Form ) :



def __init__ ( self ) :

Form . __init__ ( self )

image = Image . FromFile ( pathToFile )

pictureBox = PictureBox ( )

pictureBox . SizeMode = PictureBoxSizeMode . StretchImage

pictureBox . Image = image

pictureBox . Dock = DockStyle . Fill



self . Controls . Add ( pictureBox )



self . Show ( )



Application . EnableVisualStyles ( )

form = MainForm ( )

Application . Run ( form ) Using the greenlake image, this results in : Because we set DockStyle.Fill and PictureBoxSizeMode.StretchImage resizing is handled automatically.

The TabControl TabControls allow you to reduce the complexity of GUIs by dividing it into several pages that can be selected by clicking on the tabs. The TabControl is the container into which you place multiple TabPages. The TabPage itself is an empty container control into which you can place more GUI components. The order of the tab pages in the TabControl.TabPages collection reflects the order of tabs in the TabControl control. To change the order of tabs in the control, you must change their positions in the collection by removing them and inserting them at new indexes. The tabs are part of the TabControl , but you set the text on them by setting the Text property on the TabPage . The TabPages property is a TabPageCollection which has such useful methods as Add , Clear , Remove and Insert . You set the location of the tabs using the Alignment Property on the TabControl and the TabAlignment enumeration. Assuming we have already initialised a PictureBox , the code to create a TabControl and add a TabPage containing the image looks like this : tabControl = TabControl ( )

tabControl . Dock = DockStyle . Fill

tabControl . Alignment = TabAlignment . Bottom



tabPage = TabPage ( )

tabPage . Text = 'SomeImage'

tabPage . Controls . Add ( pictureBox )



tabControl . TabPages . Add ( tabPage )

The SplitContainer The SplitContainer is another control which, when used in the right place, can greatly augment an HCI . A splitter divides an area of a GUI into two parts, with a draggable bar that divides them. It can be a vertical bar or a horizontal bar depending on the Orientation you set (Using the Orientation Enumeration). You can set controls in the two panels it contains with the Panel1 and Panel2 properties. We'll spice up the GUI in our example by having two tabcontrols dividedby the split container. If we setup a method called setupPanel to add a TabControl to a panel, then setting up a splitter is very simple : self . image1 = Image . FromFile ( pathToFile1 )

self . image2 = Image . FromFile ( pathToFile2 )



splitter = SplitContainer ( )

splitter . Orientation = Orientation . Vertical

splitter . Dock = DockStyle . Fill



self . setupPanel ( splitter . Panel1 , self . image1 )

self . setupPanel ( splitter . Panel2 , self . image2 )

self . Controls . Add ( splitter ) Like any other control, we can handle events on the SplitContainer . Lets add some fun by changing the orientation of the splitter on a double click. The event we need is DoubleClick. In case you've forgotten how to use dot net events from IronPython, we define a function or method which takes sender and event arguments. We then add in place ( += ) it to the event on the control. The sender is the control that caused the event. def SwapOrientation ( sender , event ) :

if sender . Orientation == Orientation . Vertical :

sender . Orientation = Orientation . Horizontal

else :

sender . Orientation = Orientation . Vertical



splitter . DoubleClick += SwapOrientation