Как заставить wxFrame вести себя как модальный объект wxDialog

Возможно ли заставить объект wxFrame вести себя как модальное диалоговое окно, в котором окно, создающее объект wxFrame, останавливает выполнение до выхода из объекта wxFrame?

Я работаю над небольшой игрой и столкнулся со следующей проблемой. У меня есть главное окно программы, в котором размещается основное приложение (стратегическая часть). Иногда мне нужно перенести управление во второе окно для разрешения части игры (тактическая часть). Находясь во втором окне, я хочу, чтобы обработка в первом окне остановилась и ждала завершения работы, выполняемой во втором окне.

Обычно модальное диалоговое окно делает свое дело, но я хочу, чтобы новое окно имело некоторую функциональность, которую я не могу получить с помощью wxDialog, а именно строку состояния внизу и возможность изменять размер / максимизировать / минимизировать окно (это должно быть возможно, но не работает, см. этот вопрос ( Как заставить кнопки сворачивания и сворачивания появляться на объекте wxDialog).

В качестве дополнительного примечания я хочу, чтобы функциональность второго окна оставалась полностью отделенной от основного окна, поскольку в конечном итоге оно будет выделено в отдельную программу.

Кто-нибудь сделал это или есть предложения?

3 ответа

Я также искал аналогичное решение и получил это решение, создал фрейм, отключил другие окна, выполнив 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()

Мне потребовалось много времени, чтобы разобраться, но вот рабочий пример, который вырос из примера Анурага:

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()

На самом деле не имеет смысла "останавливать выполнение" окна, поскольку окно обрабатывает только те события, которые ему отправляются, например, события мыши, клавиатуры или рисования, и их игнорирование может привести к зависанию программы. Что вы должны сделать, это отключить все элементы управления в вашем фрейме, это выделит их серым цветом и позволит пользователю осознать тот факт, что с ними нельзя взаимодействовать в данный момент.

Вы также можете полностью отключить родительский фрейм, вместо того, чтобы отключить все элементы управления на нем. Посмотрите на класс wxWindowDisabler, в конструкторе есть параметр, указывающий окно, с которым можно взаимодействовать, и все другие окна приложения будут отключены.

Если впоследствии вы захотите выполнить вторичную программу, вы можете использовать функцию wxExecute() для этого.

Не уверен, что это отличный ответ, но он сработал.

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, и оно никогда не отрисовывается.

Другие вопросы по тегам