0. Qt快捷键

界面控制
    F1查看帮助  Esc回到代码
    F2 跳转到函数定义(和Ctrl+鼠标左键一样的效果)
        Shift+F2 声明和定义之间切换
    F4头文件和源文件之间切换
    Ctrl+H diff
    Alt+左右 切换最近文件(UI下Alt+←可以直接到代码)
    Ctrl+Tab 快速切换最近文件
    Ctrl+W 关闭当前文件

代码控制
    Ctrl+ A I 自动整理
    Ctrl+/注释行,取消注释行
    Ctrl + F 查找
    Ctrl+[]  调到块的首位
    F3 查找下一个 Shift + F3 查找上一个
    
    Ctrl + Shift + Up 将当前行的代码向上移动一行
    Ctrl + Shift + Down 将当前行的代码向下移动一行

    Ctrl+Alt+ 上下 复制一行
    Ctrl+Enter 下一行
    Ctrl+Shift+Enter 上一行

    按着Alt shift鼠标

    在头文件里按 Alt+Enter,再按回车键将在cpp中添加对应的方法实体

编译控制
    Ctrl+B编译工程
    Ctrl+R运行工程

F5开始调试
    Shift+F5停止调试
    F9设置和取消断点
    F10 单步前进
    F11 单步进入函数
    Shift + F11单步跳出函数

1. 信号与槽


信号和槽关联的格式

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

信号和槽的使用

  • 一个信号可以连接多个槽
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(addFun(int)));
connect(spinNum, SIGNAL(valueChanged(int)), this, SLOT(updateStatus(int)));

spinNum数值发生变化,两个槽进行相应,按照建立连接的顺序依次执行

  • 多个信号连接一个槽
connect(ui->rBtnBlue, SIGNAL(clicked()), this, SLOT(setTextFontColor()));
connect(ui->rBtnRed, SIGNAL(clicked()), this, SLOT(setTextFontColor()));
connect(ui->rBtnBlack, SIGNAL(clicked()), this, SLOT(setTextFontColor()));

任何一个radiobutton被点击 都会执行setTestFontColor函数

  • 一个信号连接另外一个信号
connect(spinNum, SIGNAL(valueChanged(int)), this, SIGNAL(refreshInfo()));
  • 信号和槽参数个数和类型要一致
  • 使用信号和槽 需要加入Q_OBJECT宏
  • 发射信号后,关联的槽函数执行完毕才会执行发射后面的代码

自定义信号

  • 信号必须有signals关键字声明
  • 信号没有返回值,但是可以有参数
  • 信号就是函数的声明,只需声明,无需定义
  • 使用:emit mySignal();
  • 信号可以重载 需要用函数指针 void (类名::*funSignal)(参数,参数)= &类名::信号;

lambda表达式

CONFIG+=C++11

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
connect(b4, &QPushButton::released, 
    []() mutable
    {
        qDebug()<<"1111";
    }
);
/*
    = :   把外部所有局部变量,类中所有成员以值传递,需要修改 加mutable关键字,比较安全
    this:类中所有成员,以值传递
    & :  引用传递,外部的局部变量
*/

Qt5的connect

所有参数都是指针

connect(&信号发出者, &发送者的类名::信号名字, this, &接收的类名::槽函数名字)

属性系统 Q_PROPERTY() QCLASSINFO()

还没用到

sender()函数

1
2
3
4
5
6
7
8
//判断是谁发出的信号
QObject * mySender = sender();
//转换为按钮类型
QPushButton *p = (mySender)mySender;
if(NULL != p)
{
    p->text();
}

2. Qt 类库

元对象系统

  • QObject::metaObject()
QObject *obj = new QPushButton;
obj->metaObject()->classname();// 返回QPushButton
  • QObject::inherits(const chaar * className);
    判断一个对象实例是否是className的类
QTimer *timer = new QTimer;
timer->inherits("QTimer");//true
timer->inherits("QAbsractButton");//false
  • 动态映射 dynamic cast
QObject *obj = new QMyWidget;
QWidget *Widget = qobject_cast<QWidget *>(obj); // ok myWidget是Widget的子类
QMyWidget *myWidget = qobject_cast<QMyWidget *>(obj); // ok

容器类

顺序容器 关联容器

顺序容器类

  • QList 数组、前后添加快,可以下标访问at()
    insert replace removeAt move swap append prepend removeFirst removeLast isEmpty size

  • QLinkedList 链表、基于迭代器访问、不提供下标发昂文

  • QVector 动态数组 性能高

  • QStack 栈 LIFO
    push pop

  • QQueue 队列 FIFO
    enqueue dequeue

关联容器类

  • QMap
QMap<Key,T>

QMap<QString,int> map;
map["one"] = 1;
map["two"] = 2;

map.insert("four",4);
map.remove("two");

//查找
timeout = map.value("TIMEOUT",30);//30是缺省值
  • QMultiMap
  • QHash
  • QMultiHash
  • QSet 集合 查找快 内部是QHash
    set.contains(“cat”)

容器的迭代

  • java迭代器
  • STL迭代器
  • foreach(宏)

java迭代器

容器 只读迭代器 可读写迭代器
QList, QQueue QListIterator QMutableListIterator
QLinkedList QLinkedListIterator QMutableLinkedListIterator
QVector, QStack QVectorIterator QMutableVectorIterator
QSet QSetIterator QMutableSetIterator
QMap<Key, T>, QMultiMap<Key, T> QMapIterator<Key, T> QMutableMapIterator<Key, T>
QHash<Key, T>, QMultiHash<Key, T> QHashIterator<Key, T> QMutableHashIterator<Key, T>

QListIterator的API:

函数 用途
toFront() 将迭代器移到list的最前面(在第一个项之前)
toBack() 将迭代器移到list的最后面 (最后一项之后)
hasNext() 如果迭代器没有到list的最后则返回true
next() 返回下一项,并将迭代器向前移动一个位置
peekNext() 返回下一项,不会移动迭代器
hasPrevious() 如果迭代器没有到list的最前面则返回true
previous() 返回上一项,并将迭代器移到上一个位置
peekPrevious() 返回上一项,不会移动迭代器

STL风格的迭代器

容器 只读迭代器 可读写的迭代器
QList, QQueue QList::const_iterator QList::iterator
QLinkedList QLinkedList::const_iterator QLinkedList::iterator
QVector, QStack QVector::const_iterator QVector::iterator
QSet QSet::const_iterator QSet::iterator
QMap<Key, T>, QMultiMap<Key, T> QMap<Key, T>::const_iterator QMap<Key, T>::iterator
QHash<Key, T>, QMultiHash<Key, T> QHash<Key, T>::const_iterator QHash<Key, T>::iterator

STL风格迭代器的API:

表达式 用途
*i 返回当前项
++i 将迭代器指向下一项
i += n 迭代器向前移动n项
–i 将迭代器指向上一项
i -= n 将迭代器你向后移动n项
i - j 返回迭代器i和j之间项的数目

foreach关键字

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
/////foreach遍历QLinkedList<QString>
QLinkedList<QString> list;
...
QString str;
foreach (str, list)
    qDebug() << str;

/////QMap和QHash中
QMap<QString, int> map;
...
foreach (const QString &str, map.keys())
    qDebug() << str << ":" << map.value(str);

/////对于一个多值的(multi-valued)map
QMultiMap<QString, int> map;
...
foreach (const QString &str, map.uniqueKeys()) 
{
    foreach (int i, map.values(str))
        qDebug() << str << ":" << i;
}

QString 类

  • 转换到整数
    toInt toLong toShort toUInt toULong
  • 转换到浮点数 toDouble toFloat
  • 进制转换
QString str = ui->editDec->text();
int val = str.toInt();//10进制
str = QString::number(val,16);//16进制
str = str.setNum(val,16);
str = str.toUpper();
str = str.setNum(val,2);
//str = QString::number(val,2);

组字符串 arg

QString str = QString("%1  %2").arg("Mike").arg(123);

QString常用功能

  • append() prepend()前面添加
  • toUpper toLower
  • count size length 功能相同 汉字算一个
  • trimmed 去掉最后空格 , simplified 多个空格用一个替换
  • indexOf lastIndexOf 出现位置
  • isNull(未初始化) isEmpty(只有\0是true, 常用)
  • contains() 包含
  • endsWith startsWith 判断是否某个结尾
  • left 和 right 从左右取出字符
  • section 分割

QString 和 QByteArray

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//QString -> QByteArray
QString str("hello");  
QByteArray bytes = str.toUtf8(); // QString转QByteArray方法1
bytes.toLocal8Bits();//本地编码 ANSI

//QByteArray -> char *
char *b = a.data();

//QString -> char*
str.toUtf8().data()

//char * -> QString
QString c = QString(p);

时间和日期类

  • QTime 时间 21:46:58
  • QDate 日期 2019-11-1
  • QDataTime 日期时间 2019-11-1 21:47:35 时间转化为字符串
1
2
3
#include <QDateTime>
    QDateTime curDataTime = QDateTime::currentDateTime();
    ui->lineEdit->setText(curDataTime.toString("yyyy-MM-dd hh:mm:ss:zzz A"));

字符串转化为时间 datetime = QDateTime::fromString(str,“yyyy-MM-dd hh:mm:ss”);

定时器类 QTimer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
/////.h
private:
    QTimer *timer;

private slots:
    void on_timer_timeout();

/////.cpp
timer = new QTimer(this);

connect(timer, SIGNAL(timeout()), this, SLOT(on_timer_timeout()));
timer->start(1000);

3. Qt界面组件

  1. 按钮类
  • QPushButton
  • QToolButton
  • QRadioButton
  1. item
  • QListWidget
  1. 容器
  • QStackWidget
  • QWidget
  • QFrame(可以带边框)
  1. 编辑类
  • QComboBox
  • QLineEdit
  • QTextEdit
  1. 显示类
  • QLabel
  • QLcdNumber
  • QProcessBar

SpinBox 整数的显示和输入

属性:

  • prefix
  • suffix
  • mininum
  • maxinum
  • singlestep
  • value
  • displayIntegerBase
  • decimals

下拉列表 QComboBox

addItem()

ui->comboBox->clear();
QStringList strList;
strList<<"aa"<<"aa"<<"aa"<<"aa"<<"aa"<<"aa"<<"aa";
ui->comboBox->addItems(strList);
  • int currentIndex()
  • QString currentText()
  • int count

signal:

  • void currentIndexChanged(int index)
  • void currentIndexChanged(consst QString &text)

多行简单文本编辑器 QPlainTextEdit

cut copy paste undo redo clear selectAll

  • 读取全部内容 toPlainText()

QLabel

  • 显示文字
1
label->setText("");
  • 显示图片
1
2
label->setPixmap(QPixmap("://image/xxxx.png"))
label->setScaledContents(true);
  • 显示GIF
1
2
3
4
5
#include <QMovie>
QMovie myMovie = new QMovie("://unage/xxx.gif");
label->setMovie(myMovie);
myMovie.start();
label->setScaledContents(true);
  • 显示网址
1
2
label->setText("<h1><a href=\"https://www.baidu.com\">百度一下</a></h1>");
label->setOpenExternalLinks(true);

布局

  • 水平
  • 垂直
  • 网格

布局属性,大小策略 垂直固定

自定义控件(提升)

  • 有相同的父类
  • 选中ui 右键 提升

4. Model/View结构

没写

5. Qt样式表

qss

QWiget::setStyleSheet()
QApplication::setStyleSheet()
可以为一个独立的子部件、整个窗口、整个应用程序指定一个样式表

1
selector{attribute: value}
  • 选择器
  • 属性

属性

  • color 前景色
  • background-color 背景色
  • background-image:url(://img.jpg)
  • border-image:url(://img.jpg)
  • background-position和background-repeat

6. Qt事件 Event

所有事件类都继承于QEvent

app.exec 等待事件的发生

事件过滤器eventFilter -> 分发器event() -> 事件处理函数 ☆

自定义控件的新建方法

  1. add new c++class
  2. 继承QWidget
  3. 修改3处
    • 头文件2处QWidget改为QLabel
    • .cpp 冒号后面 QWidget改为QLabel
  4. 重写protected函数

事件

  • 鼠标事件 #include
  • 键盘事件 #include
  • 定时器事件 QObject

事件的接收和忽略

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
//鼠标事件
protected:
    void mousePressEvent(QMouseEvent *ev);
    void mouseReleaseEvent(QMouseEvent *ev);
    void mouseMoveEvent(QMouseEvent *ev);

    void leaveEvent(QEvent *event);
    void enterEvent(QEvent *event);

//键盘和定时器事件
protected:
    //键盘按下事件
    void keyPressEvent(QKeyEvent *event);
    //定时器事件
    void timerEvent(QTimerEvent *event);

/* Alt+Enter 生成代码 */

MyLabel::MyLabel(QWidget *parent) : QLabel(parent)
{
    //设置默认追踪鼠标
    this->setMouseTracking(true);
}

void MyLabel::mousePressEvent(QMouseEvent *ev)
{
    int a = ev->x();
    int b = ev->y();

    QString str = QString("<center><h1>press = (%1,%2)</h1></center>").arg(a).arg(b);
    this->setText(str);

    //判断是左键还是右键
    if(ev->button()==Qt::LeftButton)
    {
        qDebug()<<"左键按下";
    }

}

void MyLabel::mouseReleaseEvent(QMouseEvent *ev)
{
    int a = ev->x();
    int b = ev->y();

    QString str = QString("<center><h1>release = (%1,%2)</h1></center>").arg(a).arg(b);
    this->setText(str);


}

void MyLabel::mouseMoveEvent(QMouseEvent *ev)
{
    int a = ev->x();
    int b = ev->y();

    QString str = QString("<center><h1>move = (%1,%2)</h1></center>").arg(a).arg(b);
    this->setText(str);

}

void MyLabel::leaveEvent(QEvent *event)
{
    qDebug()<<"离开";
}

void MyLabel::enterEvent(QEvent *event)
{
    qDebug()<<"进入";
}

MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
{
    ui->setupUi(this);

    //单位毫秒
    int timer_id = this->startTimer(1000);
    //停止定时器
//    this->killTimer(timer_id);
}

MyWidget::~MyWidget()
{
    delete ui;
}

void MyWidget::keyPressEvent(QKeyEvent *event)
{
    qDebug()<<event->key();
    if(event->key() == Qt::Key_A)
    {
       qDebug()<<"keyA";
    }
}

void MyWidget::timerEvent(QTimerEvent *event)
{
    static int sec = 0;
    sec++;
    ui->label->setText(QString("%1").arg(sec));

//    if(event->timerId() == timer_id)
//    判断是哪个定时器
}

event()函数 消息分发

#include <QEvent>

QWidget -> event()

不要轻易改event函数,return错 会让事件失效

事件过滤器

QObject eventFilter()

1
2
3
virtual bool QObject::eventFilter(QObject *watched,QEvent* event)

//不想继续转发 返回true 否则false

事件过滤器必须和被安装过滤器的组件在同一个线程 ,否则 过滤器不起作用

7. Qt绘图

画家QPainter -> QPaintEngine -> 绘图设备QPaintDevice

画图

在窗口绘图

10_PaintEvent 重写PaintEvent (注意写参数,重写虚函数,不是重载)

手动刷新

update();

绘图设备

12_QPixmap

  • QPixmap: 针对屏幕进行优化 和平台相关,不能对图片进行修改
  • QImage: 和平台无关,可以对图片进行修改,可以在线程里绘图
  • QPicture:保存绘图的状态(二进制文件)

前两个保存出来的是图片,第三个保存出来是二进制

绘图设备相互转换

1
2
3
4
5
    //pixmap转image
    pixmap.load("../1.jpg");
    QImage tempImage = pixmap.toImage();
    //image转 QPiaxmap
    QPixmap tempPixmap = QPixmap::fromImage(tempImage);

不规则窗口

  1. 给窗口画一张背景图‘
  2. 去窗口边框
  3. 设置背景透明
  4. 重写移动(移动坐标是相对于屏幕,是以左上角移动)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
//构造函数
去窗口边框
setWindowFlags(Qt::FramelessWindowHint | windowFlags() );

//设置透明
setAttribute(Qt::WA_TranslucentBackground);


//重写paintEvent
设置背景图片

//重写鼠标按下和释放 用于移动窗口
求相对坐标

8. Qt文件操作

  • 传统模式 参数char* int 返回值长度
  • Qt模式 返回值是QByteArray
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void Widget::on_button_Read_clicked()
{
    QString path = QFileDialog::getOpenFileName(this,"open","../","TXT(*.txt)");

    if(path.isEmpty() == false)
    {
        QFile file(path);
        //打开 只读方式
        bool isOK = file.open(QIODevice::ReadOnly);
        if(isOK == true)
        {
            //读文件 显示到窗口 默认utf8
            QByteArray array = file.readAll();
            //显示到编辑区
            ui->textEdit->setText(array);
            file.close();
        }
    }
}

void Widget::on_button_Write_clicked()
{
    //选择保存路径
    QString path = QFileDialog::getSaveFileName(this,"save","../","txt(*.txt)");
    if(path.isEmpty() == false)
    {
        QFile file;//创建文件对象
        //关联文件名字
        file.setFileName(path);

        bool isok = file.open(QIODevice::WriteOnly);
        if(isok)
        {
            QString str = ui->textEdit->toPlainText();
            //QString -> QByteArray
            file.write(str.toUtf8());
            file.close();
        }

    }
}

获取文件的信息

QFileInfo F1

1
2
QFileInfo info(path);
info.fileName().toUtf8().data(); //显示utf8的

QDataStream

数据流(二进制)

QTextStream

setCodec() // 按编码保存

QBuffer

#include <QBuffer> // 内存文件

memFile.buffer();//取出来

9. Qt TCP

服务器有 两个套接字 ,一个监听 一个传输

如果项目用到网络,需要添加
QT+=network

Linux Server 端

bind listen accept
read/write

Linux client 端

connect
read/write

QT Server 端 -QTcpServer

listen()【与bind合并】
//如果连接成功服务器会触发newConnection()信号
槽函数->取出建立好连接的套接字 类型:QTcpSocket
如果收到消息,通信套接字会受到readyRead()需要在对应槽函数做接收处理
read/tcp.write()

QT client 端 - QTcpSocket

connectToHost()
如果连接成功会触发connected()信号,不管服务器还是客户端
如果对方主动断开连接,会触发disconnected()信号
read/write

server

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
tcpServer = new QTcpServer(this);

tcpServer->listen(QHostAddress::any,8888);

connect(tcpServer,&QTcpServer::newCOnnection,
    [=]()
    {
        tcpSocket = tcpServer->nextPendingCOnnection();
        QString ip=tcpSocket.peerAddress().toString();
        qint16 port=tcpSocket.peerPort();

        QString temp = QString("[%1:%2]:成功连接").arg(ip).arg(port);
    }
);

client

定时器对象QTimer

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// .h
#include <QTimer>

private:
QTimer *myTimer;
/// .cpp
myTimer = new QTimer(this);
//定时器有个信号singal timeout()
connect(myTimer,&QTimer::timeout,
    [=]()
    {
        static int i = 0;
        i++;
        ui->lcdNumber->display(i);
    }
);

//startBUtton
if(myTimer->isActive() == false)
    myTimer->start(100);//启动定时器,时间间隔为100ms

//stop button
if(myTimer->isActive() == true)
    myTimer->stop();

Qt UDP

没写

Qt TCP传文件

没写

10. Qt 线程

QThread

界面上有时间比较复杂的处理

简单线程

  1. 新建一个类 继承QThread
  2. 实现虚函数 run
  3. 创建一个线程对象
  4. 线程->start();
  5. 结束线程 回收资源 ->quit() ->wait();

线程PRO

  1. 新建一个类,继承于QObject
  2. 设置一个线程函数 名字随便
  3. 创建一个线程对象(不能指定父对象)
  4. 创建QThread子线程对象,可以指定父对象
  5. 把自定义线程类加入到子线程
    • 启动子线程 thread.start() 线程函数并没有启动
    • 必须通过signal slot启动
      connect(this,&自定义信号,线程对象,线程函数);
    • 启动线程函数 emit 自定义信号();

注意

线程处理函数内不能操作图形界面 (纯数据处理)

connect的第五个参数

在多线程的时候才有意义,连接方式:默认 队列 直接

  • 默认
    • 如果是多线程 使用队列
    • 如果是单线程 使用直接
  • 队列:槽函数所在线程和信号接受者一样
  • 直接:槽函数所在线程和信号发送者一样

11. Qt数据库

QT += sql

code

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
#include <QSqlDatabase>
#include <QMessageBox>
#include <QSqlError>
#include <QSqlQuery>

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    //打印Qt支持的数据库驱动
    qDebug()<<QSqlDatabase::drivers();

    //添加Mysql数据库
    QSqlDatabase db = QSqlDatabase::addDatabase("QMYSQL");

    db.setHostName("127.0.0.1");
    db.setPort(10026);
    db.setUserName("root");
    db.setPassword("123");
    db.setDatabaseName("test"); //使用哪个数据库

    if(db.open() == false)
    {
        QMessageBox::warning(this,"错误","连接失败"+db.lastError().text());
    }
    else
    {
        QMessageBox::information(this,"提示","连接成功");

        //QSqlQuery q;
       // q.exec("select * from list;");

    }
}