QSignalMapper是如何工作的?

11

在我发表了这篇帖子之后:Associate signal and slot to a qcheckbox create dynamically,我需要将:

• 当我点击一个qCheckBox时,将信号clicked()与我的函数cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)关联起来。

为此,我必须使用QSignalMapper。经过两个小时的努力,我仍然无法得出好的结果。以下是我编写的代码,显然是错误的:

 QSignalMapper *m_sigmapper = new QSignalMapper(this);
 QObject::connect(pCheckBox, SIGNAL(mapped(QTableWidget*,int, QCheckBox*)), pCheckBox, SIGNAL(clicked()));
 QObject::connect(this, SIGNAL(clicked()), this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));

 m_sigmapper->setMapping(pCheckBox, (monTab,ligne, pCheckBox));
 QObject::connect(m_sigmapper, SIGNAL(clicked()),this, SLOT(cliqueCheckBox(QTableWidget *monTab, int ligne, QCheckBox *pCheckBox)));

你能解释一下 QSignalMapper 是如何工作的吗?我不是很明白应该关联什么 :(


为什么必须使用 QSignalMapper?有什么特别的原因吗?这可以通过直接连接轻松完成。 - Rakib
好的,在另一篇帖子中,他们向我解释说一个信号不能连接到一个带有更多参数的槽,并且 clicked() 信号没有参数。同时,我需要这三个参数。 - Evans Belloeil
是的,但我如何传递给他这3个参数:QTableWidget *monTab,int ligne,QCheckBox *pCheckBox?如果您读了其他帖子,您会发现我有数百个qCheckBox,因此我无法使用指针。 - Evans Belloeil
@EvansBelloeil,为了理解QSignalMapper的工作原理,这里有一个很好的例子可以供您参考。 - Tay2510
@Tay2510 我已经看过了,但还是谢谢你。也许我太蠢了,但它并没有对我有太大帮助。 - Evans Belloeil
显示剩余4条评论
2个回答

14

首先,我会向你解释一下QSignalMapper的工作原理。然后,我会告诉你为什么你不需要它。

QSignalMapper的工作方式:

创建一个QSignalMapper对象。假设您想要为每个复选框分配一个整数值,因此每次单击任何复选框时,您将获得带有分配给它的整数值的信号。

将映射器信号连接到您将实现的SLOT:

connect(mapper, SIGNAL(mapped(int)), this, SLOT(yourSlot(int)));

现在你可以编写一个带整数参数的插槽。每个复选框的参数都将不同。

在创建复选框时,需要为每个复选框执行以下操作:

mapper->setMapping(checkBox, integerValueForThisCheckbox);
connect(checkBox, SIGNAL(clicked()), mapper, SLOT(map()));

从现在开始,每当您点击一个复选框时,它将向 QSignalMapper 发出 clicked() 信号,然后映射到分配的整数值并发出 mapped() 信号。您连接到了那个 mapped() 信号,因此yourSlot(int) 将使用正确的整数值进行调用。

除了整数外,您还可以分配 QStringQWidget*QObject*(请参见 Qt 文档)。

这就是 QSignalMapper 的工作原理。

您不需要它:

  • QTableWidget *monTab 是单个对象,它不会改变。将其保留为类成员字段,并从您的槽函数中使用它。
  • QCheckBox *pCheckBox - 您可以通过将 sender() 转换为 QCheckBox* 来获取它。

像这样:

void supervision::yourSlot()
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) // this is just a safety check
        return;
}

sender()函数来自QObject,你继承了它,所以你可以访问它。

  • 当你创建复选框时,可以将指向该复选框的指针存储在QList类字段中,并从你的槽函数中使用它来找出它是哪一行,例如:

在类声明中:

private:
    QList<QCheckBox*> checkboxes;

创建复选框时:

QCheckBox* cb = new QCheckBox();
checkboxes << cb;

在您的槽函数中:

void supervision::yourSlot()
{
    QCheckBox* pCheckBox = qobject_cast<QCheckBox*>(sender());
    if (!pCheckBox) // this is just a safety check
        return;

    int linge = checkboxes.indexOf(pCheckBox);
}
如果你愿意,可以跳过那个并使用,然后使用映射器将行分配给复选框。这只是你偏好的问题。

谢谢你的回答,非常好而且非常完整。我的问题是有几个QTableWidget,所以如果我不使用QSignalMapper,我认为访问这些QTableWidget的方法是使用QCheckBox上的parent()。看起来我被迫使用很多技巧,这可能会导致问题,因为我的代码必须具有灵活性。所以我首先会尝试使用QSignalMapper。你能否提供更详细的信息?(对不起,这对我来说非常难理解) - Evans Belloeil

14

QSignalMapper 类收集一组无参信号,并使用与发送信号的对象相对应的整数、字符串或小部件参数重新发出它们。因此,您可以创建一个类似这样的对象:

QSignalMapper * mapper = new QSignalMapper(this);
QObject::connect(mapper,SIGNAL(mapped(QWidget *)),this,SLOT(mySlot(QWidget *)));

对于您的每个按钮,可以将 clicked() 信号连接到 QSignalMappermap() 插槽,并使用 setMapping 添加映射,以便当来自按钮的 clicked() 信号被触发时,会发出 mapped(QWidget *) 信号:

QPushButton * but = new QPushButton(this);

QObject::connect(but, SIGNAL(clicked()),mapper,SLOT(map()));
mapper->setMapping(but, but);

这样,每当您点击一个按钮时,映射器的 mapped(QWidget *) 信号就会被发射,包含该小部件作为参数。


谢谢!它可以工作,但是我怎么能够放置3个参数?这是可能的吗?因为似乎我只能放置1个,因为映射(QWidget *)。 - Evans Belloeil
不可能有多于一个参数。你可以将另一个小部件作为类成员,并在槽中访问它们。 - Nejat
什么是类成员?如果我不能将其作为参数传递,我该如何找到它? - Evans Belloeil
我是说你可以把指向小部件的指针放在你的类 .h 文件中,作为私有变量。然后你就可以访问它们了。 - Nejat
1
不应在面向对象编程中使用全局变量。您可以在类中简单地访问小部件的指针。 - Nejat
让我们在聊天中继续这个讨论 - Evans Belloeil

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接