Qt学习笔记(总)

1、添加git版本控制

版本控制忽略清单:

.DS_Store

*-Debug
*.user
debug文件夹全部不要,可以运行时生成;.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)
{}











猜你喜欢

转载自blog.csdn.net/wzj0808/article/details/79226419