在c++qt中遇到一个关于lambda引用捕获的问题;下面的QtWidgetsApplication1函数是析构函数,所属的类是创建窗口的类
在我建立的这个链接中用到lambda的引用捕获,我试图对新窗口w2和按钮btn进行引用,结果会报错访问冲突;
QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
: QMainWindow(parent)
{
MyPushButton* btn = new MyPushButton(this);
NewWidget* w2 = new NewWidget;
btn->setText("按钮");
connect(btn, &MyPushButton::clicked, [&]() {
if (btn->text() == "按钮")
{
w2->show();
btn->setText("消解");
}
else
{
w2->close();
btn->setText("按钮");
}
});
}
但当我不用lambda建立引用,直接在该函数中建立引用新窗口和按钮进行修改时,程序正常运行,这是为什么呢
QtWidgetsApplication1::QtWidgetsApplication1(QWidget* parent)
: QMainWindow(parent)
{
MyPushButton* btn = new MyPushButton(this);
NewWidget* w2 = new NewWidget;
btn->setText("按钮");
MyPushButton*& p = btn;
p->setText("修改后的按钮");
}
指针就应该用=啊,如果用引用,你引用的是临时创建的btn和w2变量,而这两个变量在构造函数结束后就销毁了,所以引用的对象就没了,如果用=则是取它们的值,也就是指针地址,还是有效的
答:了解。Qt对标准的C++进行了扩展,如信号槽、对象属性等。Qt的元对象编译系统MOC是一个预处理器,当Qt读取源文件时检测到类中包含有Q_OBJECT宏时,则会创建一个新的文件(生成路径下的moc开头的文件),将源码转换为C++编译器可以识别的代码写入moc开头的文件,然后C++编译器对其进行编译。当你的类需要使用Qt的扩展功能时,如信号槽、对象属性等时,则必须使用MOC,反之如果你的类不使用这些功能的时候不要无畏的使用MOC增大源码体积。使用MOC系统的方法:
1. 继承QObject。
2. 类中添加Q_OBJECT宏。
答:了解。信号和槽是用于对象之间的通信的,是Qt的核心。为此Qt引入了一些关键字,他们是slots、signals、emit,这些都不是C++关键字,是Qt特有的,这些关键字会被Qt的moc转换为标准的C++语句。信号槽支持线程间通信,connect函数的第五个参数可以指定信号槽的连接方式:
1. Qt::AutoConnection:信号的发送者与信号的接收者在同一线程,则默认使用Qt::DirectConnection;如果不在同一线程,则默认 使用Qt::QueuedConnection。
2. Qt::DirectConnection:信号的发送者与信号的接收者在同一线程中执行,当发出信号后,会马上进入槽函数,看上去就像在信号 发送位置调用了槽函数,在多线程下会比较危险,容易造成崩溃。
3. Qt::QueuedConnection:信号的发送者与信号的接收者不在同一线程中执行,槽函数运行于信号的接收者线程,当发送信号后, 槽函数不会马上被调用,等待信号的接收者把当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
4. Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
5. Qt::UniqueConnection:可以通过按位或(|)与以上四个结合在一起使用。当设置此参数时,当某个信号和槽已经连接时,再进行重复的连接就会失败,也就是避免了重复连接。
答:了解。Qt的MVD包含三个部分Model(模型),View(视图),代理(Delegate)。Model否则保存数据,View负责展示数据,Delegate负责Item样式绘制或处理输入。这三部分通过信号槽来进行通信,当Model中数据发生变化时将会发送信号到View,在View中编辑数据时,Delegate负责将编辑状态发送给Model层。基类分别为QAbstractItemModel、QAbstractItemView、QAbstractItemDelegate。Qt中提供了默认实现的MVD类,如QTableWidget、QListWidget、QTreeWidget等。
答:不了解。(工作中没有用到,等我学一波再来补充)
答:了解。Qt的多线程的实现方式有如下四种:
1. QThread类,重写QThread类的run方法。
优点:实现简单,可以用信号槽通信。
缺点:需要自己管理线程的创建释放,频繁地创建释放效率不高。所以适合常驻程序的线程使用。另外因为QThread对象属于父线程,所以对象中的槽函数(如果有的话)其实会在父线程执行。
2. QThread类与MoveToThread,创建对象继承QObject,将对象移动到子线程对象。
优点:实现简单,使用于比较复杂的业务场景。
缺点:只能通过信号槽的方式调用业务对象的接口。且不能给此对象指定父对象。
3. QThreadPool与QRunnable,继承QRunnable实现run方法完成业务类创建,由QThreadPool启动业务类。
优点:无需关注线程资源管理,不会频繁创建与释放线程。所以适用需要频繁创建销毁线程的业务场景。
缺点:没啥缺点。
4. QtConcurrent::run()直接将任务丢进子线程执行。
优点:调用简单,无需关注线程资源管理,不会频繁创建与释放线程。
缺点:没啥缺点。
答:了解。 参考Qt之事件处理机制 - Fate0729 - 博客园。
connect 加上 this
connect(btn, &MyPushButton::clicked, this, [=]() {
if (btn->text() == "按钮")
{
w2->show();
btn->setText("消解");
}
else
{
w2->close();
btn->setText("按钮");
}
});