此问题已在此处有答案:
Unable to connect signal to slot in another class(2个答案)
3天前关闭。
截至3天前,社区正在审查是否重新讨论此问题。
我有两个班:第一个是主QMainWindow类,第二个是我的自定义类。例如,我想在我的自定义类的构造函数中建立一个连接,当我按下TestButton(它是main类的ui的一部分)时,它会从我的自定义类中调用一个函数。代码如下:
程序h:
class Custom;
class Program : public QMainWindow
{
Q_OBJECT
friend class Custom;
public:
Program(QWidget *parent = nullptr);
~Program();
private:
Ui::ProgramClass ui;
}
Program.cpp:
#include "Program.h"
#include "Custom.h"
Program::Program(QWidget *parent)
: QMainWindow(parent)
{
ui.setupUi
Custom custom = Custom(this);
}
自定义h:
#include "Program.h"
class Custom : public QObject {
Q_OBJECT
public:
Custom(Program* program);
~Custom();
public slots:
void foo();
private:
Program* m_program;
}
最后是Custom.cpp:
#include "Custom.h"
#include "Program.h"
Custom::Custom(Program* program) {
m_program = program;
/* Here's the main problem */
QObject::connect(m_program->ui.TestButton, &QPushButton::clicked, m_program, &Custom::foo);
}
/* Here just changing text of the button and set flat true or false every time button is clicked */
void Custom::foo() {
QPushButton* button = m_program->ui.TestButton;
button->setFlat(!button->isFlat());
button->setText(button->isFlat() ?
"If you see the text changing when clicking the button, it means test is working correctly" :
"Text changed");
}
主要部分在自定义构造函数中,我在其中键入了connect函数。
错误:无法将参数3从“Program *”转换为“const Custom *”。因此,指向receiver和函数foo
的指针必须是相同的类。
所以我试了这个:QObject::connect(m_program->ui.TestButton, &QPushButton::clicked, this, &Custom::foo);
没有错误,但实际上没有连接到主程序,当我点击按钮-没有什么变化。
唯一的工作变量是:
- 让
foo
函数作为Program类的方法,但我不想让Program类有很多实际上应该是独立类的方法的函数。如果我想修改这些分离类的其他字段,这个变体将不起作用; - 在QObject::connection中输入lambda-function,但是我有一些大的函数,我需要经常在QObject::connect中调用其中的一些函数。
那么,我怎样才能正确地连接到整个程序,而不把foo
函数作为自定义类的方法呢?
1条答案
按热度按时间baubqpgj1#
行
Custom custom = Custom(this);
创建了一个本地对象,它在退出Program
构造函数后“立即死亡”,这不是你想要做的。下面是要持久化Custom
的示例所必须做的:你甚至可以让名为
custom
的指针成为一个成员变量,如果你想以后访问它的话。Custom
的构造函数必须是:该构造函数将指针传递给
QObject
的构造函数,该构造函数将Custom
注册为所提供对象的“子”,在我们的示例中为Program
。在Qt术语中,Program
将负责Custom
示例的销毁。是你想做的吗?要将按钮连接到
Custom
的示例,请执行以下操作:坦率地说,在这里使用m_program->ui.TestButton
侵犯了Program
的个人空间,并依赖于实现,但这在这里是一个题外话。但让我们退一步来看看,为什么你所做的,即使是完全错误的,也没有成功?
让我们把函数和插槽放在一边。如果必须对“普通”类这样做,并使用一个不同的
class A
指针调用类B
的方法foo()
,你会怎么做?正确,类
B
应该派生自A
,foo()
应该是在A
中首先声明的虚方法。THis允许一种类型擦除,其中指向B的指针或引用可以作为指向A的指针传递。函数也可以通过指针传递,但如果它们是类的成员则不行。为此,存在一种特殊的指针。现在,您必须了解
C::connect
在那里做了什么:它保存指向对象A* p
的指针的值和指向成员的指针。表达式&A::foo
,一个指向A的成员的指针,如果我们将它与指向B
的指针一起使用,那么对于被重写的&B::foo
来说是法律的和正确的。指向成员的指针可以像Qt中那样作为
C::connect
的参数,但要使其与任何成员函数一起工作,我们需要创建一个模板和另一个级别的类型擦除来保存这些值。我为了简洁起见把它省略了。这几乎和Qt信号\插槽系统一样,至少如果你使用直接连接和新的连接语法。你需要一个类示例来调用它的成员,这就是为什么
connect
有这样的语法。即使您成功地执行了连接,您也会通过单击连接按钮来调用未定义的行为。值得庆幸的是,Qt通过断开被破坏的对象来优雅地处理它,* 因此实际上什么也没有发生。这就是为什么所有使用signal\slot的类都必须是
QObject
的后代。信号和插槽只是函数。它们之间的区别在于 meta对象编译器生成信号的实现。要使类型擦除工作,可以执行以下操作之一:
1.必须将类型为
QObject*
的指针传递给Custom
的示例,并将其转换为class Custom
,以便QObject::connect
工作。如果在QObject
中声明了signal或 virtual slot,则不需要强制转换。1.或者你必须传递一个指向某个基类的指针,这个基类已经声明了插槽
void foo()
。在我看来,将
QMainWindow
作为基类是一个坏主意,你需要一些第三类。在最简单的情况下,它创建了过于冗长的代码,这就是为什么引入了另一个重载,它允许lambda或functor对象。