Разработка графического интерфейса с 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 для приведенного выше кода и полный пример.