Как заставить wxFrame вести себя как модальный объект wxDialog - PullRequest
8 голосов
/ 19 мая 2009

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

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

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

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

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

Ответы [ 3 ]

4 голосов
/ 04 апреля 2010

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

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

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

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

1 голос
/ 26 января 2015

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

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