[英]wxpython: how to access a window when a dialog is open
我知道當 ShowModal() 時,對話框的父級應該是不可訪問的。 但是,我的程序需要提供對單獨窗口的訪問權限,以便用戶可以查看該窗口上的信息來決定單擊對話框上的哪個按鈕。 就像在下面的程序中一樣,當“對話框”打開時,我希望能夠訪問“不同的框架”。 我怎樣才能做到這一點?
import wx
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Different Frame", size=(300, 300))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
btn = wx.Button(panel, -1, "open frame")
self.Bind(wx.EVT_BUTTON, self.OnOpenFrame, id=btn.GetId())
sizer.Add(btn)
text = "This is a line.\n" * 100
txtCtrl = wx.TextCtrl(panel, -1, text, style=wx.TE_MULTILINE,
size=(200,200))
sizer.Add(txtCtrl)
panel.SetSizer(sizer)
self.Centre()
self.Show()
def OnOpenFrame(self, evt):
ParentFrame()
class ParentFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, title="Parent Frame",size=(500, 500))
panel = wx.Panel(self)
btn = wx.Button(panel, -1, "open dialog")
self.Bind(wx.EVT_BUTTON, self.OnOpenDialog, id=btn.GetId())
self.Centre()
self.Show()
def OnOpenDialog(self, event):
dlg1 = MyDialog(self)
val = dlg1.ShowModal()
dlg2 = MyDialog(self, val)
dlg2.ShowModal()
class MyDialog(wx.Dialog):
def __init__(self, parent, prevAnsw=None):
wx.Dialog.__init__(self, parent, -1, title = "Dialog")
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
if prevAnsw is not None:
sizer.Add(wx.StaticText(
panel, -1, "Answer from previous Dialog: %s" % prevAnsw))
sizer.Add(wx.StaticText(panel, -1, "Try to scroll in Different Frame to "
"see if it is blocked"))
btn1 = wx.Button(panel, -1, "Pass 1")
self.Bind(wx.EVT_BUTTON, self.OnPass1, id=btn1.GetId())
sizer.Add(btn1)
btn2 = wx.Button(panel, -1, "Pass 2")
self.Bind(wx.EVT_BUTTON, self.OnPass2, id=btn2.GetId())
sizer.Add(btn2)
panel.SetSizer(sizer)
def OnPass1(self, evt):
self.EndModal(1)
def OnPass2(self, evt):
self.EndModal(2)
app = wx.App(0)
frame = MyFrame(None)
frame.Show()
app.MainLoop()
簡單的答案是不要讓它成為一個dialog
。
下面是一個相當不雅的偽對話框,因為它在動作發生之前不會返回。 它通過在等待事件發生的while
循環中調用Yield
來保持訪問其他窗口的能力。
由於其他窗口是“活動的”,一旦每個進程完成,激活此進程的按鈕必須禁用並重新啟用,因此它確實變得有點黑客,但它應該指向實現目標的方向你要。
也許它本身可以寫成 ChainDialog 模塊,但我認為它很可能只是復制 Mike Driscoll 提到的Wizard
模塊。
import wx
import time
class MyFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Reference Frame", size=(300, 300))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
self.btn = wx.Button(panel, -1, "open frame")
self.Bind(wx.EVT_BUTTON, self.OnOpenFrame, id=self.btn.GetId())
sizer.Add(self.btn)
text = "This is a line.\n" * 100
txtCtrl = wx.TextCtrl(panel, -1, text, style=wx.TE_MULTILINE,
size=(200,200))
sizer.Add(txtCtrl)
panel.SetSizer(sizer)
self.Centre()
self.Show()
def OnOpenFrame(self, evt):
DialogRequest(self)
class DialogRequest(wx.Frame):
def __init__(self,parent):
wx.Frame.__init__(self, parent, -1, title="Dialog Request Frame",size=(500, 500))
self.parent = parent
#Disable the "open frame" button
self.parent.btn.Enable(False)
#Use a dictionary to store chained results
#Allows for rewriting of results if "Previous" button used
self.stored_results = {}
self.dlg_chain_no = 0
self.dlg_prev_value = 0
panel = wx.Panel(self)
self.btn = wx.Button(panel, -1, "open dialog")
self.Bind(wx.EVT_BUTTON, self.OnOpenDialog, id=self.btn.GetId())
self.Bind(wx.EVT_CLOSE, self.OnClose)
self.Centre()
self.Show()
def OnOpenDialog(self, event):
self.btn.Enable(False) #Disable open dialog
#For test purposes there will be 4 chained dialogs
#result -1 is a cancelled dialog
#
while self.dlg_chain_no != 4 and self.dlg_chain_no != -1:
dlg = ChainDialog(self, self.dlg_chain_no)
result = ChainDialog.Action(dlg)
if result.chain_no == -1: # dialog Cancelled zero down stored values
self.dlg_chain_no = 0
self.stored_results = {}
print("Dialog chain Cancelled")
break
self.dlg_chain_no = result.chain_no
self.stored_results[result.chain_no] = result.result
self.dlg_prev_value = result.result
self.dlg_chain_no = 0
self.dlg_prev_value = 0
print("dialog values", self.stored_results)
self.stored_results = {}
self.btn.Enable(True) #Re-enable open dialog
def OnClose(self, event):
#Re-enable the "open frame" button
self.parent.btn.Enable(True)
event.Skip()
class ChainDialog(wx.Frame):
def __init__(self, parent, chain_no):
wx.Frame.__init__(self, parent, -1, title = "Dialog "+str(chain_no))
self.chain_no = self.saved_chain_no = chain_no
self.result = None
self.parent = parent
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
if parent.dlg_prev_value != 0:
sizer.Add(wx.StaticText(
panel, -1, "Answer from previous Dialog: %s" % parent.dlg_prev_value))
sizer.Add(wx.StaticText(panel, -1, "Try to scroll in Different Frame to "
"see if it is blocked"))
btn1 = wx.Button(panel, -1, "Step "+str(self.chain_no))
btn2 = wx.Button(panel, -1, "Previous")
btn3 = wx.Button(panel, -1, "Cancel")
self.Bind(wx.EVT_BUTTON, self.OnStep, id=btn1.GetId())
self.Bind(wx.EVT_BUTTON, self.OnPrev, id=btn2.GetId())
self.Bind(wx.EVT_BUTTON, self.OnCancel, id=btn3.GetId())
sizer.Add(btn1)
sizer.Add(btn2)
sizer.Add(btn3)
panel.SetSizer(sizer)
self.Show()
def Action(self):
#Keep this dialog frame open until an action has occurred.
#The action will be from OnStep, OnPrev or OnCancel
#Use Yield to allow other frames to be viewed
#This pseudo-dialog returns self of relevance chain_no and result
while self.chain_no == self.saved_chain_no:
time.sleep(0.2)
wx.GetApp().Yield()
self.Close()
return self
def OnStep(self, evt):
self.chain_no += 1
#Return some relevant value or other
self.result = int(time.time())
def OnPrev(self, evt):
self.chain_no -= 1
#Return some relevant value or other (I'm just using time)
self.result = int(time.time())
def OnCancel(self, evt):
self.chain_no = -1
app = wx.App()
frame = MyFrame(None)
frame.Show()
app.MainLoop()
Rolf of Saxony 的回答很有趣,所以我把它作為我的解決方案。 對於這個問題,我還有另一個更簡單的答案,其中我拆分了函數 OnOpenDialog() 以便它可以在 ParentFrame 中等待。 這個想法實際上也來自薩克森州卷的第一個答案。 我添加了在其 MyDialogs 打開時阻止 ParentFrame 的選項,而其他人不受影響(MyFrame 或不同的 Frame)。 這個答案不是很干凈但很簡單,我不必對代碼進行太多更改。
import wx
class NonrelatedFrame(wx.Frame):
def __init__(self, parent):
wx.Frame.__init__(self, parent, -1, "Non-related Frame", size=(300, 300))
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
btn = wx.Button(panel, -1, "open frame")
self.Bind(wx.EVT_BUTTON, self.OnOpenFrame, id=btn.GetId())
sizer.Add(btn)
text = "This is a line.\n" * 100
txtCtrl = wx.TextCtrl(panel, -1, text, style=wx.TE_MULTILINE,
size=(200,200))
sizer.Add(txtCtrl)
panel.SetSizer(sizer)
self.Centre()
self.Show()
def OnOpenFrame(self, evt):
ParentFrame()
class ParentFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, -1, title="Parent Frame",size=(500, 500))
self.passActivate = None
panel = wx.Panel(self)
btn = wx.Button(panel, -1, "open dialog")
self.Bind(wx.EVT_BUTTON, self.OnOpenDialog, id=btn.GetId())
self.Centre()
self.Show()
self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
def OnActivate(self, evt):
# use self.passActivate and OnActivate() to help make user not
# be able to access anything on this form
if self.passActivate is not None:
self.passActivate.Raise()
def OnOpenDialog(self, event):
dlg1 = MyDialog(self, func2call=self.OnOpenDialog2)
dlg1.Show()
def OnOpenDialog2(self, val):
dlg2 = MyDialog(self, prevAnsw=val, lastDialog=True)
dlg2.Show()
class MyDialog(wx.Dialog):
def __init__(self, parent, prevAnsw=None, lastDialog=False, func2call=None):
wx.Dialog.__init__(self, parent, -1, title = "Dialog", style=wx.CAPTION)
self.parent = parent
self.parent.passActivate = self
self.lastDialog = lastDialog
self.func2call = func2call
panel = wx.Panel(self)
sizer = wx.BoxSizer(wx.VERTICAL)
if prevAnsw is not None:
sizer.Add(wx.StaticText(
panel, -1, "Answer from previous Dialog: %s" % prevAnsw))
sizer.Add(wx.StaticText(panel, -1, "Try to scroll in Non-related Frame to "
"see if it is blocked"))
btn1 = wx.Button(panel, -1, "Pass 1")
self.Bind(wx.EVT_BUTTON, self.OnPass1, id=btn1.GetId())
sizer.Add(btn1)
btn2 = wx.Button(panel, -1, "Pass 2")
self.Bind(wx.EVT_BUTTON, self.OnPass2, id=btn2.GetId())
sizer.Add(btn2)
panel.SetSizer(sizer)
def OnPass1(self, evt):
if not self.lastDialog:
self.func2call(1)
else:
self.parent.passActivate = None
self.Close()
def OnPass2(self, evt):
if not self.lastDialog:
self.func2call(2)
else:
self.parent.passActivate = None
self.Close()
app = wx.App(0)
frame = NonrelatedFrame(None)
frame.Show()
app.MainLoop()
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.