Автоматизировать программирование окон с помощью базового класса - PullRequest
0 голосов
/ 11 сентября 2018

Я запрограммировал несколько окон для приложения, все они наследуют Gtkmm::Window.На данный момент, я хотел бы автоматизировать процесс.Прямо сейчас выделяется следующая структура:

class MyWindow : public Gtk::Window
{
public:
    MyWindow();
    virtual ~MyWindow();

    //...

private:
    void registerLayouts(); // Adds layouts to the window.
    void registerWidgets(); // Adds widgets to the layouts.

    //...
};

И конструктор:

MyWindow::MyWindow()
{
    registerLayouts(); // Cannot be virtual: in constructor.
    registerWidgets(); // Cannot be virtual: in constructor.

    //...
}

Так что проблема в том, что все это должно быть сделано вручную (т.е. копировать / вставлять)каждый раз, когда новое окно должно быть запрограммировано, потому что registerLayouts() и registerWidgets() вызываются при построении и, следовательно, не могут быть virtual.

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

Дело в том, что я не нашел, где это подходящее место могло бы быть.Я посмотрел на разные обработчики сигналов, но, похоже, для этого нет.

У вас есть представление о том, как я могу это сделать?

MFC имеет CDialog::OnInitDialog(), который выполняет что-то похожее на то, что мне нужно.

1 Ответ

0 голосов
/ 11 сентября 2018

Вы можете делегировать работу отдельному классу:

class MyWindow : public Gtk::Window
{
//public:  *** EDIT ***
protected:
    template <typename LayoutManager>
    MyWindow(LayoutManager const& lm)
    {
        lm.registerLayouts(this);
        lm.registerWidgets(this);
    }
};

class SubWindow : public MyWindow
{
    class LM { /* ... */ };
public:
     SubWindow() : MyWindow(LM()) { }
};

(Отредактировано: улучшенный шаблон скрывает от публичных менеджеров компоновки подклассов ...)

В качестве альтернативы,весь класс в виде шаблона (возможно, выше, чем выше) :

template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
public:
    MyWindow()
    {
        LayoutManager lm(*this);
        lm.registerLayouts();
        lm.registerWidgets();
    }
};

class SpecificLayoutManager { /* ... */ };
using SpecificWindow = MyWindow<SpecificLayoutManager>;

Если вам нужен менеджер раскладки для очистки (не знаком с GTK сам ...):

template <typename LayoutManager>
class MyWindow : public Gtk::Window
{
    LayoutManager lm;
public:
    MyWindow() : lm(*this)
    {
        lm.registerLayouts();
        lm.registerWidgets();
    }
    virtual ~MyWindow()
    {
        // still access to lm...
    }
};

Важное примечание: во всех вариантах у нас еще нет полностью построенный производный класс - приведение к последнему в менеджерах компоновки, таким образом, недопустимо (экспериментировал с Любопытно повторяющийся шаблон шаблона , но отбросил идею по той же самой причине: необходимо также привести к производному в конструкторе базы).

Редактировать в ответ на комментарии: Aпример того, как можно управлять дополнительными членами подкласса (используя третий вариант выше, класс шаблона один с элементом менеджера компоновки; lm элемент теперь должен быть protected):

class SubWindowLayoutManager
{
    template <typename>
    friend class MyWindow;
    friend class SubWindow;

    int someMember;

    void registerLayouts() { }
    void registerWidgets() { }

};
class SubWindow : public MyWindow<SubWindowLayoutManager>
{
    void doSomething()
    {
        lm.someMember = 77;
    }
};

Дополнительно новый вариант без шаблонов:

class MyWindow : public Gtk::Window
{
protected:
    class LayoutManager
    {
    public:
         virtual void registerLayouts(MyWindow* parent) = 0;
         virtual void registerWidgets(MyWindow* parent) = 0;
    };

    std::unique_ptr<LayoutManager> lm;

    MyWindow(std::unique_ptr<LayoutManager> lm)
        : lm(std::move(lm))
    {
        this->lm->registerLayouts(this);
        this->lm->registerWidgets(this);
    }
};

class SubWindow : public MyWindow
{
    class LM : public LayoutManager
    {
    public:
        void registerLayouts(MyWindow* parent) override { }
        void registerWidgets(MyWindow* parent) override { }

        int someMember;
    };

    // convenience access function:
    inline LM& lm()
    {
        return *static_cast<LM*>(MyWindow::lm.get());
    }

public:
    SubWindow() : MyWindow(std::make_unique<LM>()) { }

    void doSomething()
    {
        //static_cast<LM*>(lm.get())->someMember = 77;
        lm().someMember = 77;
    }
};
...