1

I made a program to calculate the area and volume of shapes from a window. Everything works, except one thing regarding the use of Gtk::Entry::signal_activate(). In the following code:

 sigc::connection c = elongueur.signal_activate().connect([this]() { calcul(); }); switch (forme) { case 1: //carré cacheEntry(); c.connected(); labelForme.set_label(listeDeroulante.get_active_text()); labelLongueur.set_label("longueur"); break; case 2: //rectangle c.disconnect(); elargeur.set_sensitive(true); labelForme.set_label(listeDeroulante.get_active_text()); labelLongueur.set_label("longueur"); labelLargeur.set_label("largeur"); elongueur.signal_activate().connect([this]() { elargeur.grab_focus(); }); elargeur.signal_activate().connect([this]() { calcul(); }); break; // ... 

if I start with option case 2 everything works fine. If I go through case 1 and then case 2, pressing the enter key shifts the focus to the next Gtk::Entry but also launches the calculation() function, which I'm trying to avoid. I think the Gtk::Entry::signal_activate() handler is not disconnected after passing through case 1, but I don't know why since I am calling sigc::connection::disconnect() when entering case 2.

How could I make this work?

0

2 Answers 2

1

I wrote a small program to replicate your issue:

#include <iostream> #include <gtkmm.h> class MyWindow : public Gtk::ApplicationWindow { public: MyWindow() { m_btn1.signal_clicked().connect([this](){PerformAction1();}); m_btn2.signal_clicked().connect([this](){PerformAction2();}); m_btn1And2.signal_clicked().connect([this](){PerformActions1And2();}); m_entryA.set_text("Entry A"); m_entryB.set_text("Entry B"); m_layout.attach(m_entryA, 0, 0, 1, 1); m_layout.attach(m_entryB, 1, 0, 1, 1); m_layout.attach(m_btn1, 0, 1, 2, 1); m_layout.attach(m_btn2, 0, 2, 2, 1); m_layout.attach(m_btn1And2, 0, 3, 2, 1); add(m_layout); } void Calcul() { std::cout << "calcul() called" << std::endl; } void PerformAction1() { // Add another handler here to amplify the problem: // m_signalEntryA = m_entryA.signal_activate().connect([this](){std::cout << "Action 0 : "; Calcul();}); m_signalEntryA = m_entryA.signal_activate().connect([this](){std::cout << "Action 1 : "; Calcul();}); // Works if you uncomment here: // m_signalEntryA.disconnect(); } void PerformAction2() { m_signalEntryA = m_entryA.signal_activate().connect([this](){std::cout << "Action 2 : "; Calcul();}); m_signalEntryA.disconnect(); m_signalEntryA = m_entryA.signal_activate().connect([this](){m_entryB.grab_focus();}); m_entryB.signal_activate().connect([this](){Calcul();}); } void PerformActions1And2() { PerformAction1(); PerformAction2(); } private: Gtk::Grid m_layout; Gtk::Entry m_entryA; Gtk::Entry m_entryB; Gtk::Button m_btn1{"Action 1"}; Gtk::Button m_btn2{"Action 2"}; Gtk::Button m_btn1And2{"Actions 1 and 2"}; sigc::connection m_signalEntryA; }; int main(int argc, char* argv[]) { auto app = Gtk::Application::create(argc, argv, "so.question.q66320704"); MyWindow window; window.show_all(); return app->run(window); } 

This program has two cases, like yours that do the same fundamental operations on signals. You can activate the different scenarios using the buttons:

enter image description here

Running the program and clicking the buttons, then the Enter key, yields the following output:

  • Action 1: Action 1 : calcul() called
  • Action 2: Nothing
  • Actions 1 and 2: Action 1 : calcul() called

From what I can see in this program, it seems that there is some sort of "stacking" in the signal connections. Uncommenting this line:

m_signalEntryA = m_entryA.signal_activate().connect([this](){std::cout << "Action 0 : "; Calcul();}); 

yield the following output:

Action 0 : calcul() called Action 1 : calcul() called 

This was very surprising as this behavior is not documented in the official documentation. Anyway, to solve your issue, it seems you have to call disconnect early, just before break.

sigc::connection c = elongueur.signal_activate().connect([this]() { calcul(); }); switch (forme) { case 1: //carré cacheEntry(); c.connected(); labelForme.set_label(listeDeroulante.get_active_text()); labelLongueur.set_label("longueur"); c.disconnect(); // <-- Add this. The connection is no more needed. break; case 2: //rectangle c.disconnect(); elargeur.set_sensitive(true); labelForme.set_label(listeDeroulante.get_active_text()); labelLongueur.set_label("longueur"); labelLargeur.set_label("largeur"); elongueur.signal_activate().connect([this]() { elargeur.grab_focus(); }); elargeur.signal_activate().connect([this]() { calcul(); }); break; 

Note: My Gtkmm version is 3.22.

Sign up to request clarification or add additional context in comments.

4 Comments

if you add output's function calculation() in a std::cout you have to add also signal_activate().emission_stop(). For example something like this elargeur.signal_activate().connect([this]() { calcul(); elargeur.signal_activate().emission_stop(); }); otherwise it repeats std::coutmany times. This means the signal is not totally deactivated
Hmm... I'm not sure I understand. Are you still having your issue even when adding the extra c.disconnect() that I am suggesting?
yes still having issue. To solve it i added emission_stop() like i said before
Ok, then I suggest you add your own answer and accept it to help other members of the community who will encounter a similar issue.
1

First add this header. See documentation from sigc++

#include <sigc++/connection.h> 

We have to disconnect signal and stop it

Declare in your own class

sigc::connection c; 

then in your main programm we can do something like that

 switch (forme) { case 1: // carré cacheEntry(); labelForme.set_label(listeDeroulante.get_active_text()); labelLongueur.set_label("longueur"); if (c.connected() == false) { c = elongueur.signal_activate().connect([this]() { calcul(); }); } break; case 2: // rectangle c.disconnect();//disconnected signal elargeur.set_sensitive(true); labelForme.set_label(listeDeroulante.get_active_text()); labelLongueur.set_label("longueur"); labelLargeur.set_label("largeur"); elongueur.signal_activate().connect([this]() { elargeur.grab_focus(); }); elargeur.signal_activate().connect([this]() { calcul(); elargeur.signal_activate().emission_stop();/*stop signal*/ }); break; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.