Подключение к сигналу реализации: странное поведение определения размера окна - PullRequest
0 голосов
/ 10 апреля 2020

Я использую Gtkmm3 (Ubuntu) для создания небольшого GUI приложения. В этом приложении у меня есть пара windows для создания, которые в основном все следуют одному и тому же шаблону:

  1. регистрация основного макета (Gtk::Grid);
  2. настройка свойств окна ( значок, заголовок и т. д. c);
  3. настройка свойств макета (расширение, вложенные макеты и т. д. c);
  4. настройка виджетов окна (добавление их к макетам, меткам и т. д.) c).

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

template<typename GtkmmWindow>
class Window
{

public:

    Window();

    virtual int Show() = 0;


protected:

    virtual void ConfigureWindow() = 0;
    virtual void ConfigureLayouts() = 0;
    virtual void ConfigureWidgets() = 0;

    void Init();


    Gtk::Grid m_mainLayout;
    GtkmmWindow m_window;

};

template<typename GtkmmWindow>
Window<GtkmmWindow>::Window()
{
    m_window.add(m_mainLayout);

    // When signal 'realize' is sent, 'Init' will be triggered.
    // This happens after construction, so virtual methods can
    // be used safely:
    m_window.signal_realize().connect([this](){Init();});
}

// Initialize child window according to its own needs:
template<typename GtkmmWindow>
void Window<GtkmmWindow>::Init()
{
    ConfigureWindow();
    ConfigureLayouts();
    ConfigureWidgets();

    // If this line is removed, no widgets are shown.
    m_window.show_all_children();
}

Цель этого класса - убедиться, что пункты с 1 по 4 выполнены всеми windows одинаково. Это происходит путем вызова соответствующих виртуальных методов (которые должны быть переопределены в конкретных дочерних классах) при отправке сигнала realize. Это связано с тем, что при отправке сигнала realize я знаю, что были вызваны конструкторы окон и что я могу безопасно использовать виртуальные методы.

Например, вот как я использую его для создания главного окна приложения. :

class MyWindow : public Window<Gtk::ApplicationWindow>
{

public:

    MyWindow(Gtk::Application& p_app) : m_app{p_app} {}

    int Show() override
    {
        m_window.show_all();
        return m_app.run(m_window);
    }

private:

    Gtk::Application& m_app;
    Gtk::Button m_button;

    void ConfigureWindow() override
    {
        m_window.set_title("SO Question");

        // If I set this to false, the window shrinks to fit the button size:
        m_window.set_resizable(false);
    }

    void ConfigureLayouts() override
    {
        m_mainLayout.override_background_color(Gdk::RGBA("yellow"));
    }

    void ConfigureWidgets() override
    {
        m_mainLayout.attach(m_button, 0, 0, 1, 1);
        m_button.set_label("Hello");
    }

};

В этом главном окне основной макет задается желтым фоном; в главном макете есть Gtk::Button с меткой «Hello». Проблема, связанная с этой стратегией, заключается в том, что при запуске кода я получаю странные размеры окна / макета:

enter image description here

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

enter image description here

То есть окно и основной макет должны сжиматься до размера их единственного содержащегося виджета. Странно, если я сделаю окно set_resizable(false), я получу желаемый размер, но тогда я не смогу изменить его размер, что часто неприемлемо.

Вопросы:

  1. Почему это не так (почему макет занимает так много дополнительного пространства)?
  2. Как этого добиться, не дублируя базовый код для каждого окна?

Вы можете создать этот код, используя g++, добавив его в:

#include <memory>
#include <gtkmm.h>

// Add here...

int main(int argc, char *argv[])
{
  auto app = Gtk::Application::create(argc, argv, "so.realize");

  std::unique_ptr<MyWindow> mainWindow = std::make_unique<MyWindow>(*(app.get()));

  return mainWindow->Show();
}

и запустив:

g++ -std=c++17 main.cpp -o example.out `pkg-config gtkmm-3.0 --cflags --libs`

1 Ответ

0 голосов
/ 11 апреля 2020

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

button.set_hexpand(true);
button.set_vexpand(true);

Вот хороший справочник по сетке против поля. https://people.gnome.org/~ryanl/gtk/html/ch28s02.html

...