GUI development with IronPython and Visual Studio 2010

pinstruct picture pinstruct · May 2, 2011 · Viewed 22.6k times · Source

I'm teaching an introductory class to programming and GUI development using Python, and have found that the least overwhelming solution for students new to programming is to use Visual Studio for GUI development.

While the GUI development experience with C# and VB is pleasant, I couldn't find a way to do the same with IronPython. I installed IronPython 2.7.1 which includes the Visual Studio tools, and created a WPF IronPython project.

I can use the WPF form designer just like VB and C#, however, I couldn't find a convenient way (i.e., comprehensible to the students) in which the GUI elements could be accessed. For example, with VB, you can refer to elements based on their name and then you can modify properties within them. The best I could do with IronPython (which I don't plan to show to the students) is the following:

import wpf

from System.Windows import Application, Window

class MyWindow(Window):
    def __init__(self):
        wpf.LoadComponent(self, 'WpfApplication3.xaml')

    def Button_Click(self, sender, e):
        #This is the only way I could find in which I can 
        #access an element and modify its properties
        self.Content.Children[1].Text += 'Hello World\n'


if __name__ == '__main__':
    Application().Run(MyWindow())

I noticed that the GUI elements do not get a name and Visual Studio crashes whenever I try to manually modify the XAML to name elements. Here is the generated XAML for a simple frame with a button and text area:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="WpfApplication3" Height="300" Width="300"> 
    <Grid>
        <Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="103,226,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click" />
        <TextBox Height="182" HorizontalAlignment="Left" Margin="24,21,0,0" VerticalAlignment="Top" Width="237" />
    </Grid>
</Window> 

Any assistance in making this easier on the students would be appreciated. I'm also open to other suggestions for Python GUI development which offer an experience similar to Visual Studio.

Answer

Matt Ward picture Matt Ward · May 2, 2011

In IronPython 2.7 the wpf.LoadComponent method will wire up any properties with the same name as the XAML UI elements. If you are using IronPython 2.6 then you would need to use the code as suggested by WombatPM. So with IronPython 2.7 if you use the following XAML:

<Window 
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       Title="IronPyWpf" Height="300" Width="300">
    <Grid>
        <Button x:Name="button" Content="Button" Height="23" HorizontalAlignment="Left" Margin="103,226,0,0" VerticalAlignment="Top" Width="75"  />
        <TextBox x:Name="textbox" Height="182" HorizontalAlignment="Left" Margin="24,21,0,0" VerticalAlignment="Top" Width="237" />
    </Grid>
</Window> 

Then you can define two properties called button and textbox to access the UI elements:

class MyWindow(Window):
    def __init__(self):
        wpf.LoadComponent(self, 'IronPyWpf.xaml')
        self._button.Content = 'My Button'
        self._textbox.Text = 'My Text'

    def get_button(self):
        return self._button

    def set_button(self, value):
        self._button = value

    button = property(get_button, set_button)

    def get_textbox(self):
        return self._textbox

    def set_textbox(self, value):
        self._textbox = value

    textbox = property(get_textbox, set_textbox)

In fact it seems that you can simplify the code even further by removing the property definitions:

class MyWindow(Window):
    def __init__(self):
        wpf.LoadComponent(self, 'IronPyWpf.xaml')
        self.button.Content = 'My Button'
        self.textbox.Text = 'My Text'

Unfortunately Visual Studio seems to crash, as you have already seen, with a null reference exception when you try to edit the XAML and give the UI elements a name.