Search code examples
c++gtkmm3

How can I connect a Gtkmm signal to a fuction in another class?


I am new to c++ and Gtkmm3. I need to set signal in another class, how would I do that with out loading the class with the function in the class with the widget.

I dont want to reload the whole of FixedLayout in ButtonBox

in class ButtonBox I dont want

FixedLayout instance;
instance.move_widget();

The following shows my code

layout.cpp

#include "layout.h"
#include <iostream>

FixedLayout::FixedLayout()
{
    fixed.put(box, 0, 0);
    add(fixed);
}

void FixedLayout::move_widget(int x, int y)
{
    fixed.move(*fixed.get_focus_child(), x, y);
}

ButtonBox::ButtonBox()
{
    set_size_request(320, 480);
    header.set_size_request(-1, 24);
    body.set_size_request(-1, 456);
    pack_start(header);
    dragger = Gtk::GestureDrag::create(header);
    dragger->set_button(GDK_BUTTON_PRIMARY);
    dragger->set_propagation_phase(Gtk::PHASE_BUBBLE);
    dragger->signal_drag_update().connect(sigc::mem_fun(*this, &ButtonBox::update_drag));
    pack_end(body);
}

void ButtonBox::update_drag(bool x, bool y)
{
    FixedLayout::move_widget(x, y);
}

layout.h

#ifndef FIXEDLAYOUT_H
#define FIXEDLAYOUT_H

#include <gtkmm.h>

class ButtonBox: public Gtk::VBox
{
    public:
    ButtonBox();

    protected:
        Gtk::Button header{"Header"}, body{"Body"};
        Glib::RefPtr<Gtk::GestureDrag> dragger;
        void update_drag(bool x, bool y);

    private:
};

class FixedLayout: public Gtk::ScrolledWindow
{
    public:
       FixedLayout();
        //virtual ~bar();

    protected:
        void move_widget(int x, int y);
        Gtk::Fixed fixed;
        ButtonBox box;

    private:
};

#endif // FIXEDLAYOUT_H

Solution

  • dragger->signal_drag_update().connect(sigc::mem_fun(*this, &ButtonBox::update_drag));
    

    Here is how you connect a signal to a callback method. this is the pointer to the actual instance of the class. So how to connect to an instance of another class?

    Using a pointer

    If you need to connect a signal to a method of another class instance, you need to provide a pointer to that instance instead of this. Something on the line of:

    signal().connect(sigc::mem_fun(*p, &::callback_name));
    

    Here p is a generic pointer, make it an attribute of your class. Be aware that this makes the two class interdipendent, so is generally not a good idea if you want to make your code reusable.

    In your case, you need to put a pointer to a FixedLayout instance in ButtonBox.

    class ButtonBox: public Gtk::VBox
    {
        private: #could be whatever
        FixedLayout *ptofl;
    
    };
    

    And in your constructor:

    whatever_signal().connect(sigc::mem_fun(*ptofl, &FixedLayout::name_of_the_method));
    

    Inheritance

    Another way could be to make ButtonBox child of FixedLayout:

    class ButtonBox: public Gtk::VBox, public FixedLayout
    

    You need to invert the order definition of the two classes. Then from ButtonBox you can access protected and public methods of FixedLayout and in your code you can use ButtonBox instances only. When connecting the signals to a callback, you can use the this pointer as usual.