1

我做了一个程序来计算窗口形状的面积和体积。一切正常,除了关于使用Gtk::Entry::signal_activate(). 在以下代码中:

  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;

 // ...

如果我从选项案例 2 开始,一切正常。如果我通过案例 1,然后是案例 2,则按 enter 键会将焦点转移到下一个Gtk::Entry但也会启动calculation()我试图避免的功能。我认为Gtk::Entry::signal_activate()处理程序在通过案例 1 后没有断开连接,但我不知道为什么,因为我sigc::connection::disconnect()在进入案例 2 时正在调用。

我怎样才能使这项工作?

4

2 回答 2

1

我写了一个小程序来复制你的问题:

#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);
}

这个程序有两种情况,就像你的一样,对信号执行相同的基本操作。您可以使用按钮激活不同的场景:

在此处输入图像描述

运行程序并单击按钮,然后按 Enter 键,将产生以下输出:

  • 行动一:Action 1 : calcul() called
  • 行动二:无
  • 行动 1 和 2:Action 1 : calcul() called

从我在这个程序中可以看到,信号连接中似乎存在某种“堆叠”。取消注释这一行:

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

产生以下输出:

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

这是非常令人惊讶的,因为官方文档中没有记录这种行为。无论如何,要解决您的问题,您似乎必须在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;

注意:我的 Gtkmm 版本是 3.22。

于 2021-02-27T14:28:15.733 回答
1

首先添加此标题。请参阅sigc++的文档

#include <sigc++/connection.h>

我们必须断开信号并停止它

在你自己的类中声明

sigc::connection c;

然后在你的主程序中我们可以做类似的事情

  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;
于 2021-03-05T08:16:23.690 回答