1、添加git版本控制
版本控制忽略清单:
.DS_Store *-Debug *.userdebug文件夹全部不要,可以运行时生成;.user文件包含用户配置,里面看了下还有绝对路径,这个还是不要把,在另一个地方首次打开只要配置下即可。
即可生成.user文件
2、创建桌面窗口应用的基类选择
基类有3个,那么都有什么区别?
(1)QMainWindow:提供一个有菜单条、工具条、状态条的主应用程序窗口;
(2)QWidget:是所有用户界面对象的基类;
(3)QDialog:顶级对话框。
使用原则:
主窗体,基于QMainWindow创建;
顶级对话框,基于QDialog创建;
需要嵌入到其他窗体中,基于QWidget创建。
3、头文件相关
(1)头文件如何保证不会被重复执行
如果一个头文件被多个源代码文件包含,如何保证他不会被重复执行?
注意看头文件的第一行,有(#ifndef),表示“如果本指令所引用的定义不存在,则执行代码”,保证了如果被多次包含不会重复执行。
(2)explicit用来修饰构造函数,使用了explicit关键字则不可以隐式调用
(3)函数必须在头文件有声明,变量则不需要
4、两种实例创建方式
QAction *quitAction; quitAction = new QAction(tr("退出"),this);//用new的方式返回一个指针 // 使用时如果需要传递指针,直接传quitAction即可 // 使用时如果需要传递对象,则用*quitAction QAction quitAction(tr("退出"),this);// 直接创建,quitAction即是一个QAction对象 // 使用的如果需要传递对象,直接传quitAction // 使用的如果需要传递指针,则用&quitAction
5、指定输出目录
在.pro文件里添加此声明则会将生成文件放到此目录下:
#手动添加:生成的内容放在这里 DESTDIR =..\MyDebug
并且把项目中的shadow build打勾去掉:
6、编辑QComboBox项目
7、main中写函数
在main.cpp中写函数,并在main中调用,一直提示:不在定义范围(意思大致如此)。网上搜遍了原因,大部分人是说:他不属于那个类,肯定调用不到,或者说必须是静态函数才能调用。
今天晚上测试,把要调用的函数放到main前面,就可以了...
另:在main文件的顶级定义变量和函数,即可获得全局变量。
8、生成依赖的Qt-DLL
因为我们开发环境都有Qt的DLL,并且配置了环境变量,所以只要一个exe文件就可以打开并运行qt程序。
但是用户电脑上没有这些DLL,我们需要给他放到同一个文件夹中让exe调用。
Qt自带一个工具可以生成这些依赖的DLL。
<1>把exe拷贝到一个文件夹里;
<2>cmd进入到此目录;
<3>执行命令 windeployqt 文件名.exe即可。
7、QGridLayout使用
通过addWidget添加控件。
QGridLayout::addWidget ( QWidget * widget, int row, int column, Qt::Alignment alignment = 0 )
参数为:控件名、行、列、占用行数、占用列数、对齐方式
比如一个列数为2的布局,那么有一个控件需要跨越2个列,就是说别人占一小格(一半),他全占了,那么应该这样写:
topLayout->addWidget(textEdit,2,0,1,2);
8、示例:页面布局及颜色控制
此示例是从别人博客看到了,后来再查一下,真正出处可能是这里:https://www.cnblogs.com/hanzhaoxin/archive/2012/11/18/2775918.html,在此表示感谢!
#include "palette.h" #include <QBoxLayout> Palette::Palette(QWidget *parent) : QDialog(parent) { createCtrlFrame(); createContentFrame(); QHBoxLayout *mainLayout = new QHBoxLayout(this); mainLayout->addWidget(ctrlFrame); mainLayout->addWidget(contentFrame); } // 左边控制颜色的下拉框 void Palette::createCtrlFrame() { ctrlFrame = new QFrame; //窗口背景色 windowLabel = new QLabel(tr("QPalette::window: ")); windowComboBox = new QComboBox; fillColorList(windowComboBox); connect(windowComboBox,SIGNAL(activated(int)),this,SLOT(showWindow())); windowTextLabel = new QLabel(tr("QPalette::WindowText: ")); //窗口前景色 windowTextComboBox = new QComboBox; fillColorList(windowTextComboBox); connect(windowTextComboBox,SIGNAL(activated(int)),this,SLOT(showWindowText())); buttonLabel = new QLabel(tr("QPalette::Button: ")); //窗口按钮的颜色 buttonComboBox = new QComboBox; fillColorList(buttonComboBox); connect(buttonComboBox,SIGNAL(activated(int)),this,SLOT(showButton())); buttonTextLabel = new QLabel(tr("QPalette::ButtonText: ")); //窗口按钮上面文本的颜色 buttonTextComboBox = new QComboBox; fillColorList(buttonTextComboBox); connect(buttonTextComboBox,SIGNAL(activated(int)),this,SLOT(showButtonText())); baseLabel = new QLabel(tr("QPalette::Base: ")); baseComboBox = new QComboBox; fillColorList(baseComboBox); connect(baseComboBox,SIGNAL(activated(int)),this,SLOT(showBase())); QGridLayout *mainLayout = new QGridLayout(ctrlFrame); mainLayout->setSpacing(20); mainLayout->addWidget(windowLabel,0,0); mainLayout->addWidget(windowComboBox,0,1); mainLayout->addWidget(windowTextLabel,1,0); mainLayout->addWidget(windowTextComboBox,1,1); mainLayout->addWidget(buttonLabel,2,0); mainLayout->addWidget(buttonComboBox,2,1); mainLayout->addWidget(buttonTextLabel,3,0); mainLayout->addWidget(buttonTextComboBox,3,1); mainLayout->addWidget(baseLabel,4,0); mainLayout->addWidget(baseComboBox,4,1); } // 右边是内容 void Palette::createContentFrame() { contentFrame = new QFrame; // 第一行 // 左边是一个label显示文字说明 label1 = new QLabel(tr("请选择一个值:")); // 右边是一个下拉框 comboBox1 = new QComboBox; // 第二行 // 左边是一个label label2 = new QLabel(tr("请输入字符串: ")); // 右边是一个输入框 lineEdit2 = new QLineEdit; // 第三行 // 是一个大的文本编辑框 textEdit = new QTextEdit; // 做一个表格布局 QGridLayout *topLayout = new QGridLayout; // 00 topLayout->addWidget(label1,0,0); // 01 topLayout->addWidget(comboBox1,0,1); // 10 topLayout->addWidget(label2,1,0); // 11 topLayout->addWidget(lineEdit2,1,1); // 从2,0开始,占用行数,占用列数 topLayout->addWidget(textEdit,2,0,1,2); // 确认与取消按钮 okBtn = new QPushButton(tr("确认")); cancelBtn = new QPushButton(tr("取消")); // 一个水平布局容器 QHBoxLayout *bottomLayout = new QHBoxLayout; // addStretch这样理解: // 从左到右: // 先添加1根弹簧,然后添加两个按钮,然后再添加2根弹簧 // 那么效果可以看到,中间2个按钮,左边一个空白,右边一个空白,右边的空白是左边的2倍 bottomLayout->addStretch(1);// 将空白widget分成n份,然后按参数大小分配弹簧 bottomLayout->addWidget(okBtn); bottomLayout->addWidget(cancelBtn); bottomLayout->addStretch(2); // 最后一个是右布局的主容器 // 添加一个上容器一个下容器 QVBoxLayout *mainlayout = new QVBoxLayout(contentFrame); mainlayout->addLayout(topLayout); mainlayout->addLayout(bottomLayout); okBtn->setAutoFillBackground(true); //允许自动填充 cancelBtn->setAutoFillBackground(true); contentFrame->setAutoFillBackground(true); } void Palette::showWindow() //用于控制背景颜色的显示 { QStringList colorList = QColor::colorNames(); QColor color = QColor(colorList[windowComboBox->currentIndex()]); // contentFrame->setAutoFillBackground(true); QPalette p = contentFrame->palette(); p.setColor(QPalette::Window, color); contentFrame->setPalette(p); contentFrame->update(); } void Palette::showWindowText() //对窗体的前景色进行设置 { QStringList colorList = QColor::colorNames(); QColor color = colorList[windowTextComboBox->currentIndex()]; QPalette p = contentFrame->palette(); p.setColor(QPalette::WindowText, color); contentFrame->setPalette(p); } void Palette::showButtonText() { QStringList colorList = QColor::colorNames(); QColor color = QColor(colorList[buttonTextComboBox->currentIndex()]); QPalette p = contentFrame->palette(); p.setColor(QPalette::ButtonText , color); contentFrame->setPalette(p); } void Palette::showBase() { QStringList colorList = QColor::colorNames(); QColor color = QColor(colorList[baseComboBox->currentIndex()]); QPalette p = contentFrame->palette(); p.setColor(QPalette::Base , color); contentFrame->setPalette(p); } void Palette::fillColorList(QComboBox *comboBox) { QStringList colorList = QColor::colorNames(); QString color; foreach (color, colorList) { QPixmap pix(QSize(70,20)); pix.fill(QColor(color)); comboBox->addItem(QIcon(pix), NULL); comboBox->setIconSize(QSize(70,20)); comboBox->setSizeAdjustPolicy(QComboBox::AdjustToContents); } } void Palette::showButton() { QStringList colorList = QColor::colorNames(); QColor color = QColor(colorList[buttonComboBox->currentIndex()]); //contentFrame->setAutoFillBackground(true); QPalette p = contentFrame->palette(); p.setColor(QPalette::Button , color); contentFrame->setPalette(p); contentFrame->update(); } Palette::~Palette() { }
9、QDialog与QMainWindow的区别
有的QMainWindow的上部(页眉)有一些部件,用于创建菜单,而QDialog没有;
QMainWindow能直接转为QDialog吗?
从代码上看,只要把QMainWindow换成QDialog就完全一样了,但是运行的时候报错:ui->setupUi(this)类型错误,即这个this是属于QMainWindow类型而非QDialog类型。
原因就在于,这个设计界面集成的类不能改,因此直接改成QDialog还是不行的。
如果使用无边框界面,使用QMainWindow的情况下,页眉有些白白的东西不够纯粹,因此想改为QDialog,其实可以直接进入ui设计页面,删掉这个页眉,解决。
10、设置窗口大小
resize(QSize(800,600));
11、判断是否为空指针
if(&labelIcon==Q_NULLPTR) { qDebug()<<"labelIcon不存在"; }else { qDebug()<<"labelIcon存在"; }
12、动态添加ui组件方式
动态添加组件,要用:
QLabel * labelIcon2 = new QLabel;
不要用:
QLabel labelIcon1;
后者得到的只能是一片空白。
// 设置标题栏 // QFrame做背景 QFrame * headFrame = new QFrame; // icon加载 QPixmap pixmapLabelIcon; pixmapLabelIcon.load(":/img/zeesan.jpg"); QPixmap pixmapLabelIcon2; pixmapLabelIcon2.load(":/img/headIcon2.png"); QLabel labelIcon1; labelIcon1.setFixedSize(pixmapLabelIcon.width(),pixmapLabelIcon.height()); labelIcon1.setPixmap(pixmapLabelIcon); QLabel * labelIcon2 = new QLabel; labelIcon2->setFixedSize(pixmapLabelIcon2.width(),pixmapLabelIcon2.height()); labelIcon2->setPixmap(pixmapLabelIcon2); // 创建一个layout QHBoxLayout * hBoxLayout = new QHBoxLayout(headFrame); hBoxLayout->addWidget(&labelIcon1); hBoxLayout->addWidget(labelIcon2); hBoxLayout->addStretch(1); // headFrame->setAutoFillBackground(true); // QColor color = QColor(37,37,118); // QPalette p = headFrame->palette(); // p.setColor(QPalette::Window,color); // headFrame->setPalette(p); // headFrame->update(); QVBoxLayout * mainLayout = new QVBoxLayout(this); mainLayout->addWidget(headFrame);
13、按钮透明背景
minBtn->setStyleSheet("background-color: rgba(0, 0, 0, 0)");//此种方法完美实现按钮透明背景 // minBtn->setFlat(true);//注意,如果用此种方法实现背景透明,则点击的时候仍然会显示按钮的轮廓,白色
14、动态设置Label字体属性
QLabel * labelStatus = new QLabel; QFont fontStatus; fontStatus.setBold(true); fontStatus.setPointSize(16); fontStatus.setFamily("Microsoft YaHei"); labelStatus->setFont(fontStatus); labelStatus->setText("2018/03/06 10:16:30 通讯成功");
15、QVector的使用:
progressStacked = new QStackedWidget; QVector<int> progressIntArr; progressIntArr<<0<<12<<25<<37<<50<<62<<75<<87<<100; QVector<int>::iterator iter; for(iter = progressIntArr.begin();iter != progressIntArr.end();iter++) { QPixmap pixmapProgress; qDebug()<<*iter; pixmapProgress.load(QString(":/img/progress%1.png").arg(*iter)); QLabel * label = new QLabel; label->setFixedSize(pixmapProgress.width(),pixmapProgress.height()); label->setPixmap(pixmapProgress); progressStacked->addWidget(label); }
16、使用setStyleSheet设置样式
如果在主页面设置:
this->setStyleSheet("border: 1px solid #CCCCCC;");
这样会对这个页面所有组件添加边框。
如果是限定QDialog:
this->setStyleSheet("QDialog{border: 1px solid #CCCCCC;}");
则只对主窗口QDialog添加边框。
注意:如果QDialog有多个,则上述方法又不凑效了。
其实可以应用第一种方法,然后在其子控件添加不需要边框的声明即可:
QPixmap pixmapReportBg; pixmapReportBg.load(":/img/reportBg.png"); reportNameFrameInner->setFixedSize(pixmapReportBg.width(),pixmapReportBg.height()); reportNameFrameInner->setStyleSheet("border-image:url(:/img/reportBg.png)");// 应用背景的控件 labelReportName->setStyleSheet("border-image:null");// 更内一层的控件要这样声明
17、QPushButton的设定
(1)给按钮添加背景图片,没有设定文字
QPushButton * clearCloseBtn = new QPushButton; clearCloseBtn->setFixedSize(pixmapClearClose.width(),pixmapClearClose.height()); clearCloseBtn->setIcon(pixmapClearClose); clearCloseBtn->setIconSize(QSize(pixmapClearClose.width(),pixmapClearClose.height())); clearCloseBtn->setCursor(Qt::PointingHandCursor); clearCloseBtn->setStyleSheet("background-color: rgba(0, 0, 0, 0)");// 此代码令按钮原有边框消失
(2)给按钮添加背景图片,并且在其上设定文字(适用于背景固定但是按钮文字变化的多个按钮)
// 设定按钮背景图片以及文字内容、字体等 clearCloseBtn->setStyleSheet("border-image:url(:/img/clearBtnClose.jpg)"); clearCloseBtn->setText("文字改变"); clearCloseBtn->setFont(fontInnerButton); // 设定按钮文字的颜色 QPalette pal = clearCloseBtn->palette(); pal.setColor(QPalette::ButtonText,QColor("#252576")); clearCloseBtn->setPalette(pal);
18、报错:找不到槽QObject::connect: No such slot
写了一个类继承于QFrame,然后添加槽,运行发现找不到槽(如上提示No such slot);
仔细检查发现在头文件没有添加Q_OBJECT,于是添加上去;
再运行发现类名报错error: undefined reference to vtable for ClassName;
各种查找资料,发现要添加Q_OBJECT之后要执行qmark,于是执行之,解决。
19、QMap的使用
qMap->value(key);直接这样取值。
int indexOfPages = 0; pagesMap = new QMap<PagesEnum,int>; stackedWidget = new QStackedWidget; stackedWidget->addWidget(homePage);//0 pagesMap->insert(PagesEnum::homePage,indexOfPages); stackedWidget->addWidget(runPageFrame);//1 pagesMap->insert(PagesEnum::runPage,++indexOfPages); stackedWidget->addWidget(clearPageFrame);//2 pagesMap->insert(PagesEnum::clearPage,++indexOfPages); stackedWidget->addWidget(reportPage);//3 pagesMap->insert(PagesEnum::reportPage,++indexOfPages);
void Dialog::onPageChangeByEnum(PagesEnum page) { if(pagesMap->contains(page)) { stackedWidget->setCurrentIndex(pagesMap->value(page)); } }
20、继承
继承主要是一个参数问题。
比如:
(1)子类与父类构造函数的参数一一对应,直接把参数变量传入
ProgressEditPop::ProgressEditPop(int width,int height,QString title):BasePopUp(width,height,title)
(2)如果在子类里我们不传入这些参数,而是用固定值——那么传入固定值
ProgressEditPop::ProgressEditPop():BasePopUp(400,400,"helloworld")
21、模态窗口与非模态窗口
所谓模态窗口是阻塞的意思,当弹出模块窗口的时候,背景窗口点不到;非模态窗口则是背景窗口还是可以点击。
非模态窗口的问题是:当点击主窗口的时候,发现弹窗不见了;但不是真的不见了,而是跑到主窗口后面去了。
所以最好还是用模态窗口。
progressEditPop = new ProgressEditPop; progressEditPop->exec();// 模态
progressEditPop = new ProgressEditPop; progressEditPop->show();// 非模态
progressEditPop = new ProgressEditPop; progressEditPop->setModal(true); progressEditPop->show();// 模态,等价于exec
关闭:
progressEditPop->close();
22、子类重写父类的虚槽函数
首先:要在子父类都要加上:
Q_OBJECT
父类定义了一个关闭窗口的按钮,在槽函数中执行:
this->close();
发现关闭不了。为什么呢,因为这个this指向父类(编译时已决定),而当前窗口是子类,关掉父类并不等于会关掉子类,或者说根本不可以这样关。
这时就把父类槽函数头文件改为:
protected slots: virtual void onBaseCloseBtnClick();
实现也是要实现的,实现放空就好了:
void BasePopUp::onBaseCloseBtnClick() { }
这样写,当调用的时候不会执行父类的这个函数,而是会执行子类的这个函数(如果有实现的话)。
在子类:不需要写连接了,直接写槽函数:
protected slots: virtual void onBaseCloseBtnClick();// 发现有没有加virtual都是可以的
void ProgressEditPop::onBaseCloseBtnClick() { this->close(); }这样在子类里面有了正确的this指向,就可以关掉窗口了。
23、连续弹窗的注意事项
连续弹窗的时候,通常是先关掉前一个弹窗在弹出后一个弹窗,或者说先弹出新弹窗再close旧弹窗也行。
一个核心的要点是:如果新弹窗发送信号让就弹窗接收,在就弹窗的代码里处理,显然是不合适的,因为新弹窗出来以后,就弹窗就销毁了。
就是说,不要在一个弹窗里弹另一个弹窗,因为即使现在没有,但是有可能后面新老窗口要发生交互,这样的架构就有问题了。
所以比较稳妥的方式是:所有弹窗都基于一个稳固的页面弹出,页面通过接收信号来处理新弹窗的生成,旧弹窗则在发出信号之前就把自己close掉,省的在页面处理(如果是局部变量,就不好处理)。
旧弹窗在初始化的时候添加槽连接:
void DevelopPage::onProgressEditClick() { ProgressEditPop * progressEditPop = new ProgressEditPop; connect(progressEditPop,SIGNAL(onProgressBtnClickSignal1()),this,SLOT(onProgressBtnClick1())); connect(progressEditPop,SIGNAL(onProgressBtnClickSignal2()),this,SLOT(onProgressBtnClick2())); progressEditPop->exec();// 这里有一个要点需要特别注意:槽连接的建立必须在exec或者show之前,否则程序崩溃!!!!!! }
void ProgressEditPop::onBtnClick1() { this->close(); onProgressBtnClickSignal1();// 发送信号告诉页面生成新弹窗 // 之前直接在此生成新弹窗,已废弃此方法 // SubProgressEditPop * subProgress = new SubProgressEditPop; // subProgress->exec(); }
页面这样处理:
void DevelopPage::onProgressBtnClick1() { SubProgressEditPop * subProgress = new SubProgressEditPop; // 下面可以对新弹窗添加槽,注意要在exec之前添加 // ... subProgress->exec(); }
24、QHBoxLayout和QVBoxLayout
经常使用一个函数:
setMargin
此函数可以设定边距为0,但是没完,以QVBoxLayout为例,设置setMargin为0之后,发现上下控件还是有间距,经查发现还需要这个:
setSpacing
此函数设置为0,才可以令控件上下没有间距。
25、默认参数
Qt默认参数只能在头文件中声明,在源代码中就把他当普通参数来写:
void movePosCommon(QString objName,QString objValue,bool IsValTranToHex=true);
void ExtractParamEditPage::movePosCommon(QString objName, QString objValue,bool IsValTranToHex) {}