wxPython: получить доступ к классификатору GUI, сгенерированному wxFormBuilder, и заменить дочерний

Я хочу построить свои приложения по идее MVC, с отдельным графическим интерфейсом и контроллером. Кроме того, у меня есть коллега по работе с графическими задачами, намного лучше меня, и мы хотим распределить работу: он создает графическую часть с помощью wxFormBuilder, а я создаю "механизм" приложения.

Когда у меня сгенерирован графический интерфейс, я хочу заменить некоторые элементы, которыми wxFormbuilder не может управлять: например, wxObjectListView. Моя идея состоит в том, чтобы создать графический интерфейс с обычным wxListBox, импортировать его с помощью основной программы и заменить его wxObjectListView. Я не хочу напрямую изменять сгенерированный код с помощью wxFormBuilder, потому что я хочу поддерживать обратную совместимость с графическим редактором.

Проблема и вопрос: из основной программы, которая импортирует графический интерфейс, как я могу получить доступ к классификатору, который содержит список, удалить и заменить ObjectListView? Что-то вроде sizer.Delete(список), а затем sizer.Add(olv)...

Вот вам пример:

Код GUI, сгенерированный wxFormBuilder: фрейм со списком и кнопкой.

# -*- coding: utf-8 -*- 

###########################################################################
## Python code generated with wxFormBuilder (version Sep  8 2010)
## http://www.wxformbuilder.org/
##
## PLEASE DO "NOT" EDIT THIS FILE!
###########################################################################

import wx

###########################################################################
## Class MyFrame1
###########################################################################

class MyFrame1 ( wx.Frame ):

    def __init__( self, parent ):
        wx.Frame.__init__ ( self, parent, id = wx.ID_ANY, title = wx.EmptyString, pos = wx.DefaultPosition, size = wx.Size( 330,288 ), style = wx.DEFAULT_FRAME_STYLE|wx.TAB_TRAVERSAL )

        self.SetSizeHintsSz( wx.DefaultSize, wx.DefaultSize )

        fgSizer = wx.FlexGridSizer( 2, 1, 0, 0 )
        fgSizer.AddGrowableCol( 0 )
        fgSizer.AddGrowableRow( 0 )
        fgSizer.SetFlexibleDirection( wx.BOTH )
        fgSizer.SetNonFlexibleGrowMode( wx.FLEX_GROWMODE_SPECIFIED )

        m_listBox1Choices = [ u"Row1", u"Row2" ]
        self.m_listBox1 = wx.ListBox( self, wx.ID_ANY, wx.DefaultPosition, wx.DefaultSize, m_listBox1Choices, 0 )
        fgSizer.Add( self.m_listBox1, 1, wx.ALL|wx.EXPAND, 5 )

        self.m_button1 = wx.Button( self, wx.ID_ANY, u"MyButton", wx.DefaultPosition, wx.DefaultSize, 0 )
        fgSizer.Add( self.m_button1, 1, wx.ALL|wx.EXPAND, 5 )

        self.SetSizer( fgSizer )
        self.Layout()

        self.Centre( wx.BOTH )

    def __del__( self ):
        pass

И вот основной код, который импортирует графический класс.

from __future__ import print_function
# -*- coding: utf-8 -*-
import wx
from olvGUI import MyFrame1

class Ventana(MyFrame1):

    def inicia(self):
        hijos = self.GetChildren()
        for h in hijos:
            print(h)


if __name__ == "__main__":
    app = wx.App(False)
    v = Ventana(None)
    v.inicia()
    v.Show()
    app.MainLoop()

Когда я пытаюсь получить доступ к дочерним элементам Frame, я вижу только "конечные" объекты, а не Sizer.

<wx._controls.ListBox; proxy of <Swig Object of type 'wxListBox *' at 0x1e0cea8> >
<wx._controls.Button; proxy of <Swig Object of type 'wxButton *' at 0x19a5f90> >

Может быть, графический интерфейс должен иметь другую структуру, если я хочу сделать его элементы доступными, но я не знаю, как это сделать. Я попытался сделать два уровня размеров, и конечный результат тот же: я могу получить доступ к конечным элементам, а не к размерам.

1 ответ

Решение

Вам нужно будет изменить fgSizer в self.fgSizer так что вы можете получить к нему доступ позже. Тогда вы можете использовать Sizer's Remove способ удалить виджет. Есть Insert метод, который вы можете использовать, чтобы вставить другой виджет на его место.

Смотрите документацию по размерам для получения полной информации:

Поскольку вы удаляете и вставляете виджет, вам, скорее всего, потребуется позвонить Layout в конце этого метода. Эта статья имеет пример:

Наконец, вот пример получения классификатора:

import wx

########################################################################
class MyFrame(wx.Frame):
    """"""

    #----------------------------------------------------------------------
    def __init__(self):
        """Constructor"""
        wx.Frame.__init__(self, None, title='Test')
        self.panel = wx.Panel(self)

        sizer = wx.BoxSizer(wx.VERTICAL)

        btn = wx.Button(self.panel, label="Get sizer")
        btn.Bind(wx.EVT_BUTTON, self.onGetSizer)
        sizer.Add(btn, 0, wx.ALL|wx.CENTER, 5)
        self.panel.SetSizer(sizer)

        self.Show()

    #----------------------------------------------------------------------
    def onGetSizer(self, event):
        """"""
        sizer = self.panel.GetSizer()

if __name__ == '__main__':
    app = wx.App(False)
    frame = MyFrame()
    app.MainLoop()

Вот пример сохранения индекса вашего виджета:

self.widget_dict = {}
some_boxsizer.Add(some_widget)  # this is the first widget, so its ID is zero
self.widget_dict[some_widget] = 0

Теперь в вашем обработчике событий вы можете использовать этот словарь, чтобы определить, какой виджет находится в каком индексе:

index = self.widget_dict[some_widget]
Другие вопросы по тегам