【问题标题】:Using sigc::mem_fun by accesing parent of container通过访问容器的父级来使用 sigc::mem_fun
【发布时间】:2020-10-29 15:56:08
【问题描述】:

我正在尝试用 Gtkmm3 制作一个简单的软件。

我想要一个带有网格的窗口。单击该网格内的按钮时,应触发窗口的一个方法以删除当前网格并将其替换为另一个网格。

我可以使用这样的网格方法:

button.signal_clicked().connect(sigc::mem_fun(*this, &MyGrid::someMethod));

“this”是 MyGrid。

我想做这样的事情:

button.signal_clicked().connect(sigc::mem_fun(*this->get_parent(), &MyWindow::someMethod));

其中 this->get_parent() 将是 MyWindow 的一个实例

我的.h:


#ifndef MINIPROJECT_GUI_H
#define MINIPROJECT_GUI_H

#include <gtkmm/button.h>
#include <gtkmm/window.h>
#include <gtkmm/grid.h>
#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <gtkmm/label.h>


class WelcomeGrid: public Gtk::Grid
{
    Gtk::Label message;
    Gtk::Button nextButton; // This button should be connected to Fenetre::infoView()
public:
    WelcomeGrid();
    void display();

};


class InfoGrid : public Gtk::Grid
{
    Gtk::Button button2;// This button should be connected to Fenetre::welcomeView()
    Gtk::Label label2;
public:
    InfoGrid();
    void display();
};


class Fenetre : public Gtk::Window
{

public:
    Fenetre();
    virtual ~Fenetre(); // Setup window

    void welcomeView();

protected:
    //Member widgets:
    WelcomeGrid welcome;
    InfoGrid info;
    void infoView(); // Remove the current grid from the window and replace it by infoGrid
    void welcomeView(); // Remove the current grid from the window and replace it by WelcomeGrid

};


#endif //MINIPROJECT_GUI_H

我的 .cpp :

#include "GUI.h"

Fenetre::Fenetre()
{
    // Sets the border width of the window.
    set_border_width(10);
    this->add(welcome);
}

Fenetre::~Fenetre()
{
}

void Fenetre::welcomeView() {
    this->remove();
    this->add(welcome);
}

void Fenetre::infoView() {
    this->remove();
    this->add(info);
}


InfoGrid::InfoGrid() {
    button2.set_label("Hello.");
    button2.signal_clicked().connect(sigc::mem_fun(*this,
                                                   &InfoGrid::display));

    label2.set_label("Welcome on the Vampire creation interface.");
    this->attach(label2, 0, 0, 1, 1);
    this->attach(button2,1,1,1,1);
    button2.show();
    this->show_all();
}



WelcomeGrid::WelcomeGrid() {
    nextButton.set_label("Create new character.");
    auto a = this->get_parent();
    nextButton.signal_clicked().connect(sigc::mem_fun(*this,
                                                   &WelcomeGrid::display));

    message.set_label("Welcome on the Vampire creation interface.");
    this->attach(message, 0, 0, 1, 1);
    this->attach(nextButton,1,1,1,1);
    // This packs the button into the Window (a container);
    this->show_all();
}

void WelcomeGrid::display() {
    auto a = this->get_parent();
    std::cout << typeid(a).name();
}

void InfoGrid::display() {
    std::cout << "coucou";
}

【问题讨论】:

    标签: c++ gtkmm gtkmm3 libsigc++


    【解决方案1】:

    没有任何代码,很难知道您到底在寻找什么。我会这样做:我会在网格内保留对父窗口的引用。例如:

    #include <iostream>
    #include <memory>
    #include <sstream>
    
    #include <gtkmm.h>
    
    class MyWindow : public Gtk::Window
    {
    
    public:
    
        MyWindow()
        : m_grid{std::make_unique<MyGrid>(*this, m_count)}
        {
            add(*m_grid);
        }
    
        // This is called when the grid's button is pressed:
        void ReplaceGrid()
        {
            ++m_count; 
            
            // Remove the grid from the window:
            remove();
    
            // Destroy current grid:
            m_grid = nullptr;
    
            // Create a new grid:
            m_grid = std::make_unique<MyGrid>(*this, m_count);
    
            // Add it to the window:
            add(*m_grid);
    
            show_all();
        }
    
    private:
    
        class MyGrid : public Gtk::Grid
        {
        
        public:
        
            MyGrid(MyWindow& p_parent, int p_count)
            : m_parent{p_parent}
            {
                // Create button:
                std::ostringstream ss;
                ss << "Replace me #" << p_count;
                m_replaceButton = Gtk::Button(ss.str());
        
                // Attach it to the grid:
                attach(m_replaceButton, 0, 0, 1, 1);
        
                // Connect replacement signal, using the parent window:
                m_replaceButton.signal_clicked().connect([this]()
                                                         {
                                                             // Call the parent (the window):
                                                             m_parent.ReplaceGrid();
                                                         });
            }
    
            ~MyGrid()
            {
                std::cout << "Grid destroyed" << std::endl;
            }
        
        private:
        
            Gtk::Button m_replaceButton;
    
            // Keep a reference to the parent window in the grid:
            MyWindow&   m_parent;
        };
    
        int                     m_count = 0;
        std::unique_ptr<MyGrid> m_grid;
    };
    
    int main(int argc, char *argv[]) 
    {
        auto app = Gtk::Application::create(argc, argv, "so.question.q64594709");
        MyWindow w;
    
        w.show_all();
        
        return app->run(w);
    }
    

    如果您运行此代码,您将看到一个带有网格的窗口,其中包含一个按钮。每当您单击按钮时,窗口:

    1. 更新计数器
    2. 破坏当前网格
    3. 使用更新后的计数器值创建一个新网格

    您将在新网格的按钮标签上看到更新的计数器值。在终端中,grids 的析构函数会打印一条消息,证明grids 确实被切换了。

    请注意,我在这里使用了 lambdas 来清理语法。我建议你也这样做。如果您真的想使用sigc::men_fun,您可以将lambda的内容封装到您在问题中提到的MyGrid::someMethod方法中。

    还要注意,网格是窗口的私有嵌套类(其他人不需要知道...)。

    使用 GCC 编译:

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

    【讨论】:

    • 感谢您的回答!有这样的嵌套类是一种好习惯吗?如果我在窗口内更改内容的方式不好,请告诉我!明天我会收到我的代码
    • 由于网格在您的窗口中并且也在使用它,因此不太可能在其他上下文中使用它。在这种情况下,隐藏(私下嵌套)是一种很好的做法,因为为其设计的窗口没有其他人可以(误用)使用它。
    • 不是真的,因为我会有 5 个不同的网格,我不想有 5 个嵌套类。
    猜你喜欢
    • 1970-01-01
    • 2023-03-28
    • 2017-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-03
    • 2020-05-26
    • 1970-01-01
    相关资源
    最近更新 更多