如何使wxFrame的行为类似于模态wxDialog对象

时间:2009-05-19 15:35:57

标签: c++ wxwidgets

是否可以使wxFrame对象的行为类似于模式对话框,因为创建wxFrame对象的窗口会停止执行,直到wxFrame对象退出?

我正在处理small game并遇到以下问题。我有一个主程序窗口,主持主应用程序(战略部分)。偶尔,我需要将控制转移到第二个窗口以解决部分游戏(战术部分)。在第二个窗口中,我希望第一个窗口中的处理停止并等待在第二个窗口中完成的工作完成。

通常情况下,模态对话框可以解决这个问题,但我希望新窗口具有一些我无法通过wxDialog获得的功能,即底部的状态栏以及调整大小/最大化/最小化的功能窗口(这应该是可能但不起作用,请参阅此问题How to get the minimize and maximize buttons to appear on a wxDialog object)。

作为补充说明,我希望第二个窗口的功能需要与主窗口完全分离,因为它最终将被分离到一个单独的程序中。

有没有人这样做过或有任何建议?

4 个答案:

答案 0 :(得分:4)

我也从类似的解决方案看起来并且已经想出这个解决方案,创建一个框架,通过执行frame.MakeModal()来禁用其他窗口并在显示框架后停止执行开始和事件循环,并且当框架关闭时退出事件循环例如我这里是使用wxpython的示例,但在wxwidgets中应该类似。

import wx

class ModalFrame(wx.Frame):
    def __init__(self, parent, title):
        wx.Frame.__init__(self, parent, title=title, style=wx.DEFAULT_FRAME_STYLE|wx.STAY_ON_TOP)

        btn = wx.Button(self, label="Close me")
        btn.Bind(wx.EVT_BUTTON, self.onClose)
        self.Bind(wx.EVT_CLOSE, self.onClose) # (Allows main window close to work)

    def onClose(self, event):
        self.MakeModal(False) # (Re-enables parent window)
        self.eventLoop.Exit()
        self.Destroy() # (Closes window without recursion errors)

    def ShowModal(self):
        self.MakeModal(True) # (Explicit call to MakeModal)
        self.Show()

        # now to stop execution start a event loop 
        self.eventLoop = wx.EventLoop()
        self.eventLoop.Run()


app = wx.PySimpleApp()
frame = wx.Frame(None, title="Test Modal Frame")
btn = wx.Button(frame, label="Open modal frame")

def onclick(event):
    modalFrame = ModalFrame(frame, "Modal Frame")
    modalFrame.ShowModal()
    print "i will get printed after modal close"

btn.Bind(wx.EVT_BUTTON, onclick)

frame.Show()
app.SetTopWindow(frame)
app.MainLoop()

答案 1 :(得分:3)

“停止执行”窗口并没有多大意义,因为窗口只处理发送给它的事件,例如鼠标,键盘或绘图事件,忽略它们会使程序显示为挂起状态。你应该做的是禁用你框架中的所有控件,这会使它们变灰并让用户意识到此时它们无法与之交互。

您还可以完全禁用父框架,而不是禁用其上的所有控件。查看 wxWindowDisabler 类,构造函数有一个参数来指示可以与之交互的窗口,并且应用程序的所有其他窗口都将被禁用。

如果您以后想要执行辅助程序,那么您可以使用 wxExecute()函数来执行此操作。

答案 2 :(得分:1)

这让我花了很多时间来弄明白,但这是一个从Anurag的例子中发展出来的实例:

import wx

class ChildFrame(wx.Frame):
    ''' ChildFrame launched from MainFrame '''
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, -1,
                          title=self.__class__.__name__,
                          size=(300,150))

        panel = wx.Panel(self, -1)
        closeButton = wx.Button(panel, label="Close Me")

        self.Bind(wx.EVT_BUTTON, self.__onClose, id=closeButton.GetId())
        self.Bind(wx.EVT_CLOSE, self.__onClose) # (Allows frame's title-bar close to work)

        self.CenterOnParent()
        self.GetParent().Enable(False)
        self.Show(True)

        self.__eventLoop = wx.EventLoop()
        self.__eventLoop.Run()

    def __onClose(self, event):
        self.GetParent().Enable(True)
        self.__eventLoop.Exit()
        self.Destroy()

class MainFrame(wx.Frame):
    ''' Launches ChildFrame when button is clicked. '''
    def __init__(self, parent, id):
        wx.Frame.__init__(self, parent, id,
                          title=self.__class__.__name__,
                          size=(400, 300))

        panel = wx.Panel(self, -1)
        launchButton = wx.Button(panel, label="launch modal window")

        self.Bind(wx.EVT_BUTTON, self.__onClick, id=launchButton.GetId())

        self.Centre()
        self.Show(True)

    def __onClick(self, event):
        dialog = ChildFrame(self, -1)
        print "I am printed by MainFrame and get printed after ChildFrame is closed"

if __name__ == '__main__':
    app = wx.App()    
    frame = MainFrame(None, -1)
    frame.Show()
    app.MainLoop()

答案 3 :(得分:0)

不确定这是否是一个很好的答案,但它确实有效。

bool WinApp1::OnInit()
{
  if (!wxApp::OnInit())
    return false;

  SettingsDialog dialog(m_settingsData);
  dialog.ShowModal();

  return false;
}

SettingsDialog::SettingsDialog(SettingsData& settingsData)
  : m_settingsData(settingsData)
{
  SetExtraStyle(wxDIALOG_EX_CONTEXTHELP);

  wxWindow* parent = nullptr;
  Create(parent, wxID_ANY, "Preferences", wxDefaultPosition, wxDefaultSize,
    wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER);

WinApp1窗口永远不会提供wxFrame,也不会绘制。