从wxPython Frame返回值

时间:2010-05-22 18:27:29

标签: python wxpython

有人能告诉我如何从wxPython Frame返回一个值吗?当用户点击关闭时,我会弹出一个消息对话框,询问他一个问题。我想将此消息对话框的返回代码返回给我的调用函数。

由于

8 个答案:

答案 0 :(得分:5)

因为wxFrame具有通过app.MainLoop()函数处理的事件,所以获取wx.Frame()的返回值的唯一方法是通过捕获事件。

处理事件的标准做法通常来自wx.Window本身派生的类(例如,Frame,Panel等)。由于您希望wx.Frame外部的代码接收在处理OnClose()事件时收集的信息,因此最好的方法是为您的帧注册事件处理程序。

wx.Window :: PushEventHandler的文档可能是最好的资源,甚至wxpython wiki都有关于如何执行此操作的精彩文章。在文章中,他们注册了一个自定义处理程序,它是“MouseDownTracker”的一个实例。您不希望在PushEventHandler调用中进行实例化,而是希望在调用之前对其进行实例化,以便您可以保留EventHandler派生类的句柄。这样,你可以在Frame被销毁之后检查派生的EventHandler类变量,或者甚至允许派生类为你做特殊的事情。

以下是来自wx python wiki的代码的改编(由于需要使用“调用”函数处理自定义事件的结果,因此有点令人费解):

import sys
import wx
import wx.lib.newevent

(MyCustomEvent, EVT_CUSTOM) = wx.lib.newevent.NewEvent()

class CustomEventTracker(wx.EvtHandler):
 def __init__(self, log, processingCodeFunctionHandle):
  wx.EvtHandler.__init__(self)
  self.processingCodeFunctionHandle = processingCodeFunctionHandle
  self.log = log
  EVT_CUSTOM(self, self.MyCustomEventHandler)

 def MyCustomEventHandler(self, evt):
  self.log.write(evt.resultOfDialog + '\n')
  self.processingCodeFunctionHandle(evt.resultOfDialog)
  evt.Skip()

class MyPanel2(wx.Panel):
 def __init__(self, parent, log):
  wx.Panel.__init__(self, parent)
  self.log = log

 def OnResults(self, resultData):
  self.log.write("Result data gathered: %s" % resultData)

class MyFrame(wx.Frame):
 def __init__(self, parent, ID = -1, title = "", pos = wx.DefaultPosition,
     size = wx.DefaultSize, style = wx.DEFAULT_FRAME_STYLE):
  wx.Frame.__init__(self, parent, ID, title, pos, size, style)
  self.panel = panel = wx.Panel(self, -1, style = wx.TAB_TRAVERSAL
       | wx.CLIP_CHILDREN
       | wx.FULL_REPAINT_ON_RESIZE)
  sizer = wx.BoxSizer(wx.VERTICAL)
  sizer.Add((25, 25))

  row = wx.BoxSizer(wx.HORIZONTAL)
  row.Add((25,1))
  m_close = wx.Button(self.panel, wx.ID_CLOSE, "Close")
  m_close.Bind(wx.EVT_BUTTON, self.OnClose)
  row.Add(m_close, 0, wx.ALL, 10)
  sizer.Add(row)
  self.panel.SetSizer(sizer)

 def OnClose(self, evt):
  dlg = wx.MessageDialog(self, 
   "Do you really want to close this frame?",
   "Confirm Exit", wx.OK|wx.CANCEL|wx.ICON_QUESTION)
  result = dlg.ShowModal()
  dlg.Destroy()
  if result == wx.ID_CANCEL:
   event = MyCustomEvent(resultOfDialog = "User Clicked CANCEL")
   self.GetEventHandler().ProcessEvent(event)
  else: # result == wx.ID_OK
   event = MyCustomEvent(resultOfDialog = "User Clicked OK")
   self.GetEventHandler().ProcessEvent(event)
   self.Destroy()

app = wx.App(False)
f2 = wx.Frame(None, title="Frame 1 (for feedback)", size=(400, 350))
p2 = MyPanel2(f2, sys.stdout)
f2.Show()
eventTrackerHandle = CustomEventTracker(sys.stdout, p2.OnResults)
f1 = MyFrame(None, title="PushEventHandler Tester (deals with on close event)", size=(400, 350))
f1.PushEventHandler(eventTrackerHandle)
f1.Show()
app.MainLoop()

答案 1 :(得分:2)

您可以从Dialog ShowModal方法中获得单击“确定”,“取消”按钮的结果 给定对话框是其中一个wxPython Dialog类的实例:

result = dialog.ShowModal()
if result == wx.ID_OK:
    print "OK"
else:
    print "Cancel"
dialog.Destroy()

答案 2 :(得分:2)

对于最初的问题已经晚了几年,但是当我自己寻找这个问题的答案时,我偶然发现了一种从模态中获取返回值的内置方法,而不会弄乱任何自定义事件的乐趣。想我会发布在这里以防其他人需要它。

这就是这个人:

  

wxDialog :: EndModal void EndModal( int retCode

     

结束模式对话框,传递要从返回的值   * wxDialog :: ShowModal调用。*

使用上述内容,您可以从对话框中返回任何内容。

示例用法是将wx.Dialog子类化,然后将EndModal函数放在按钮处理程序中。

class ProjectSettingsDialog(wx.Dialog):
    def __init__(self):
        wx.Dialog.__init__(self, None, -1, "Project Settings", size=(600,400))

        sizer = wx.BoxSizer(wx.VERTICAL) #main sized
        sizer.AddStretchSpacer(1) 

        msg = wx.StaticText(self, -1, label="This is a sample message")
        sizer.Add(msg, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALL, 15)


        horizontal_sizer = wx.BoxSizer(wx.HORIZONTAL)
        okButton = wx.Button(self, -1, 'OK')
        self.Bind(wx.EVT_BUTTON, self.OnOK, okButton)

        cancelBtn = wx.Button(self, -1, "Cancel")
        self.Bind(wx.EVT_BUTTON, self.OnCancel, cancelBtn)

        horizontal_sizer.Add(okButton, 0, wx.ALIGN_LEFT)
        horizontal_sizer.AddStretchSpacer(1)
        horizontal_sizer.Add(cancelBtn, 0, wx.ALIGN_RIGHT)

        sizer.Add(horizontal_sizer, 0)

        sizer.AddStretchSpacer(1)
            self.SetSizer(sizer)

    def OnOK(self, event):
        self.EndModal(wx.ID_OK) #returns numeric code to caller
        self.Destroy()


    def OnCancel(self, event):
        self.EndModal(wx.ID_CANCEL) #returns numeric code to caller
        self.Destroy()

(注意:我刚刚快速敲除了这段代码;没有测试大小调整器)

正如您所看到的,您需要做的就是从按钮事件中调用EndModal以将值返回到生成对话框的任何内容。

答案 3 :(得分:1)

我想做同样的事情,拥有一个可以在控制台应用程序中运行的图形“选择器”。我就是这样做的。

# Fruit.py

import wx

class Picker (wx.App):
    def __init__ (self, title, parent=None, size=(400,300)):
        wx.App.__init__(self, False)
        self.frame = wx.Frame(parent, title=title, size=size)

        self.apple_button = wx.Button(self.frame, -1, "Apple", (0,0))
        self.apple_button.Bind(wx.EVT_BUTTON, self.apple_button_click)

        self.orange_button = wx.Button(self.frame, -1, "Orange", (0,100))
        self.orange_button.Bind(wx.EVT_BUTTON, self.orange_button_click)

        self.fruit = None
        self.frame.Show(True)

    def apple_button_click (self, event):
        self.fruit = 'apple'
        self.frame.Destroy()

    def orange_button_click (self, event):
        self.fruit = 'orange'
        self.frame.Destroy()

    def pick (self):
        self.MainLoop()
        return self.fruit

然后从控制台应用程序中,我将运行此代码。

# Usage.py

import Fruit

picker = Fruit.Picker('Pick a Fruit')
fruit = picker.pick()
print 'User picked %s' % fruit

答案 4 :(得分:1)

user1594322的答案有效,但它要求您将所有控件放在wx.App中,而不是wx.Frame。这将使代码更难回收。

我的解决方案涉及在定义 init 功能时定义“PassBack”变量。 (类似于“父”变量,但通常在启动wx.Frame时使用它)

从我的代码:

class MyApp(wx.App):
    def __init__ (self, parent=None, size=(500,700)):
        wx.App.__init__(self, False)
        self.frame = MyFrame(parent, -1, passBack=self) #Pass this app in
        self.outputFromFrame = "" #The output from my frame


    def getOutput(self):
        self.frame.Show()
        self.MainLoop()
        return self.outputFromFrame

和帧类:

class MyFrame(wx.Frame):
    def __init__(self, parent, ID, passBack, title="My Frame"):
        wx.Frame.__init__(self, parent, ID, title, size=(500, 700))
        self.passBack = passBack #this will be used to pass back variables/objects

在执行MyFrame期间的某个地方

self.passBack.outputFromFrame = "Hello"

总而言之,从应用程序中获取字符串

app = MyApp()
val = app.getOutput()
#Proceed to do something with val

答案 5 :(得分:0)

在comp.lang.python上查看此答案:Linkie

答案 6 :(得分:0)

我认为wxFrame不能返回值,因为它不是模态的。如果您不需要使用wxFrame,那么模态对话框可能适合您。如果你真的需要一个框架,我会考虑使用自定义事件。

它会是这样的: (1)用户点击关闭wxFrame (2)您重写OnClose(或类似的东西)以弹出一个对话框,询问用户一个问题 (3)创建并发布自定义事件 (4)关闭wxFrame (5)其他一些代码处理您的自定义事件

答案 7 :(得分:0)

我想我和你有同样的问题。我没有将弹出窗口设为框架,而是将其设为对话框。我通过继承wx.dialog而不是wx.frame来创建自定义对话框。然后你可以使用joaquin上面发布的代码。您可以检查对话框的返回值以查看输入的内容。这可以通过在用户单击ok到本地变量时存储textctrl的值来完成。然后在它被摧毁之前,你会以某种方式得到这个价值。

这个网站的自定义对话框部分帮助了我。 http://zetcode.com/wxpython/dialogs/