信号与槽
- connect函数参数中‘槽函数实参’没有声明为slots时,编译不会报错,但是也不会起作用(被执行)。
- 注意qt4和qt5两种版本下connect函数中信号和槽函数的形参不同。
- 使用qt5语法时,若信号存在重载,则connect函数编译时会报错,不能准确的与槽函数(形参格式)相匹配!这时要么用qt4形式,要么通过static_cast方法进行数据类型装换,如:
(将QButtonGroup::buttonClicked强制装换为形参是int的那个)
参考:https://blog.youkuaiyun.com/f_zyj/article/details/82018147 - C++中"A:: "的意思:指向类A中任意元素的指针(变量、方法),如:
int A:: point_i2,表示point_i2是一个指向类A中int变量的指针;
如果A::fun存在重载,则:static_cast<void (A:😗)(int)>(&fun):表示将fun函数指针强制装换为类A中形参格式为int的那个重载函数的函数指针。(有歧义,待改正)
- qt中使用资源文件时,如果编译提示:
原因:一般由于文件资源路径改动后导致。
解决办法:将工程目录下对应工程的Debug文件删除,重新编译工程即可。 - 在为button和form设置icon时,icon的路径没有问题,但就是不显示icon内容,删除debug文件夹也无效,后来在qt creater中删除*.qrc资源树下导入的文件,重新添加后恢复正常,不知道以后会不会再遇到!
- C++中静态成员(变量和方法)的作用、理解及其使用(不需要依赖具体的对象)
创建对象:使用和不使用new
- 不使用new关键字(
QLabel label1;
):新建的对象位于栈中,属于局部变量,在函数结束后被自动销毁; - 使用new关键字(
QLabel *label2=new QLabel;
):新建的对象位于堆中,生命周期通常比栈中变量长,需要手动释放。 - 下面通过4种形式分别测试在不同位置创建QPushButton对象,对应的现象:
- 在类的构造函数中不使用new创建:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
// QPushButton btn1("btn1", &w);
// QPushButton *btn2=new QPushButton("btn2", &w);
w.show();
return a.exec();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
QPushButton btn1("btn1", this);
// QPushButton *btn2=new QPushButton("btn2", this);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:按钮未显示
- 在类的构造函数中使用new创建:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
// QPushButton btn1("btn1", &w);
// QPushButton *btn2=new QPushButton("btn2", &w);
w.show();
return a.exec();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
// QPushButton btn1("btn1", this);
QPushButton *btn2=new QPushButton("btn2", this);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:按钮正常显示
- 在main函数中不使用new创建:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
QPushButton btn1("btn1", &w);
// QPushButton *btn2=new QPushButton("btn2", &w);
w.show();
return a.exec();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
// QPushButton btn1("btn1", this);
// QPushButton *btn2=new QPushButton("btn2", this);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:按钮正常显示
- 在main函数中使用new创建:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
// QPushButton btn1("btn1", &w);
QPushButton *btn2=new QPushButton("btn2", &w);
w.show();
return a.exec();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
// QPushButton btn1("btn1", this);
// QPushButton *btn2=new QPushButton("btn2", this);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:按钮正常显示
经测试发现:通过new关键字在堆上创建对象时,无论是在类的函数中还是在main函数中,都可以正常显示;不使用new关键字在类的函数中创建对象时,对象不可见,因为在类函数执行结束后,对象也被销毁;不使用new关键字在main函数中创建对象时,对象也可见,因为当前对象的声明周期是在main函数内,而main函数因为return a.exec();
的存在而不会退出;最后我们再做个测试:
- 在main函数中不使用new创建,但放置在函数体中:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
do{
QPushButton btn1("btn1", &w);
}while(0);
// QPushButton *btn2=new QPushButton("btn2", &w);
w.show();
return a.exec();
}
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
//
// QPushButton btn1("btn1", this);
// QPushButton *btn2=new QPushButton("btn2", this);
}
MainWindow::~MainWindow()
{
delete ui;
}
运行结果:按钮不显示
和预料中一样,对象在do…while的花括号结束后就被销毁了,所以不可见。
创建对象但不指定parent时的现象
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
// do{
// QPushButton btn1("btn1", &w);
// }while(0);
QPushButton *btn2=new QPushButton("btn2", &w);
QPushButton *btn3=new QPushButton("btn3");
btn3->show();
w.show();
return a.exec();
}
结果:
- 这两个窗体是不是模态的,相互可以叠加,各自的按钮也可以单独按下;
- 关闭其中任意一个,程序都不会结束,除非两个窗体都关闭。
待研究。。。
父、子对象析构顺序测试
- 先在栈中定义子对象,再定义父对象,子对象再绑定父对象:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
#include <QMenuBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QPushButton btn1("btn1");
// QPushButton *btn3=new QPushButton("btn3");
MainWindow w;
btn1.setParent(&w);
// btn3->setParent(&w);
w.show();
return a.exec();
}
关闭窗口后,程序崩溃。
- 先定义父对象,再在栈中定义子对象,子对象再绑定父对象:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
#include <QMenuBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QPushButton *btn3=new QPushButton("btn3");
MainWindow w;
QPushButton btn1("btn1");
btn1.setParent(&w);
// btn3->setParent(&w);
w.show();
return a.exec();
}
关闭窗口后,程序正常结束。
- 先在堆中定义子对象,再定义父对象,子对象再绑定父对象:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
#include <QMenuBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QPushButton btn1("btn1");
QPushButton *btn3=new QPushButton("btn3");
MainWindow w;
// btn1.setParent(&w);
btn3->setParent(&w);
w.show();
return a.exec();
}
关闭窗口后,程序正常结束。
- 先定义父对象,再在堆中定义子对象,子对象再绑定父对象:
#include "mainwindow.h"
#include <QApplication>
#include <QPushButton>
#include <QMenuBar>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// QPushButton btn1("btn1");
MainWindow w;
// btn1.setParent(&w);
QPushButton *btn3=new QPushButton("btn3");
btn3->setParent(&w);
w.show();
return a.exec();
}
关闭窗口后,程序正常结束。
分析(局部对象的析构顺序应该按照其创建顺序的相反过程):
1. 在堆上创建的对象不论创建顺序前后,程序都会正常结束;
2. 如果在栈上创建的子对象比父对象先创建,在父对象先调用析构函数且释放其所有子对象后,子对象的析构函数再次被调用,所以造成程序异常崩溃;
3. 在栈上创建的子对象在父对象之后创建,则会先调用子对象的析构函数将其从父对象 window 的子对象列表中删除,然后才会再调用 window 的析构函数,程序正常结束。
结论:
- 在栈上创建子对象时就绑定父对象,在父对象还不存在时编译器会报错,起到提示作用,避免程序运行后才感知到错误。
- 尽量在堆上创建子对象,可以避免定义的顺序问题。