【问题标题】:GUI development with IronPython and Visual Studio 2010使用 IronPython 和 Visual Studio 2010 进行 GUI 开发
【发布时间】:2011-05-02 05:44:06
【问题描述】:

我正在教授一门关于使用 Python 进行编程和 GUI 开发的入门课程,并且发现对于刚接触编程的学生来说,最不压倒性的解决方案是使用 Visual Studio 进行 GUI 开发。

虽然使用 C# 和 VB 的 GUI 开发体验很愉快,但我找不到使用 IronPython 的方法。我安装了包含 Visual Studio 工具的 IronPython 2.7.1,并创建了一个 WPF IronPython 项目。

我可以像 VB 和 C# 一样使用 WPF 表单设计器,但是,我找不到可以访问 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())

我注意到,当我尝试手动修改 XAML 以命名元素时,GUI 元素没有获得名称并且 Visual Studio 崩溃。这是为带有按钮和文本区域的简单框架生成的 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 GUI 开发的建议,这些建议提供类似于 Visual Studio 的体验。

【问题讨论】:

  • 我发现将 PyQt4 与 Qt Designer 一起使用(对我而言)比使用 Visual Studio 容易得多,因为它轻量且简单。我尝试了几年 Visual Studio,但它非常臃肿。

标签: python visual-studio-2010 user-interface ironpython


【解决方案1】:

在 IronPython 2.7 中,wpf.LoadComponent 方法将连接任何与 XAML UI 元素同名的属性。如果您使用的是 IronPython 2.6,那么您需要使用 WombatPM 建议的代码。因此,如果您使用以下 XAML,请使用 IronPython 2.7:

<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 来访问 UI 元素:

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'

不幸的是,正如您所见,当您尝试编辑 XAML 并为 UI 元素命名时,Visual Studio 似乎崩溃并出现空引用异常。

【讨论】:

  • 这个答案是正确的。崩溃听起来像是一个错误,我很高兴在 Python Tools for Visual Studio (pythontools.codeplex.com) 中修复它。我为此打开了一个错误-pytools.codeplex.com/workitem/158,我将在那里修复它或确保它不会重现。一般来说,我建议使用 PTVS 而不是 IronPython 2.7 的内置工具,因为它们在这一点上得到了更积极的维护(所以我们通常会很快修复错误)。
  • 我无法重现与 PTVS 相关的问题,因此它看起来已修复(或者我需要更多关于您更改名称的具体操作的信息 - 我用 x 进行了尝试:名称、名称和通过 UI 进行编辑)。一种可能性是这是 IpyTools 的旧版本,因为我确实记得那里有一些崩溃的错误,这些错误后来得到了修复。
  • 只有在使用 IronPython 2.7 安装程序附带的 Visual Studio 工具为 x:Name 属性键入名称时才会出现此问题。 Python 工具没问题。我在使用 Python 工具时遇到的唯一问题是我无法运行 WPF 应用程序。看起来它无法导入 wpf 库。
【解决方案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

【讨论】:

    猜你喜欢
    • 2012-07-08
    • 2012-05-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多