Возвращаемое значение из фрейма wxPython
может ли кто-нибудь показать мне, как я могу вернуть значение из фрейма wxPython? Когда использование щелкает закрыть, я всплывающее диалоговое окно сообщения, задавая ему вопрос. Я хотел бы вернуть код возврата этого диалогового окна сообщения в мою вызывающую функцию.
спасибо
8 ответов
потому что wxFrame имеет события, которые обрабатываются через приложение.Функциональность MainLoop (), единственный способ получить возвращаемое значение wx.Frame () - это улавливание события.
стандартная практика обработки событий обычно происходит из класса, производного от wx.Само окно (например, рама, панель и т. д.). Поскольку вы хотите внешний код для wx.Фрейм для получения информации, которая была собрана при обработке события OnClose (), то лучший способ сделать это-зарегистрироваться обработчик событий для вашего фрейма.
документация для wx.Window:: PushEventHandler, вероятно, лучший ресурс и даже wxPython, в вики есть хорошая статья о том, как это сделать. В статье они регистрируют пользовательский обработчик, который является экземпляром " MouseDownTracker."Вместо того, чтобы создавать экземпляр в вызове PushEventHandler, вы хотели бы создать его до вызова, чтобы сохранить дескриптор производного класса EventHandler. Таким образом, ты можно проверить производные переменные класса 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()
вы можете получить результат нажатия кнопок OK, CANCEL из диалогового метода ShowModal.
Данный диалог является экземпляром одного из диалоговых классов wxPython:
result = dialog.ShowModal()
if result == wx.ID_OK:
print "OK"
else:
print "Cancel"
dialog.Destroy()
Я хотел сделать то же самое, чтобы иметь графический "выбор", который я мог бы запустить из консольного приложения. Вот как я это сделал.
# 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
ответ user1594322 работает, но он требует, чтобы вы поместили все свои элементы управления в свой wx.Приложение, а не wx.Рамка. Это затруднит переработку кода.
мое решение включает в себя определение переменной "PassBack" при определении вашего init. (аналогично" родительской " переменной, но она обычно используется уже при инициировании wx.Кадр)
из моего кода:
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
и для класса frame:
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
несколько лет спустя для первоначального вопроса, но при поиске ответа на этот вопрос я сам наткнулся на встроенный метод получения возвращаемого значения из модального, не возясь с какой-либо пользовательской забавностью событий. Подумал, что напишу здесь на случай, если кому-то еще понадобится.
Это просто этот парень прямо здесь:
wxDialog:: EndModal void EndModal (int retCode)
заканчивается модальный диалог, передающий значение, возвращаемое из *wxDialog::вызов ShowModal.*
используя вышеизложенное, вы можете вернуть все, что хотите из диалогового окна.
примером использования будет подкласс a 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
из события button, чтобы вернуть значение тому, что породило диалог.
Я не думаю, что wxFrame может возвращать значение, поскольку оно не является модальным. Если вам не нужно использовать wxFrame, тогда модальный диалог может работать для вас. Если вам действительно нужен фрейм, я бы рассмотрел использование пользовательского события.
Это будет что-то вроде этого: (1) пользователь щелкает, чтобы закрыть wxFrame (2) вы переопределяете OnClose (или что-то в этом роде), чтобы открыть диалоговое окно, чтобы задать пользователю вопрос (3) Создание и публикация пользовательского события (4) закройте wxFrame (5) некоторые другие процессы кода пользовательское событие
Я думаю, что у меня была та же проблема, что и у вас. Вместо того, чтобы сделать это всплывающее окно рамкой, я сделал его диалогом. Я сделал пользовательский диалог, унаследовав wx.диалог вместо wx.рамка. Затем вы можете использовать код, который Хоакин выложил выше. Проверьте возвращаемое значение диалогового окна, чтобы увидеть, что было введено. Это можно сделать, сохранив значение textctrl, когда пользователь нажимает ok в локальную переменную. Затем, прежде чем он будет уничтожен, вы каким-то образом получите эту ценность.
в раздел пользовательского диалога этого сайта очень помог мне. http://zetcode.com/wxpython/dialogs/