Разработка графического интерфейса с IronPython и Visual Studio 2010

Я преподаю вводный класс для программирования и разработки графического интерфейса с использованием Python и нашел, что наименее подавляющее решение для новых студентов для программирования - использовать Visual Studio для разработки графического интерфейса.

В то время как опыт разработки графического интерфейса с С# и VB приятный, я не мог найти способ сделать то же самое с IronPython. Я установил IronPython 2.7.1, который включает инструменты Visual Studio, и создал проект WPF IronPython.

Я могу использовать конструктор форм WPF так же, как VB и С#, однако я не мог найти удобный способ (то есть понятный для студентов), в котором могли бы быть доступны элементы GUI. Например, с помощью VB вы можете ссылаться на элементы, основанные на их имени, а затем вы можете изменять свойства внутри них. Лучшее, что я мог сделать с IronPython (которое я не планирую показывать студентам), следующее:

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())

Я заметил, что элементы GUI не получают имя и сбой Visual Studio, когда я пытаюсь вручную модифицировать XAML для обозначения элементов. Вот сгенерированный XAML для простого кадра с кнопкой и текстовой областью:

<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> 

Любая помощь в облегчении этого для студентов будет оценена по достоинству. Я также открыт для других предложений для разработки графического интерфейса Python, которые предлагают опыт, похожий на Visual Studio.

Ответы

Ответ 1

В IronPython 2.7 метод wpf.LoadComponent подключит любые свойства с тем же именем, что и элементы интерфейса XAML. Если вы используете IronPython 2.6, вам нужно будет использовать код, предложенный WombatPM. Итак, с IronPython 2.7, если вы используете следующий 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> 

Затем вы можете определить два свойства с именем button и textbox для доступа к элементам пользовательского интерфейса:

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)

На самом деле кажется, что вы еще более упростите код, удалив определения свойств:

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

К сожалению, Visual Studio, похоже, сбой, как вы уже видели, с ошибкой нулевой ссылки, когда вы пытаетесь отредактировать XAML и дать элементам UI имя.

Ответ 2

Вам нужно пройти все объекты и создать более простые/понятные ссылки, используя такую ​​функцию.

#
# Waddle returns a dictionary of Control types e.g. listbox, Button.
# Each Entry is a dictionary of Control Instance Names i.e.
# controls['Button']['NewSite'] returns the button control named NewSite
# Controls should have Unique names and only those with a Name attrib set
# will be included.
#
def Waddle(c, d):
    s = str(c.__class__)
    if "System.Windows.Controls." in str(c) and hasattr(c,"Name") and c.Name.Length>0:
        ControlType = s[s.find("'")+1:s.rfind("'")]
        if ControlType not in d:
            d[ControlType] = {}
        d[ControlType][c.Name] = c
    if hasattr(c,"Children"):
        for cc in c.Children:
            Waddle(cc, d)
    elif hasattr(c,"Child"):
        Waddle(c.Child, d)
    elif hasattr(c,"Content"):
        Waddle(c.Content, d)
if __name__ == "__main__":
    xr = XmlReader.Create(StringReader(xaml))
    win = XamlReader.Load(xr)

    controls = {}
    Waddle(win, controls)

    #Make all Named buttons do something!
    for butt in controls['Button']:
        controls['Button'][butt].Click += sayhello

    #Make one button do something.
    controls['Button']['NewSite'].Click += sayhello2
    Application().Run(win)

См. http://www.ironpython.info/index.php/XAML_GUI_Events_Example для приведенного выше кода и полный пример.