目录
Qt中添加资源文件(图片等)
1.远中工程右键->添加新文件,弹出下图对话框
2选中Qt->Qt Resoure File,弹出下列对话框
3.取名,下一步,完成,然后会出现如下对话框
4.点击添加,选择添加前缀,添加好前缀之后就可以添加文件了,选择需要添加的文件,这里需要把需要添加的文件先放到项目目录下的一个文件夹下,添加好之后保存,就能在资源浏览器中看到了,也就能在代码中引用了。<图标下载百度icon>
QByteArray
访问与赋值
访问QByteArray主要有4中方式,分别为[]、at()、data[]和constData[]。其中[]和data[]为可读可写,at()和constData[]仅为可读。如果仅是读,则通过at()和constData[]访问速度最快,因可避免复制处理。示例如下:
QByteArray ba;
ba.resize(5);
ba[0] = 0x41; //十进制为65,对应ASCII为'A'
ba[1] = 0x30; //十进制为48,对应ASCII为'0'
ba[2] = 66; //十进制为66,对应ASCII为'B'
ba.data()[3] = 0x31; //十进制为49,对应ASCII为'1'
ba.data()[4] = 0x43; //十进制为67,对应ASCII为'C'
/*QByteArray输入数字,则输出值为ASCII码表对应字符*/
qDebug()<<"[]"<<ba[0]; //'A'
qDebug()<<"at()"<<ba.at(1); //'0'
qDebug()<<"data()"<<ba.data()[2]; //'B'
qDebug()<<"constData()"<<ba.constData()[3]; //'1'
qDebug()<<"constData()"<<ba.constData()[4]; //'C'
QByteArray byte(2,0);//定义大小为2,其值为空
qDebug()<<"byte = "<<byte<<endl; //"\x00\x00"
数据转换
1、QByteArray转为Hex
QByteArray ba;
ba.resize(5);
ba[0] = 0x41; //十进制为65,对应ASCII为'A'
ba[1] = 0x30; //十进制为48,对应ASCII为'0'
ba[2] = 66; //十进制为66,对应ASCII为'B'
ba.data()[3] = 0x31; //十进制为49,对应ASCII为'1'
ba.data()[4] = 0x43; //十进制为67,对应ASCII为'C'
qDebug()<<"ba = "<<ba<<endl; //ba = "A0B1C"
qDebug()<<"ba.Hex() = "<<ba.toHex()<<endl; //ba.Hex() = "4130423143"
QByteArray ba("ABCDEF");
Debug()<<"ba = "<<ba<<endl; //ba = "ABCDEF"
qDebug()<<"ba.Hex() = "<<ba.toHex()<<endl; //ba.Hex() = "414243444546"
2、Hex转QByteArray
QByteArray text = QByteArray::fromHex("517420697320677265617421");
text.data(); // returns "Qt is great!"
qDebug()<<"text = "<<text<<endl; //Qt is great!
qDebug()<<"text.data() = "<<text.data()<<endl; //Qt is great!
3、数值转换
int num = 63;
QByteArray ba1 = QByteArray::number(num); //"63"
QByteArray ba2 = QByteArray::number(num,2); //"111111"
QByteArray ba3 = QByteArray::number(num,16); //"3f"
QByteArray ba4 = QByteArray::number(num,16).toUpper(); //"3F"
QByteArray ba5;
ba5 = ba5.setNum(num); //"63"
ba5 = ba5.setNum(num,16); //"3f"
4、QByteArray <-> char *
char ch[] = "hello world!";
QByteArray byte = QByteArray(ch);
char *ch1;//不要定义成ch1[n];
QByteArray byte1("hello world!");
ch1 = byte1.data();
5、QString <-> QByteArray
QString str("hello world!"); QByteArray byte = str.toLatin1(); //QString -> QByteArray QByteArray byte("hello world!"); QString string = QString(byte); //QByteArray -> QString //string.prepend(byte); //QByteArray -> QString
中文 QByteArray 转换成QString会乱码,解决如下:
QByteArray byte("我爱我的祖国");
QTextCodec *tc = QTextCodec::codecForName("UTF-8");//QTextCodec::codecForName("GBK")
QString tmpQStr = tc->toUnicode(byte);
5、QByteArray 转换为数字(串口通信常用)
toInt()是把里面的字符串(如果是数)转成整数,如不是数学,则值为0
QByteArray byte("122");
quint16 num = byte.toUInt();//num = 122
qDebug()<<"num = "<<num<<endl;
QByteArray byte2("a123");
quint16 num2 = byte2.toUInt();
qDebug()<<"num2 = "<<num2<<endl; //num = 0
int num = 35;
char test[4];
memcpy(test,&num,4);
int sum = *((int*)(test)); //35
qDebug()<<"sum = "<<sum<<endl; //35
QByteArray temp;
memcpy(temp.data(),&num,4);
qint32 res;
//res=temp.toInt(); //值为0,因为toInt()是把里面的字符串(如果是数)转成整数
//memcpy(&res,temp.constData(),4); //有可能值异常
memcpy(&res,temp.left(4).constData(),4);//建议这样转换
//res = *((int*)(temp.data()));
qDebug()<<"temp = "<<temp<<endl;//"#"
qDebug()<<"res = "<<res<<endl; //35
信号与槽
信号和槽使用注意事项:
1、需要继承自QObject或其子类;
2、 使用信号和槽必须在类声明的最开始处添加Q_OBJECT宏;
3、槽中参数类型要和信号参数的类型相对应,且不能比信号的参数多;
4、信号只有声明,没有定义,且返回值为void类型;
5、槽有声明,也有定义。
信号
Qt内部自带了各种窗口部件的信号,最常见的就是按钮的clicked()。但是也可以自己声明信号,声明信号需要使用signals关键字,在signals前面不能用public、private和protected等限定符,信号默认是public函数,可以从任何地方进行发射。
1、自定义信号,在头文件中定义,信号没有实体。
signals:
void singalSelf();
2、信号发射
emit this->singalSelf();
槽
槽就是普通的C++函数,可以像一般的函数一样使用。声明槽函数要使用slots关键字,可以是private、public或者protected类型的,槽也可以被声明为虚函数。它最大的特点就是可以和信号关联,这是其它函数比不了的。
信号和槽关联
信号和槽关联使用的是QObject类的connect()函数,需要注意的是,connect()函数中信号和槽的参数只能为类型,不能有变量名。
- 第一个参数:发射信号的对象
- 第二个参数:发射的信号
- 第三个参数:接受信号的对象
- 第四个参数:要执行的槽
- 第五个参数:信号和槽的关联方式,默认为自动关联
第五个参数:
- Qt::AutoConnection: 默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。
- Qt::DirectConnection(槽函数在接收者所依附线程执行):槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程(无论槽函数所属对象在哪个线程,槽函数都在发射信号的线程内执行)。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。
- Qt::QueuedConnection:槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。
- Qt::BlockingQueuedConnection:槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。
- Qt::UniqueConnection:这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。
3.1 Qt4原型
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
Qt4示例:
connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(slotDealDate()));
3.2 Qt5原型
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,Qt::ConnectionType type = Qt::AutoConnection);
Qt5示例:
注意:如果信号和槽有参数,Qt5连接时不需要参数。
connect(ui->pushButton,&QPushButton::clicked,this,&MainWindow::slotDealDate);
3.3 多个相同部件用同一个槽函数(以QPushButton举例)
connect(ui->pushButton1,SIGNAL(pressed()),this,SLOT(SLOTButtonClick()));
connect(ui->pushButton2,SIGNAL(pressed()),this,SLOT(SLOTButtonClick()));
void Widget::SLOTButtonClick()
{
QPushButton *btn=qobject_cast<QPushButton*>(sender()); //得到当前操作的按钮
if(btn==ui->pushButton1)
{
//添加响应信息
}
else if(btn == ui->pushButton2)
{
//添加响应信息
}
else
{
}
}
3.4 自定义数据类型需要在main函数中向Qt注册自定义的数据格式,用于信号和槽
//向Qt注册自定义的数据格式,用于信号和槽
qRegisterMetaType<FunctionCodeType>("FunctionCodeType");
qRegisterMetaType<StructData>("StructData");
菜单栏和工具栏
示例图:
菜单栏
1.在菜单栏添加菜单
QMenu *filemenu = menuBar()->addMenu("&文件"); //添加文件菜单
2.在菜单中添加菜单项
方法一:
QAction *newfile = new QAction("&new");
newfile->setIcon(QIcon(":/image/new.png")); //为文件添加图标
filemenu->addAction(newfile); //菜单下拉组(菜单下添加新文件)
方法二:
QAction *newfil = new QAction(QIcon(":/image/new.png"),"&new",this);
filemenu->addAction(savefile);
connect(newfile,SIGNAL(triggered(bool)),this,SLOT(new_fun())); //新文件信号与槽
3.菜单项中添加分割线
filemenu->addSeparator(); //设置分割线
工具栏
QToolBar *newtool = addToolBar("newtool"); //声明一个工具栏
newtool->addAction(newfile); //添加内容(新建文件)
文件操作(QFileDialog)
(一)打开文件
QSting filename = QFileDialog::getOpenFileName(this,"open file",".","file (*.*)");//获取文件名,2-4个参数分别为:标题,位置,文件类型
QFile file(filename);
if(!file.open(QIODevice::ReadWrite | QIODevice::Text)) //打开文件
{
qDebug()<<"open file failing"<<endl;
return;
}
while(!file.atEnd())
{
QByteArray line = file.readLine();
line.chop(1);
textedit->append(line); //将文本文件显示在textedit文本框中
}
file.close();
(二)保存文件
if(filename.isEmpty()) //如果文件名为空,就获得文件名(用户取);如果是另存为则不需判断
{
filename = QFileDialog::getSaveFileName();
}
QFile file(filename);
if(!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
file.write(textedit->toPlainText().toStdString().c_str());//将文本框的内容,导入文件中
file.close();
QDataStream与QTextStream
QDataStream类为我们的程序提供了读写二进制数据的能力。一个数据流如果是二进制编码的数据流,那么它肯定是与计算机的操作系统、CPU或者字节序无关的。例如,一个数据流是在一个运行Windows系统的PC机上被写入的,那么它照样可以
在一台运行Solaris的Sun SPARC的机器上被读取出来。同样,我们也可以使用
QDataStream去读写原生的未编码的二进制数据。
QDataStream类实现了序列化C++的基本数据类型的功能,比如char,short,int,char*,QBrush,QColor,QDateTime,QList,QLinkedList,QVector,QSet,QHash,QMap 和QImage等等。
注意:写入什么类型就读出什么类型。
void Widget::writeData()
{
QFile file("../test.txt");//没有就创建
if(!file.open(QIODevice::WriteOnly))
{
qDebug()<<"---open fial---"<<endl;
return;
}
QDataStream stream(&file);
stream<<QString("akdlfjl")<<234;
QMap<qint16,bool> mymap;
mymap.insert(12,false);
mymap.insert(22,false);
mymap.insert(12,false);
mymap.insert(55,false);
mymap.insert(66,false);
stream<<mymap;
}
void Widget::readData()
{
QFile file("../test.txt");
if(!file.open(QIODevice::ReadOnly))
{
qDebug()<<"---open fial---"<<endl;
return;
}
QDataStream stream(&file);
QString str;
quint32 num;
stream>>str>>num;
qDebug()<<"str = "<<str<<" num = "<<num<<endl;
QMap<qint16,bool> mymap;
stream>>mymap;
QMapIterator<qint16,bool> it(mymap);
while(it.hasNext())
{
it.next();
qDebug()<<"key = "<<it.key()<<"value = "<<it.value()<<endl;
}
}
QTextStream可以设置编码类型
void Widget::writeData()
{
QFile file("../test.txt");
if(!file.open(QIODevice::WriteOnly))
{
qDebug()<<"---open fial---"<<endl;
return;
}
QTextStream stream(&file);
//指定编码
stream.setCodec("UTF-8");
stream<<QString("挖机噶")<<234;//QTextStream会把两个字符串连在一起即“挖机噶234"
}
void Widget::readData()
{
QFile file("../test.txt");
if(!file.open(QIODevice::ReadOnly))
{
qDebug()<<"---open fial---"<<endl;
return;
}
QTextStream stream(&file);
QString str;
quint32 num;
// stream>>str>>num;//因为两个字符串连在一起了,所以str ="挖机噶234",num = 0
str = stream.readAll();// 一般以read的方式读出
qDebug()<<"str = "<<str<<" num = "<<num<<endl;
}
QDir和QFile
QDir writeDir;
writeDir.setPath(RUNTIME_PATH);
if (writeDir.exists() == false) //如果该文件夹路径不存在,新建该路径
{
writeDir.mkpath(RUNTIME_PATH);
}
writeDir.setCurrent(RUNTIME_PATH);
QFile file;
file.setFileName(RUNTIME_FILE);
if(file.open(QIODevice::WriteOnly))
{
file.write();
file.flush();
file.close();
}
else
{
}
对话框(QDialog)
基本用法
QDialog *findDlog = new QDialog;
findDlog->setWindowTitle(tr("查找"));
findLineEdit = new QLineEdit(findDlog);
QPushButton *FrontButton = new QPushButton(tr("向下查找"),findDlog);
QPushButton *RearButton = new QPushButton(tr("向上查找"),findDlog);
QVBoxLayout *Layout = new QVBoxLayout(findDlog); //布局
Layout->addWidget(findLineEdit);
Layout->addWidget(FrontButton);
Layout->addWidget(RearButton);
findDlog->setLayout(Layout);
findDlog->show();
示例对话框如下图:
模态与非模态
show() 与 exec() 并不是模态与非模态的区别。
- 模态对话框:在其没有被关闭之前,用户不能与同一个应用程序的其他窗口进行交互,直到该对话框关闭。
- 非模态对话框:当其被打开时,用户既可选择和该对话框进行交互,也可以选择同应用程序的其他窗口交互。
模态与非模态设置
setModal(bool modal);
更多知识点参考:QDialog 模态对话框与事件循环_1+1=10-CSDN博客
字体颜色和大小
/*颜色*/
QColor color1 = QColorDialog::getColor();
textedit->setTextColor(color1);
/*类型大小*/
bool ok = true;
QFont font1 = QFontDialog::getFont(&ok);
if(ok)
{
textedit->setFont(font1);
}
布局
布局有水平布局(QHBoxLayout)、垂直布局(QVBoxLayout)、网格布局(QGtidLayout)等
/*垂直布局和水平布局一样*/
QPushButton *Button1 = new QPushButton(tr("Yes"),this);
QPushButton *Button2 = new QPushButton(tr("No"),this);
QVBoxLayout *Layout = new QVBoxLayout(this); //布局
Layout->addWidget(Button1 );
Layout->addWidget(Button2 );
this->setLayout(Layout);
/*网格布局*/
QPushButton *Button1 = new QPushButton(tr("Yes"),this);
QPushButton *Button2 = new QPushButton(tr("No"),this);
QGridLayout *Layout = new QGridLayout (this); //布局
Layout->addWidget(Button1,0,1);
Layout->addWidget(Button2,1,0);
this->setLayout(Layout);
时间
1、获取时间与显示时间
QDateTime current = QDateTime::currentDateTime();
QString time = current.toString("yyyy-M-dd hh:mm:ss");//显示时间格式
QString Time = QDate::currentDate().toString("yyyy-MM-dd")+" "+QTime::currentTime().toString("hh:mm:ss");
textedit->append(time); //在文本框中显示
2、判断时间显示格式是否正确,可以用来字符串相关格式
QTime::fromString("04:00","hh:mm").isValid();//反回真假
3、字符串转时间
QDateTime Time = QDateTime::fromString( (Date.toString("yyyy-MM-dd")), "yyyy-MM-dd");
4、时间撮
QDateTime current = QDateTime::currentDateTime();
int timeNum = current.toTime_t();//时间转时间撮
current = QDateTime::fromTime_t(timeNum.toString("yyyy-MM-dd hh:mm:ss");//时间撮转时间
定时器(QTimer)
QTimer *timer;
timer = new QTimer();
timer->start(1000);//= timer->setInterval(1000),timer->start();
connect(timer,SIGNAL(timeout()),this,SLOT(time_out()));
timet->stop(); //停止定时器
直接触发定时器
QTimer::singleShot(10,this,SLOT(槽函数));//10ms后触发槽函数(槽函数不能有参数)
QLineEdit
(一)设置LineEdit输入值范围
double m_rangeMin = 12.0;
double m_rangeMax = 99.0;
//设置整数和浮点数的输入范围
QDoubleValidator *doubleValidator = new QDoubleValidator(m_rangeMin,m_rangeMax,1,this);//1是小数位数
//这里作为一个标准的数字的字符串被写入,另外还有一种科学计数方式写入
doubleValidator->setNotation(QDoubleValidator::StandardNotation);
ui->lineEdit->setValidator(doubleValidator);
qint8 m_rangeMin = 14;
qint8 m_rangeMax = 100;
QIntValidator *intValidator = new QIntValidator(m_rangeMin, m_rangeMax, this);
ui->lineEdit->setValidator(intValidator);
if(ui->lineEdit->hasAcceptableInput())//判断lineEdit的内容是否满足输入格式
{
}
(二)QLineEdit的一些用法
1、ui->lineEdit->setEchoMode(QLineEdit::Password);//将lineEdit输入的内容为隐式
QTextEdit
1、禁止鼠标选中文本
ui->textEdit->setTextInteractionFlags(Qt::NoTextInteraction);
QListwidget
1.向列表中添加控件,如下图:
QListWidget *listwidget = new QListWidget();
QListWidgetItem *item = new QListWidgetItem;
item->setSizeHint(QSize(0,50)); //设置项的高框
listwidget->addItem(item); //加载列表项到列表框
QWidget *w = new QWidget;
QHBoxLayout *layout=new QHBoxLayout;
QLabel *label = new QLabel("swich:",w);
QPushButton *pushButton1 = new QPushButton("ON",w);
QPushButton *pushButton2 = new QPushButton("OFF",w);
layout->addWidget(label);
layout->addWidget(pushButton1);
layout->addWidget(pushButton2);
w->setLayout(layout);
listwidget->setItemWidget(item,w);
2.添加列表项,如下图:
listwidget->addItem("北京");
listwidget->addItem("上海");
QListWidgetItem *item = new QListWidgetItem(QICon("test.png"),"深圳");
listwidget->addItem(item);
listwidget->insertItem(1,"深圳");//插入列表
3.删除列表
listwidget->takeItem(row); //删除列表,并没删除只是隐藏了
4.获取哪一页
ListWidget->setCurrentIndex(num);
QTableWidget
ui->tableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);//表格不能编辑
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);//表格每次选择一行
qint8 row = ui->tableWidget->rowCount();//获取行数
ui->tableWidget->setRowCount(row+1);//增加一行
QString ip = "127.0.0.1";
qint8 port = 123;
ui->tableWidget->setItem(row,colum,new QTableWidgetItem(ip));//想表格里添加文本
ui->tableWidget->setItem(row,colum+1,new QTableWidgetItem(QString::number(port)));
QAbstractTableModel
QAbstractTableModel 是 Qt 中的一个抽象类,在某些应用场景下我们可能会继承该类来实现一些特殊业务逻辑。
GridTable.h
#ifndef GRIDTABLE_H
#define GRIDTABLE_H
#include <QAbstractTableModel>
#include <QStringList>
class GridTable:public QAbstractTableModel
{
public:
GridTable(QObject *parent=0);
virtual int rowCount(const QModelIndex &/*parent=QModelIndex()*/) const;
virtual int columnCount(const QModelIndex &/*parent=QModelIndex()*/) const;
//如果表格可编辑添加下列两个函数
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role);
QVariant data(const QModelIndex &index, int role) const;
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
void insertInformationRows(const QList<QStringList> &warningInfoList); //插入信息
void removeAllRows(void);//清空内容
private:
QStringList header; //Table表头
QStringList nameList;
QStringList sexList;
QStringList ageList;
QStringList heightList;
};
#endif
GridTable.cpp
#include "gridtable.h"
GridTable::GridTable(QObject *parent) : QAbstractTableModel(parent)
{
header<<tr("姓名")<<tr("性别")<<tr("年龄")<<tr("身高");
}
int GridTable::columnCount(const QModelIndex &/*parent*/) const
{
return 4;
}
int GridTable::rowCount(const QModelIndex &/*parent*/) const
{
return nameList.size();
}
QVariant GridTable::data(const QModelIndex &index, int role) const
{
if(!index.isValid())
{
return QVariant();
}
if(role == Qt::TextAlignmentRole) //设置显示数据居中显示
return int(Qt::AlignCenter);
else if(role==Qt::DisplayRole)
{
switch(index.column())
{
case 0:
return nameList[index.row()];
break;
case 1:
return sexList[index.row()];
break;
case 2:
return ageList[index.row()];
break;
case 3:
return heightList[index.row()];
break;
default:
return QVariant();
}
}
return QVariant();
}
QVariant GridTable::headerData(int section, Qt::Orientation orientation, int role) const
{
if((role == Qt::DisplayRole)&&(orientation == Qt::Horizontal))
{
return header[section];
}
return QAbstractTableModel::headerData(section,orientation,role);
}
void GridTable::insertInformationRows(const QList<QStringList> &InfoList)
{
beginInsertRows(QModelIndex(), 0, InfoList.size()-1);
foreach(QStringList Info, InfoList)
{
nameList.insert(0,(Info.at(0)));
sexList.insert(0,(Info.at(1)));
ageList.insert(0,(Info.at(2)));
heightList.insert(0,(Info.at(3)));
}
endInsertRows();
}
void GridTable::removeAllRows(void)
{
beginRemoveRows(QModelIndex(), 0, nameList.size()-1);
nameList.clear();
sexList.clear();
ageList.clear();
heightList.clear();
endRemoveRows();
}
Qt::ItemFlags GridTable::flags(const QModelIndex &/*index*/) const
{
return Qt::ItemIsEnabled | Qt::ItemIsSelectable|Qt::ItemIsEditable;
}
bool GridTable::setData(const QModelIndex &index, const QVariant &/*value*/, int role)
{
//处理 Qt::EditRole 角色,此时的 value 就是修改后的值
if(index.isValid()&&role==Qt::EditRole){
switch (index.column()) {
case 0:
//
break;
case 1:
//
break;
case 2:
//
break;
case 3:
//
break;
default:
break;
}
}
return true;
}
main.c
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
GridTable SetTable;
ui->TableShow->setModel(&SetTable);
ui->TableShow->horizontalHeader()->resizeSection(0,140); //设置第一列列宽
ui->TableShow->horizontalHeader()->resizeSection(1,140); //设置第二列列宽
ui->TableShow->horizontalHeader()->resizeSection(2,140); //设置第三列列宽
ui->TableShow->horizontalHeader()->resizeSection(3,140); //设置第四列列宽
ui->TableShow->setSelectionBehavior(QAbstractItemView::SelectRows); //一次选择一行
ui->TableShow->setSelectionMode(QAbstractItemView::SingleSelection); //只允许单行选择
ui->TableShow->verticalHeader()->setDefaultSectionSize(40); //调整默认行间距
ui->historywarningtable->verticalHeader()->setMinimumSectionSize(40); //设置最小行间距
ui->TableShow->setStyleSheet("QScrollBar:vertical { width:40px; }");//滑条宽度
//ui->TableShow->horizontalHeader()->setResizeMode(QHeaderView::Fixed); //限定列宽大小,无法拉伸
//ui->TableShow->verticalHeader()->hide(); //隐藏列头
//ui->TableShow->horizontalHeader()->hideSection(5); //隐藏第五列
QList<QStringList> InfoList;
QStringList Info;
Info<<"小明"<<"男"<<"16"<<"162";
InfoList.append(Info);
SetTable.insertInformationRows(InfoList);
return a.exec();
}
QCalendarWidget(日历)
m_calendar = new QCalendarWidget(this);
m_calendar->resize(580, 340); //原始大小 360,210
m_calendar->move(100, 220-(m_calendar->size().height()-210));
QTableView *table_calendarview = m_calendar->findChild<QTableView *> ("qt_calendar_calendarview");
if(table_calendarview)
{
table_calendarview->hideColumn(0); //隐藏掉第0列显示的“一年中的第几周”
}
QToolButton *calendar_prevmonth = m_calendar->findChild<QToolButton *>("qt_calendar_prevmonth");//调日历的左右按钮
QToolButton *calendar_nextmonth = m_calendar->findChild<QToolButton *>("qt_calendar_nextmonth");
if(calendar_prevmonth && calendar_nextmonth)
{
calendar_prevmonth->setIconSize(QSize(40,40));
calendar_nextmonth->setIconSize(QSize(40,40));
}
m_calendar->setLocale(QLocale::Chinese);//将日历转为中文
线程(QThread)
线程使用
Qt中线程常用函数:start()、run()、quit()、wait();
- start(),子线程开始执行函数,即开始运行run()函数。
- quit()函数是用来停止QThread的,但是由于Qt本身是事件循环机制,所以在调用完quit()后,QThread可能还没有完全停止,此时如果执行delete thread,程序就会报错。在执行quit()后,调用wait()来等待QThread子线程的结束(即从run()函数的返回),这样就能保证在清除QThread时,其子线程是停止运行的。
一、创建线程的步骤
- 子类化 QThread:新建一个类MyThread,继承QThread(点击工程右键->添加新文件->c++ class->基类设为QObject,建立完成将QObject改为QThread);
- 重载 run 函数:重写类MyThread的虚函数void run(),即新建一个函数protected void run(),为线程处理函数和主线程不是同一个线程;
- 在需要用到多线程的地方,MyThread *mythread = new MyThread(this),然后调用函数mythread ->start()后,则开启一条线程,将会运行函数run();
- 当要停止线程时,调用mythread ->wait()函数,等待线程结束,并且回收线程资源;
- 线程处理函数内部,不允许操作图形界面(一般只做后台处理);
/***************Mythread.h**************************/
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class Mythread : public QThread
{
Q_OBJECT
public:
explicit Mythread(QObject *parent = 0);
protected:
void run(); //QTread的虚函数;
//不能直接调用,通过start()间接调用
signals:
public slots:
};
#endif // MYTHREAD_H
/******************Mythread.cpp*********************************/
#include "mythread.h"
Mythread::Mythread(QObject *parent) : QThread(parent)
{
}
void Mythread::run()
{
/*
1.数据处理(为了实现子线程的循环运行,可以用两种方法:用while()循环、在run()函数中实现事件循环如定时器)
2.emit 处理完可以发射一个信号
3.然后在主线程的槽函数中停止线程:mythread->quit(),
再等待线程结束:mytread->wait();
*/
}
- 该方法除了run()函数是在子线程中运行,其他地方都是在主线程中运行;
- 若为该类定义信号和槽,实质槽函数并不会在子thread 运行,而是在主线程运行;因为Thread的对象在主线程中创建,Thread的对象依附在主线程,所以他的slot函数会在主线程中执行,而不是次线程,除非将Thread 对象依附到次线程中(通过movetoThread),也就是下列方法。
线程另一种用法
Qt4.4开始, run 默认调用 QThread::exec() 。这样一来不需要子类化 QThread 了,只需要子类化一个 QObject 就够了
(一)线程类
1、设定一个类Mythread,继承于QObject
2、类中设置一个线程函数(只是一个线程函数)
class Mythread:public QObject
{
void MythreadFun//自定义线程处理函数
{
while(1)
{
emit MySignal();
}
}
}
(二)主窗口
1、构造函数中创建一个线程对象(不能指定父对象)
myT = new Mythread;
2、在Mythread构造函数中将Mythread依附于次线 //下面方法同样的效果
this->moveToThread(this);//
2、创建一个子线程对象
QThread *thread = new QThread(this);
把自定义模块依附于子线程
myT->movetoThread(thread);
3、启动线程。
thread->start();
4、通过信号与槽(signal - slot),槽函数则在子线程中运行
connect(this,&startThread,myT,&MythreadFun);
5、接受线程的信号,并处理
connect(myT,&MySignal,this,&槽函数);
不管那种方法构造函数始终是在主线程中执行的,如下:
#include <QDebug>
#include "subthread.h"
int main()
{
qDebug()<<"main threadID : "<<QThread::currentThreadId()<<endl;
subThread thread;
thread.start();
thread.quit();
thread.wait();
return 0;
}
#include <QDebug>
subThread::subThread(QThread *parent) : QThread(parent)
{
qDebug()<<"subThread_threadID : " <<currentThreadId()<<endl;
}
void subThread::run()
{
qDebug()<<"subThread_runID : " <<currentThreadId()<<endl;
}
/*
打印信息:
main threadID : 0x25a4
subThread_threadID : 0x25a4
subThread_runID : 0x33c0
*/
线程间资源竞争
变量竞争
当多个线程对某个变量进行读写操作,很容易造成这个变量的值是意想不到的结果 ,如下例子:
#include <QCoreApplication>
#include "threadtestclass.h"
int cnt = 0;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ThreadTestClass t1;
ThreadTestClass t2;
t1.start();
t2.start();
t1.wait(); //相当于pthread_join()
t2.wait();
qDebug() << "cnt=" << cnt;
return 0;
}
/***************************************/
#include "threadtestclass.h"
extern int cnt;
ThreadTestClass::ThreadTestClass(QObject *parent) : QThread(parent)
{
}
void ThreadTestClass::run()
{
for(int i = 0; i < 200000; i++)//
{
cnt++;
}
this->quit();
}
编译运行,cnt每个结果都不相同,cnt变量同时被两个线程操作,所以就需要用到锁。
互斥锁
QMutex类提供的是线程之间的访问顺序化。QMutex的目的是保护一个对象、数据结构或者代码段,所以同一时间只有一个线程可以访问它。
QMutex用法1:
QMutex mutex;//全局变量
mutex.lock();
/*需要锁的内容*/
mutex.unlock();
QMutex用法2:
QMutex mutex;
{
QMutexLocker locker(&mutex);
/*需要加锁的代码*/
/*当QMutexLocker对象被销毁时,互斥锁将始终被解锁*/
}
#include <QCoreApplication>
#include "threadtestclass.h"
int cnt = 0;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ThreadTestClass t1;
ThreadTestClass t2;
t1.start();
t2.start();
t1.wait(); //相当于pthread_join()
t2.wait();
qDebug() << "cnt = " << cnt;
return 0;
}
/****************************/
#include "threadtestclass.h"
#include <QDebug>
extern int cnt;
QMutex ThreadTestClass::s_mutex;
ThreadTestClass::ThreadTestClass(QObject *parent) : QThread(parent)
{
}
void ThreadTestClass::run()
{
for(int i = 0; i < 200000; i++)
{
s_mutex.lock();
cnt++;
s_mutex.unlock();
}
this->quit();
}
运行结果:cnt = 40000;
读写锁
QReadWriteLock用法1:
QReadWriteLock s_readWriteLock;
s_readWriteLock.lockForRead();//读锁
/*加锁代码*/
s_readWriteLock.unlock();
s_readWriteLock.lockForWrite();//写锁
/*加锁代码*/
s_readWriteLock.unlock();
QReadWriteLock用法2:
QReadWriteLock s_readWriteLock;
QReadLocker locker(&s_readWriteLock);
/*需要读锁代码*/
/*QReadLocker 对象销毁时,自动解锁,一般放在局部*/
QWriteLocker locker(&s_readWriteLock);
/*需要写锁代码*/
/*QWriteLocker对象销毁时,自动解锁,一般放在局部*/
1、QReadWriteLock类为我们提供了读写锁的功能,从名字上可以看得出来是把lock分为了readlock和writelock,读写锁是用来保护可以被读访问和写访问的资源的一种同步工具。如果你想让多个线程同时的对资源进行读访问,但只要有一个线程要对资源进行写访问时,所有其他的线程必须等待,直到写访问完成。对于这种情况,读写锁是非常有用的。
#include <QCoreApplication>
#include "threadtestclass.h"
int cnt = 0;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ThreadTestClass t1;
ThreadTestClass t2;
t1.start();
t2.start();
t1.wait();
t2.wait();
qDebug() << "cnt = " << cnt;
return 0;
}
/****************************/
#include "threadtestclass.h"
#include <QDebug>
extern int cnt;
QReadWriteLock ThreadTestClass::s_mutex;
ThreadTestClass::ThreadTestClass(QObject *parent) : QThread(parent)
{
}
void ThreadTestClass::run()
{
for(int i = 0; i < 200000; i++)
{
s_mutex.lockForWrite();//其他线程可以读不能写(若是lockForRead,则相反)
cnt++;
s_mutex.unlock();
}
this->quit();
}
2、 读写锁允许并行的读,如果遇到写锁时其它锁被锁住。写锁的优先级要高于读锁,如等待的锁中有读锁和写锁时,一旦上一个锁被解锁时会优先执行写锁。QReadWriteLock相对于QMutex的好处是当要保护的对象在大多数的情况是读操作偶尔写操作时,不会造成不必要的堵塞。
#include <QCoreApplication>
#include "ReadThread.h"
QReadWriteLock s_readWriteLock;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ReadThreadt1;
ReadThreadt2;
t1.start();
t2.start();
t1.wait();
t2.wait();
return 0;
}
/*******************************************/
#include "ReadThread.h"
#include <QDebug>
extern QReadWriteLock s_readWriteLock;
ReadThread::ReadThread(QObject *parent) : QThread(parent)
{
}
void ReadThread::run()
{
s_readWriteLock.lockForRead();
qDebug()<<"1--------read : "<<QThread::currentThreadId()<<endl;
qDebug()<<"2--------read : "<<QThread::currentThreadId()<<endl;
qDebug()<<"3--------read : "<<QThread::currentThreadId()<<endl;
s_readWriteLock.unlock();
this->quit();
}
运行结果:
可以看出两个线程还是交替运行的,是因为QReadWriteLock是允许并行读的,当调用写锁时其他的lock就要等待。
写锁的优先级要高于读锁,如等待的锁中有读锁和写锁时,一旦上一个锁被解锁时会优先执行写锁。
#include <QCoreApplication>
#include "ReadThread.h"
QReadWriteLock s_readWriteLock;
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
ReadThreadt1;
ReadThreadt2;
t1.start();
t2.start();
t1.wait();
t2.wait();
return 0;
}
/*******************************************/
#include "ReadThread.h"
#include <QDebug>
extern QReadWriteLock s_readWriteLock;
ReadThread::ReadThread(QObject *parent) : QThread(parent)
{
}
void ReadThread::run()
{
s_readWriteLock.lockForRead();
qDebug()<<"1--------read : "<<QThread::currentThreadId()<<endl;
qDebug()<<"2--------read : "<<QThread::currentThreadId()<<endl;
qDebug()<<"3--------read : "<<QThread::currentThreadId()<<endl;
s_readWriteLock.unlock();
this->quit();
}
/***************************************************/
#include "writethread.h"
QReadWriteLock writeThread::m_writeLock;
extern QReadWriteLock s_readWriteLock;
writeThread::writeThread(QObject *parent) : QThread(parent)
{
}
void writeThread::run()
{
s_readWriteLock.lockForWrite();
qDebug()<<"1--------write : "<<QThread::currentThreadId()<<endl;
qDebug()<<"2--------write : "<<QThread::currentThreadId()<<endl;
qDebug()<<"3--------write : "<<QThread::currentThreadId()<<endl;
s_readWriteLock.unlock();
}
运行结果:
可以看出写锁不能并行。
线程池(QThreadPool)
对于频繁创建和销毁线程,频繁切换线程对系统资源是极大的浪费,为了提高cpu利用效率,于是产生了分装好了的线程池用于管理线程。
线程池需要用到两个类:QThreadPool、QRunnable;
QRunnable 类是一个接口,用于表示一个任务或要执行的代码,需要重新实现 run() 函数。
QThreadPool 管理和循环使用单独的 QThread 对象,以帮助程序减少创建线程的成本。每个 Qt 应用程序都有一个全局 QThreadPool 对象,可以不定义QThreadPool 对象,直接通过调用 globalInstance() 访问<QThreadPool::globalInstance()->start(任务)>。
QRunnable
新建一个任务类,继承 QRunnable,重写 run() 方法,并将其传递给线程池 QThreadPool 进行管理。
常用接口
bool QRunnable::autoDelete() const;
void QRunnable::setAutoDelete(bool autoDelete);
QRunnable 常用函数不多,setAutoDelete主要设置其传到底给线程池后,是否需要自动析构(如果启用了 autoDelete,当最后一个线程退出 run() 函数,QRunnable 将被删除)。不调用次函数,默认为true;若该值为false,则需要程序员手动析构,要注意内存泄漏;
QThreadPool
常用接口
1、start()和tryStart
void QThreadPool::start(QRunnable * runnable, int priority = 0);
bool QThreadPool::tryStart(QRunnable * runnable);
- start() 预定一个线程用于执行QRunnable接口,当预定的线程数量超出线程池的最大线程数后,QRunnable接口将会进入队列,等有空闲线程后,再执行;
- priority指定优先级
- tryStart() 和 start() 的不同之处在于,当没有空闲线程后,不进入队列,返回false
2、cancel()和clear()
void QThreadPool::cancel(QRunnable * runnable);
void QThreadPool::clear();
- cancel()如果指定的QRunnable还没有执行,则从队列中移除;
- clear()清空队列中还没有执行的QRunnable;
3、waitForDone()
bool QThreadPool::waitForDone(int msecs = -1);
- 等待所有线程结束并释放资源(如果需要自动释放的话);
- msecs指定超时;
- 若所有线程都被移除,则,返回true,否则返回false;
4、最大线程数
int maxThreadCount() const
void setMaxThreadCount(int maxThreadCount)
- 线程池维护的最大线程数量;
- 设定该值,不会影响已经开始的线程;
- 默认值是最大线程数为
QThread::idealThreadCount()
获取;一般硬件平台几核,最大理想线程数就为几;
5、超时
int expiryTimeout() const
void setExpiryTimeout(int expiryTimeout)
- 线程的终结超时;
- 没有开启,且超过终结时间的线程,会退出,这些线程会根据需要重启开始,即这些线程不会消失,线程池会重新取出这些线程,开启或者放入队列,所谓的终结超时就是重新排列等待队列;
- 建议在创建线程池后,调用 start() 前设定终结超时;
6、全局线程池
static QThreadPool * QThreadPool::globalInstance();
- 全局内存池实例;
- 若创建QThreadPool实例,则在实例生存周期内,内存池有效,
线程池实现
示例1:
(1)首先自定了接口类:
/*********customtasks.h*************/
#ifndef CUSTOMTASKS_H
#define CUSTOMTASKS_H
#include <QObject>
#include <QRunnable>
class CustomTasks : public QRunnable
{
public:
explicit CustomTasks(const QString &threadName);
~CustomTasks();
protected:
void run();
private:
QString threadName;
};
#endif // CUSTOMTASKS_H
/********customtasks.cpp***********/
#include "customtasks.h"
#include <QDebug>
#include <QThread>
CustomTasks::CustomTasks(const QString &name):threadName(name)
{
}
CustomTasks::~CustomTasks()
{
}
void CustomTasks::run()
{
qDebug()<<"Thread Name :"<<threadName<<endl;
qDebug()<<threadName<<"Thread ID :"<<QThread::currentThreadId()<<endl;
}
(2)线程池创建
#include <QApplication>
#include <QThreadPool>
#include "customtasks.h"
#include <QDebug>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug()<<"Main Thread ID :"<<QThread::currentThreadId()<<endl;
QThreadPool *threadPool = new QThreadPool(this);
CustomTasks *tasksRun_1 = new CustomTasks("1# thread");
tasksRun_1->setAutoDelete(true);
CustomTasks *tasksRun_2 = new CustomTasks("2# thread");
tasksRun_2->setAutoDelete(true);
threadPool->start(tasksRun_1);
threadPool->start(tasksRun_2);
return a.exec();
}
示例2:
QRunnable 并不继承自 QObject,也就是说,根本无法使用 QObject 的特性,例如:信号/槽、事件等。为了便于使用,我们可以继承 QObject。
(1)接口类
/*********customtasks.h************/
#ifndef CUSTOMTASKS_H
#define CUSTOMTASKS_H
#include <QObject>
#include <QRunnable>
class CustomTasks : public QObject,public QRunnable
{
Q_OBJECT
public:
explicit CustomTasks(const QString &threadName);
~CustomTasks();
protected:
void run();
private:
QString threadName;
signals:
void signalFinish();
};
#endif // CUSTOMTASKS_H
/*********customtasks.cpp************/
#include "customtasks.h"
#include <QDebug>
#include <QThread>
CustomTasks::CustomTasks(const QString &name):threadName(name)
{
}
CustomTasks::~CustomTasks()
{
}
void CustomTasks::run()
{
qDebug()<<"Thread Name :"<<threadName<<endl;
qDebug()<<threadName<<"Thread ID :"<<QThread::currentThreadId()<<endl;
emit signalFinish();
}
(2) 线程池创建
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "customtasks.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
qDebug()<<"Main Thread ID :"<<QThread::currentThreadId()<<endl;
threadPool = new QThreadPool(this);
CustomTasks *tasksRun_1 = new CustomTasks("1# thread");
tasksRun_1->setAutoDelete(false);
CustomTasks *tasksRun_2 = new CustomTasks("2# thread");
tasksRun_2->setAutoDelete(false);
threadPool->start(tasksRun_1);
threadPool->start(tasksRun_2);
connect(tasksRun_1,&CustomTasks::signalFinish,this,&MainWindow::slotThreadFinish, Qt::UniqueConnection);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::slotThreadFinish()
{
qDebug()<<"The Thread is finish"<<endl;
}
QtConcurrent
若有大量工作需要完成,则使用方式1、2、3均可,但是若只有一小段工作,需要在线程中完成,无论是使用QThread,还是moveToThread,更或者,使用QThreadPool,都有大材小用的感觉,这时候,使用 QtConcurrent 就是最佳选择。
pro文件中添加模块
QT += concurrent
接口函数
QFuture<T> QtConcurrent::run(Function function, ...);
QFuture<T> QtConcurrent::run(QThreadPool * pool, Function function, ...);
- QtConcurrent::run() 方法的第一个参数是线程池,可以指定线程池,若没有指定,则使用全局线程池;
-
第二个参数,执行普通函数,并传参,获取返回值。
示例:
#include <QApplication>
#include <QtConcurrent>
#include <QThreadPool>
#include <QDebug>
void func(QString name)
{
qDebug() << name << "is ID" << QThread::currentThreadId();
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
qDebug()<<"main Thread ID : "<< QThread::currentThreadId();
QThreadPool thread;
QFuture<void> fut1 = QtConcurrent::run(func, QString("Thread 1"));
QFuture<void> fut2 = QtConcurrent::run(&thread,func, QString("Thread 2"));
fut1.waitForFinished();
fut2.waitForFinished();
return a.exec();
}
输出结果:
main Thread ID : 0x28a4
"Thread 1" is ID 0x1154
"Thread 2" is ID 0x2e20
参考网址:1、 (44条消息) Qt中的线程池_SunnyFish-ty的博客-CSDN博客_qt线程池
2、Qt线程池 - sherlock_lin - 博客园 (cnblogs.com)
QProcess
QProcess可用于完成启动外部程序,并与之交互通信。
QProcess *ShotProcess = new QProcess();
ShotProcess->start("路径");
坐标系统
(一)性质:
- 窗口,坐标系统相对于父窗口;
- 原点相对于窗口空白区域左上角(不包括边框);
- X:往右递增,Y:往下递增;
(二)移动坐标
控件->move(100,100);
(三)获取控件的全局坐标
QPoint LinePoint = 控件->mapToGlobal(QPoint(0,0));
(四)坐标函数
frameGeometry().topLeft() //窗口左上角全局坐标
globalPos(); //全局坐标
Qt自定义界面提升
(一)用法
当需要把一个界面(B),放到另一个界面中(A),则需要用到提升。实质是widget继承B类;
(二)特点
- 界面A不能直接操作界面B的控件,必须调用A类的函数来间接操作;
- 界面A中需要拖动一个widget控件,然后将其提升(点击右键->提升为...->提升类的名称:B类的名称->提升),实质是widget继承B类;
QPushButton
(一)点击信号
- pressed --- pressed按下就触发;
- clicked --- clicked按下再弹起才触发;
- toggled --- 这个信号触发的前提是按钮的Checkable属性要设置成true,这样在点击按钮之后就会触发toggled信号;当调用setChecked()函数时,会自动运行槽函数;
- 三个触发先后顺序:toggled 、pressed 、clicked ;
(二)将按钮设为凹陷形式
方法一:需要将按钮Checkable属性要设置成true,setChecked(true)---凹陷形式;
方法二:直接setdown(true),但点击其他地方有恢复,目前我还没找到方法;
(三)将按钮Checkable属性要设置成true时,有两种状态Checked(ture)<按钮凹陷形式>和Checked(false),点击按钮两种状态相互切换;
(三)添加背景图片
ui->pushButton->setStyleSheet("background-image: url(:/new/prefix1/image/cut.png);");
自定义开关
效果如下:
设计思路:
- 在widget上添加一个PushButton,上图蓝色为widget,白色为按钮;
- 点击按钮通过动画(QPropertyAnimation)移动按钮;
- 在需要使用此自定义按钮时,添加一个widget,然后提升为自定义按钮。
程序实现:
/************************.h*************************/
#ifndef SWITCHBUTTONWIDGET_H
#define SWITCHBUTTONWIDGET_H
#include <QWidget>
#include <QPropertyAnimation>
#include <QPointer>
#include <QTimer>
namespace Ui {
class SwitchButtonWidget;
}
class SwitchButtonWidget : public QWidget
{
Q_OBJECT
public:
explicit SwitchButtonWidget(QWidget *parent = nullptr);
~SwitchButtonWidget();
void setSwitchWidgetResize(quint8 wide, quint8 high); //设置窗口大小
bool getSwitchStatus(); //获取开关状态
protected:
void resizeEvent(QResizeEvent* event);
private slots:
void on_pushButton_Switch_clicked();
void slotAnimationStop(); //清零动画标志位
private:
Ui::SwitchButtonWidget *ui;
QPointer<QPropertyAnimation> mAnimation; //动画
bool mSwitchFlag = false; //按钮开关
bool mAnimationing = false; //动画使能
qint8 mWidth = 111; //窗口宽度(设置值)
qint8 mHeight = 50; //窗口高度(设置值)
qint8 mPreWidth = 111; //窗口宽度
qint8 mPreHeight = 50; //窗口高度
qreal mWidthRatio; //宽度比列,用于设置按钮大小
qreal mHeightRatio; //高度比列,用于设置按钮大小
qreal mLeftPointRatio; //按钮在左边时坐标比列
qreal mRightPointRatio; //按钮在右边时坐标比列
};
#endif // SWITCHBUTTONWIDGET_H
/************************.cpp*************************/
#include "SwitchButtonWidget.h"
#include "ui_SwitchButtonWidget.h"
/***************************************************************************************************
函数名称: SwitchButtonWidget()
功能描述: 构造函数
输入参数: 无
返回的值: 无
***************************************************************************************************/
SwitchButtonWidget::SwitchButtonWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::SwitchButtonWidget)
{
ui->setupUi(this);
mPreWidth = this->width();
mPreHeight = this->height();
mWidthRatio = 1.0*ui->pushButton_Switch->width()/ui->widget->width();
mHeightRatio = 1.0*ui->pushButton_Switch->height()/ui->widget->height();
mLeftPointRatio = 6.0/mPreWidth; //6为按钮在左边时的x坐标(见ui)
mRightPointRatio = 55.0/mPreWidth; //55为按钮在右边时的x坐标(见ui)
}
/***************************************************************************************************
函数名称: ~SwitchButtonWidget()
功能描述: 析构函数
输入参数: 无
返回的值: 无
***************************************************************************************************/
SwitchButtonWidget::~SwitchButtonWidget()
{
if(mAnimation != nullptr)
{
delete mAnimation;
}
delete ui;
}
/***************************************************************************************************
函数名称: setSwitchWidgetResize()
功能描述: 重置窗口大小
输入参数: 无
返回的值: 无
***************************************************************************************************/
void SwitchButtonWidget::setSwitchWidgetResize(quint8 wide, quint8 high)
{
mWidth = wide;
mHeight = high;
this->resize(mWidth,mHeight);
}
/***************************************************************************************************
函数名称: getSwitchStatus()
功能描述: 获取开关状态
输入参数: 无
返回的值: 无
***************************************************************************************************/
bool SwitchButtonWidget::getSwitchStatus()
{
return mSwitchFlag;
}
/***************************************************************************************************
函数名称: resizeEvent()
功能描述: 大小重置事件
输入参数: event---事件
返回的值: 无
***************************************************************************************************/
void SwitchButtonWidget::resizeEvent(QResizeEvent *event)
{
Q_UNUSED(event);
ui->widget->resize(mWidth,mHeight);
QString widgetQss = QString("QWidget{border-radius: %1px;background-color: #2058A8;}").arg(mHeight/2);
ui->widget->setStyleSheet(widgetQss);
ui->pushButton_Switch->resize(int(mWidth*mWidthRatio),int(mHeight*mHeightRatio));
QString pushButtonQss = QString("QPushButton{border-radius:%1px;border-style:outset;background-color:rgb(255,255,255);}").arg(ui->pushButton_Switch->height()/2);
ui->pushButton_Switch->setStyleSheet(pushButtonQss);
ui->pushButton_Switch->move(mWidth*mLeftPointRatio,3);
}
/***************************************************************************************************
函数名称: on_pushButton_Switch_clicked()
功能描述: 按钮点击槽函数
输入参数: 无
返回的值: 无
***************************************************************************************************/
void SwitchButtonWidget::on_pushButton_Switch_clicked()
{
if(mAnimationing)
{
return;
}
if(!mSwitchFlag)
{
if(mAnimation == nullptr)
{
mAnimation = new QPropertyAnimation(ui->pushButton_Switch, "pos", this);
}
mAnimation->setDuration(300);
mAnimation->setEasingCurve(QEasingCurve::Linear);
mAnimation->setStartValue(QPointF(mWidth*mLeftPointRatio,3));
mAnimation->setEndValue(QPointF(mWidth*mRightPointRatio, 3));
mAnimation->start();
mSwitchFlag = true;
}
else
{
if(mAnimation == nullptr)
{
mAnimation = new QPropertyAnimation(ui->pushButton_Switch, "pos", this);
}
mAnimation->setDuration(300);
mAnimation->setEasingCurve(QEasingCurve::Linear);
mAnimation->setStartValue(QPointF(mWidth*mRightPointRatio, 3));
mAnimation->setEndValue(QPointF(mWidth*mLeftPointRatio, 3));
mAnimation->start();
mSwitchFlag = false;
}
mAnimationing = true;
QTimer::singleShot(300,this,[=](){
slotAnimationStop();
});
}
/***************************************************************************************************
函数名称: slotAnimationStop()
功能描述: 清零动画标志位
输入参数: 无
返回的值: 无
***************************************************************************************************/
void SwitchButtonWidget::slotAnimationStop()
{
if(mAnimationing)
{
mAnimationing = false;
}
}
QTabWidget
(一)删除页(实质是隐藏)
ui->tabWidget->removeTab(2);//删除第二页
ui->tabWidget->addTab(ui->tab_2,QObject::tr("方法"));//删除后又让其显示
(二)插入页
ui->tabWidget->addTab();
QSQLITE数据库
(一)使用方法
- 在.pro文件添加:QT += core gui spl
- dayinQT支持的数据库驱动:qDebug()<<QSqlDatabase::drivers();
- sqlite数据库需要与QSqlQuery类关联使用;
(二) sqlite数据的函数
QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE"); //创建一个QSqlite数据库 database.setHostName("localhost"); //数据库主机名 database.setDatabaseName("scott"); //数据库名 database.setUserName("stott"); //数据库用户名 database.setPassword("tiger"); //数据库密码 database.open(); //打开数据库连接 database.close(); //释放数据库连接
(三)QSqlQuery类
用于处理sqlite的命令
方法一:
QSqlQuery qsQuery = QSqlQuery(database);
qsQuery.exec("sqlite数据库的命令");
方法二:
QSqlQuery qsQuery = QSqlQuery(database);
QString strSqlText = QString("sqlite命令");
qsQuery.prepare(strSqlText);
qsQuery.exec();
示例:
//设置数据库驱动名称
QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE"); //创建一个QSqlite数据库
/*一般这样用
if(database.contains("数据库名"))
database = QSqlDatabase::database("数据库名");
else
database = QSqlDatabase::addDatabase("QSQLITE" , "数据库名");
*/
//设置数据库名
database.setDatabaseName("../test.db");
if(database.open())
{
qDebug()<<"dadabase open success"<<endl;
}
else
{
qDebug()<<"dadabase open fail"<<endl;
}
QSqlQuery qsQuery = QSqlQuery(database);
qsQuery.exec("create table stu(nu integer,name char,score float)");//创建表
qsQuery.exec("insert into stu values(1,'xiaoming',89)");//插入数据
qsQuery.prepare("select *from stu"); //查询数据
while(qsQuery.next())
{
int num = qsQuery.value(0).toInt();
QString name = qsQuery.value(1).toString();
int score = qsQuery.value(2).toInt();
qDebug()<<"num = "<<num<<" name = "<<name<<" score = "<<score<<endl;
}
qsQuery.exec();
database.close();
(三)查询数据库sqlite中是否含有某个表
QSqlDatabase database = QSqlDatabase::addDatabase("QSQLITE"); //创建一个QSqlite数据库
//设置数据库名
database.setDatabaseName("../test.db");
QString cmd = QString("SELECT COUNT(*) FROM sqlite_master WHERE type='table' AND name='%1'").arg("表名");
SQLBase db = SQLBase(cmd);
QSqlQuery query(database);
query.prepare(cmd);
if(query.first())
{
bool isHaveTable = query.value(0).toBool();//含有某个表返回ture
if(isHaveTable == true)
{
}
}
QMap
(一)性质
1、键不能重复,重复后一个覆盖前一个;
QMap<qint16,bool> mymap;
mymap.insert(12,false);
mymap.insert(22,false);
mymap.insert(12,false);
mymap.insert(55,false);
mymap.insert(66,false);
QMapIterator<qint16,bool> it(mymap);
while(it.hasNext())
{
it.next();
qDebug()<<"key = "<<it.key()<<"value = "<<it.value()<<endl;
}
qDebug()<<mymap[12]<<endl;
(二)用法
1、简单用法
QMap<int,QString>Info;
Info.insert(100,"xiaoming");
Info.insert(87,"xiaohong");
Info.insert(99,"shax");
QString name1 = Info.value(100,NULL);
QString name2 = Info.value(87,NULL);
qDebug()<<"name1 = "<<name1<<endl; //name1 = "xiaoming";
qDebug()<<"name2 = "<<name2<<endl; //name2 = "xiaohong";
常用于QMap<QString,类> Info;和上诉一样。
截图实现
QPixmap::grabWindow(WinId); //获取图片
QDesktopWidget //获取当前程序所在窗口的Id
winId()
#include <QPixmap>
#include <QDesktopWidget>
#include <QDesktopServices>
#include <QFileDialog>
#include <QClipboard>
QPixmap pixmap = QPixmap::grabWindow(QApplication::desktop()->window()->winId());//获取桌面图片
ui->ScreenLabel->setPixmap(pixmap.scaled(ui->ScreenLabel->size()));//将图片显示在label中并按比例缩放
QString fileName = QFileDialog::getSaveFileName(this,"Save file",".");//保存图片
pixmap.save(fileName);
QClipboard *clipboard = QGuiApplication::clipboard();//创建剪切板
//QString originalText = clipboard->text();
clipboard->setPixmap(this->pixmap);//将图片放在剪切板上,可以直接粘贴
事件
所有的事件都是受保护的成员函数。
一、显示鼠标右键光标位置事件
#include <QContextMenuEvent>
void contextMenuEvent(QContextMenuEvent *event)//在函数中实现内容
{
对话框->exec(QCursor::pos());//显示在光标位置
}
二、关闭事件-closeEvent()
#include <QCloseEvent>
void MainWindow::closeEvent(QCloseEvent *event)
{
if()
{
event->accept();//接受事件
}
else
{
event->ignore();//忽略事件
}
}
三、鼠标事件
(一)鼠标按下-mousePressEvent()
void Widget::mousePressEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
QPoint p = event->globalPos() - this->frameGeometry().topLeft();
}
else if(event->button() == Qt::RightButton)
{
this->close();
}
else
{}
Widget::mousePressEvent(event);//信号继续往下传(传给Widget)
}
(二)鼠标移动-mouseMoveEvent()
void Widget::mouseMoveEvent(QMouseEvent *event)
{
move(event->globalPos());
}
(三)鼠标释放-mouseReleaseEvent()
void Widget::mouseReleaseEvent(QMouseEvent *event)
{
if(event->button() == Qt::LeftButton)
{
}
else if(event->button() == Qt::RightButton)
{
}
else
{}
}
示例:
/*移动对话框*/
void Widget::mousePressEvent(QMouseEvent *event)
{
if (event->button() == Qt::LeftButton)
{
firstPoint = QCursor::pos() - frameGeometry().topLeft();
}
}
void Widget::mouseMoveEvent(QMouseEvent *event)
{
if (event->buttons() & Qt::LeftButton)
{
QPoint curPoint = event->globalPos() - firstPoint;
move(curPoint);
}
}
四 、键盘事件
(一)键盘按下-keyPressEvent()
void Widget::keyPressEvent(QKeyEvent *event)
{
if(event->key() == Qt::Key_A)
{
}
}
五、其他事件
(一)、resizeEvent()
resizeEvent()事件触发:
- resize调用或者其他导致窗口事件大小发生变化产生。
- 如果想拖动主窗口的时候,能够让窗口中的组件随着窗口也能缩放的话,需要重写resizeEvent,原因在于,在构造之后,子窗口的大小就是固定的。
画图
画图事件:
- 函数:void paintEvent(QPaintEvent *event);
- 如果在主窗口绘图。必须放在绘图事件里;
- 如果需要重绘图,一定要在 paintEvent()中绘图;
- 绘图事件内部自动调用,窗口需要重绘的时候(状态改变)--调用update()就间接调用了画图事件;
画图事件触发原因:
- 窗口显隐导致重画
- 窗口大小(重新调整)改变,或者重新排布(布局)导致重画
- 调用update 或者 repaint重画
- 当窗口第一次显示时,系统会自动产生绘图事件
- 当窗口部件被其他部件遮挡时,然后又再次显示出来,会对隐藏区域进行重绘事件
画图默认坐标为以窗口左上角为O点,如下图所示:
设置坐标O点为窗口中心:
QPainter painter(this);
painter.translate(this->width()/2.0, this->height()/2.0);
void Widget::paintEvent(QPaintEvent *event)
{
QPainter p(this);//创建画家对象
/*QPainter p;
p.begin(this);
//绘图操作
p.end();*/
//设置背景图
// p.drawPixmap(0,0,this->width(),this->height(),QPixmap("../IMG"));//1
//p.drawPixmap(rect(),QPixmap("../IMG"));//2
//定义画笔
QPen pen;
pen.setWidth(5);//设置线宽
//pen.setColor(Qt::red);//设置颜色
pen.setColor(QColor(12,23,56));//rgb设置颜色
//把画笔交给画家
p.setPen(pen);
//画直线
p.drawLine(50,50,50,150);
//创建画刷对象
QBrush brush;
brush.setColor(Qt::red);//设置颜色
brush.setStyle(Qt::Dense1Pattern);//设置样式
//把画刷交给画家
p.setBrush(brush);
//画矩形
p.drawRect(50,150,50,50);
//画圆形
p.drawEllipse(QPoint(150,150),60,60);//60为半径
QRectF rect(50,50,this->width(),this->height());//(50,50)是坐标,width()/heigh()为宽高,非半径
painter.drawEllipse(rect);
//图片 方法一
p.drawPixmap(0,0,QPixmap("../IMG.png");
p.drawPixmap(0,100,QBitmap("../IMG.png"));//QBitmap只有黑白两种颜色
//图片 方法二
QPixmap pixmap;
pixmap.load("../IMG.png");
p.drawPixmap(0,200,pixmap);
}
(二)绘图设备
- QPixmap:针对屏幕进行优化,和平台有关(显示的效果不一样),不能对图片进行修改;
- QImage:和平台无关,可以对图片进行修改,可以在线程中绘图;
- QPicture:保存绘图的状态(二进制文件);
//绘图设备 400*300
QPixmap pixmap(400,300);
QPainter p(&pixmap);
//填充白色背景色
p.fillRect(0,0,400,300,QBrush(Qt::white));
//pixmap.fill(Qt::white);
p.drawLine(20,20,50,60);
//保存图片
pixmap.save("../pixmap.png");
QPicture pic;
QPainter p(&pic);
p.drawRect(40,40,60,60);
//保存的是二进制文件
pic.save("../pic.png");
(三)画曲线
曲线实质是很多条直线组合而成。
QPainter p(this);//创建画家对象
QPen pen;//定义画笔
pen.setWidth(5);//设置线宽
pen.setColor(Qt::red);//设置颜色
p.setPen(pen);//把画笔交给画家
//方法一
QPoint a(20,30);
QPoint b(150,150);
QPoint c(80,20);
QVector<QPoint> v;
v.append(a);
v.append(b);
v.append(c);
QPolygon polyline(v);
p.drawPolyline(polyline);
//方法二
QPoint a(20,30);
QPoint b(150,150);
QPoint c(80,20);
QPolygon polyline(3);
polyline[0] = a;
polyline[1] = b;
polyline[2] = c;
p.drawPolyline(polyline);
画渐变图形
渐变有三种:线性渐变(QLinearGradient)、半径渐变(QConicalGradient) 、圆锥渐变 (QRadialGradient)。
QGradient父类的常用公共函数有:
void QGradient::setSpread (QGradient::Spread method); 设置填充梯度区域外的区域,参数有: QGradient::PadSpread :填充区域内最接近的停止颜色。这是默认的。 QGradient::RepeatSpread : 在区域外继续重复填充 QGradient::ReflectSpread : 在区域外反射填充 QGradient::setCoordinateMode (QGradient::CoordinateMode mode); 参数:设置渐变的坐标模式,比如QGradient::LogicalMode设置坐标为逻辑坐标(默认为该值) void setColorAt (qreal position, const QColor & color ); 参数:设置梯度颜色, position处于0~1之间
QLinearGradient线性渐变
构造函数:QLinearGradient(qreal x1, qreal y1, qreal x2, qreal y2);
参数:1、x1,y1表示渐变起始坐标, x2,y2表示渐变终点坐标;
2、如果只有x相等,则表示垂直线性渐变,如果只有y相等,则表示平行线性渐变,否则就是斜角线性渐变。
示例:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
QLinearGradient Linear(100,100,100,200); //垂直渐变
Linear.setColorAt(0,Qt::red);
Linear.setColorAt(1,Qt::blue);
painter.setBrush(Linear);
painter.setPen(Qt::transparent);
painter.drawRect(100,100,100,100);
//QRectF rect(50,50,this->width()/2,this->height()/2);
//painter.drawEllipse(rect);
}
QRadialGradient线性渐变
构造函数: QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qreal fy);
参数:1、cx cy : 设置圆的中心原点(center);
2、radius:设置圆半径;
3、fx fy : 设置焦点focus,也就是颜色的起始位置;
示例:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.translate(width()/2,height()/2); //坐标O为窗口中心
QRadialGradient Radial(0,0,100,0,0); //设置圆的原点和焦点在中心,半径100(此半径为渐变半径)
Radial.setColorAt(0,Qt::red);
Radial.setColorAt(0.5,Qt::blue); //设置50%处的半径为蓝色
Radial.setColorAt(1,Qt::green);
painter.setPen(Qt::transparent);
painter.setBrush(Radial);
painter.drawEllipse(-120,-120,240,240);
}
QConicalGradient圆锥渐变
构造函数:QConicalGradient ( qreal cx, qreal cy, qreal angle );
参数:1、(cx,cy)位置为圆锥尖设置;
2、angle角度为起始颜色位置(逆时针渐变)、x轴逆时针方向计算角度。
示例1:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.translate(width()/2,height()/2);
QConicalGradient Conical(0,0,90); //设置点在中心,角度为90
Conical.setColorAt(0,Qt::red);
Conical.setColorAt(0.5,Qt::blue);
Conical.setColorAt(1,Qt::green);
painter.setPen(Qt::transparent);
painter.setBrush(Conical);
painter.drawEllipse(-120,-120,240,240);
}
示例2:
void Widget::paintEvent(QPaintEvent *)
{
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing,true);
painter.translate(width()/2,height()/2);
QConicalGradient Conical(0,0,90); //设置点在中心,角度为90
Conical.setColorAt(0,Qt::blue);
Conical.setColorAt(1,Qt::green);
painter.setPen(Qt::NoPen);
painter.setBrush(Conical);
QRectF rect(-100, -100, 200,200);
QPainterPath path;
path.arcTo(rect, 90, -60); //开始角度->当前角度;注意:第二个参数为起始角度应与Conical一致,
//第三个参数为终点角度,正数表示逆时针方向,负数为顺时针方向
painter.drawPath(path);
}
渐变实现进度
//.文件
protected:
void paintEvent(QPaintEvent *);
private:
void drawBaseCircle(QPainter &painter); //画基础圆
void drawGraduaCirle(QPainter &painter);//画渐变圆
void drawCoverCirle(QPainter &painter); //画覆盖圆
void drawMoveCirlde(QPainter &painter); //画移动圆
private slots:
void slotOutTimer();
private:
Ui::Widget *ui;
quint16 mBaseCircleR; //基础圆(外圆)半径
quint16 mCoverCircleR; //遮盖圆(内圆)半径
quint16 mMoveCircleR; //移动圆半径
qreal mStartAngle = 90; //开始角度
qreal mCurrAngle = 0; //当前角度
QColor mBorderColor = QColor("#B8B8B8"); //边框颜色
QColor mBaseColor = QColor("#EAF3F7"); //基础圆颜色
QColor mStartColor = QColor("#0D74BE"); //起始颜色
QColor mCurrColor = QColor("#0F99E4"); //当前颜色
QPointer<QTimer> timer;
quint16 mProgressValue = 0;//进度
//.cpp文件
void Widget::slotOutTimer()
{
mProgressValue++;
if(mProgressValue >= 60)
{
mProgressValue = 60;
timer->stop();
}
mCurrAngle = -360*(mProgressValue/60.0);//计算当前角度,负数为顺时针
ui->label->setText(QString::number(quint8(mProgressValue/60.0*100)) + tr("%"));
update();
}
void Widget::paintEvent(QPaintEvent *)
{
mBaseCircleR = qMin(width(), height())/2-10;//基础圆(外圆)半径,这里减少10像素是为了保证边缘能完全显示
mCoverCircleR = mBaseCircleR - 20; //遮盖圆(内圆)半径
mMoveCircleR = mBaseCircleR - mCoverCircleR;//移动圆半径
QPainter painter(this);
painter.translate(width()/2.0, height()/2.0);
painter.setRenderHint(QPainter::Antialiasing, true); //反锯齿
drawBaseCircle(painter); //画基础圆
drawGraduaCirle(painter); //画渐变圆
drawCoverCirle(painter); //画覆盖圆
drawMoveCirlde(painter); //画移动圆
}
void Widget::drawBaseCircle(QPainter &painter)
{
QRectF rect(-mBaseCircleR,-mBaseCircleR,mBaseCircleR*2,mBaseCircleR*2);
painter.setPen(QPen(mBorderColor)); //边框
painter.setBrush(mBaseColor);
painter.drawEllipse(rect);
}
void Widget::drawGraduaCirle(QPainter &painter)
{
QRectF rect(-mBaseCircleR, -mBaseCircleR, mBaseCircleR*2, mBaseCircleR*2);
//渐变,当前角度->结束角度
QConicalGradient conical(0, 0, 90); //开始角度90°
conical.setColorAt(-mCurrAngle/360.0, mCurrColor); //当前角度颜色
conical.setColorAt(1.0, mStartColor); //结束角度颜色
painter.setPen(Qt::NoPen);
painter.setBrush(conical);
QPainterPath path;
path.arcTo(rect, 90, mCurrAngle); //开始角度->当前角度,顺时针
painter.drawPath(path);
}
void Widget::drawCoverCirle(QPainter &painter)
{
QRectF rect(-mCoverCircleR, -mCoverCircleR, mCoverCircleR*2, mCoverCircleR*2);
painter.setPen(QPen(QColor("#FFFFFF"), 3));//边框颜色白色,边框大小3
painter.setBrush(QColor("#E4EAEF"));
painter.drawEllipse(rect);
}
void Widget::drawMoveCirlde(QPainter &painter)
{
QPointF point(0, 0);
qreal tempR = mCoverCircleR + (mBaseCircleR - mCoverCircleR)/2.0;
point.setX(point.x() + qCos((mCurrAngle+90)*M_PI/180) * tempR);
point.setY(point.y() - qSin((mCurrAngle+90)*M_PI/180) * tempR);
painter.setPen(QPen(mBorderColor));
painter.setBrush(Qt::white);
painter.drawEllipse(point, mMoveCircleR, mMoveCircleR);
painter.setPen(Qt::NoPen);
painter.setBrush(mCurrColor);
painter.drawEllipse(point, (mBaseCircleR - mCoverCircleR)/2.0, (mBaseCircleR - mCoverCircleR)/2.0);
}
QVariant
一、简述
QVariant 可以保存很多Qt的数据类型,包括QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、 QPalette、QPen、QPixmap、QPoint、QRect、QRegion、QSize和QString,并且还有C++基本类型,如 int、float等。到需要使用的时候使用一系列的to函数取出来即可,注意:对于存入的是什么类型,取出也要为这个类型。
QVariant也可以支持自定义的数据类型。被QVariant存储的数据类型需要有一个默认的构造函数和一个拷贝构造函数。为了实现这个功能,首先必须使用Q_DECLARE_METATYPE()宏。通常会将这个宏放在类的声明所在头文件的下面:
二、简单例子实现
存储用到了QVariant QVariant::fromValue(const T &value) 或 void QVariant::setValue(const T &value)。获取用到了 T QVariant::value() const 或 to函数,在这之前一般要bool QVariant::canConvert(int targetTypeId) const先用进行判断,是否可以转换。
QVariant v1(520);
int num1 = v1.toInt();
QVariant v2 = 520;
int num2 = v2.toInt();
QVariant v3;
v3.setValue(5);
int num3 = v3.toInt(); // num3 = 5
QString str3 = v3.toString(); // str3 = "5"
QVariant v4;
v4.fromValue(5);
int num4 = v4.toInt(); //num4 =5
QString str4 = v4.toString(); //str4 = ""
QVariant v5;
v5.setValue(250);
int num5 = v5.value<int>(); //num5 = 250
QString str5 = v5.value<QString>(); //str5 = "250";
三、自定义存储QVariant类型
QVariant也可以支持自定义的数据类型。被QVariant存储的数据类型需要有一个默认的构造函数和一个拷贝构造函数。为了实现这个功能,首先必须使用Q_DECLARE_METATYPE()宏。通常会将这个宏放在类的声明所在头文件的下面。
struct Student{
QString name;
int age;
int score;
};
Q_DECLARE_METATYPE(Student)
//存储数据
Student stu;
stu.name = "xiaoming";
stu.age = 18;
stu.score = 98;
QVariant v6 = QVariant::fromValue(stu);
//获取数据
Student stu1 = v6.value<Student>();
Movie
一、QMovie实现简单的.gif动态图显示
#include <QMovie>
int main(int argc,char *argv[])
{
QApplication app(argc,argv);
QLabel *label = new QLabel();
//方法一
/*
QMovie *movie = new QMovie("../Photograph/tt.gif");
label->setMovie(movie);
*/
//方法二
QMovie *movie = new QMovie(this);
Movie->setFileName("../Photograph/tt.gif");
label->setMovie(Movie);
Movie->setScaledSize(label->size());//图片大小为label大小
Movie->setSpeed(200);//播放速度
movie->start();
label->show();
return app.exec();
}
二、手动打开.gif
#define MAINWINDOW_H
#include <QMainWindow>
#include <QMovie>
#include <QPixmap>
#include <QString>
#include <QFileDialog>
#include <QFileInfo>
#include <QDebug>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private slots:
void on_pushButton_2_clicked();
void on_pushButton_3_clicked();
void on_pushButton_clicked();
private:
Ui::MainWindow *ui;
QMovie *Movie;
};
#endif // MAINWINDOW_H
/*************************************/
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
Movie = new QMovie(this);
Movie->setScaledSize(ui->label->size());//图片大小为label尺寸
Movie->setSpeed(200);//设置播放速度
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_2_clicked()
{
Movie->start();
}
void MainWindow::on_pushButton_3_clicked()
{
Movie->stop();
}
void MainWindow::on_pushButton_clicked()
{
QString filename = QFileDialog::getOpenFileName(this,"open file","../","file (*.gif*)");//获取文件名,2-4个参数分别为:标题,位置,文件类型
if(!filename.isEmpty())
{
if(Movie->isValid())
{
Movie->stop();
}
Movie->setFileName(filename);
ui->label->setMovie(Movie);
Movie->start();
return;
}
}
QPropertyAnimation(动画)
m_animation = new QPropertyAnimation(ui->label, "pos", this);
m_animation->setDuration(300); //动画,持续3s
m_animation->setEasingCurve(QEasingCurve::Linear);//直线移动
m_animation->setStartValue(QPoint(130, 200)); //开始坐标
m_animation->setEndValue(QPoint(130, 80)); //结束坐标
m_animation->start();
QString
1 、获取str中从第row起连续length个字符
QString str1 = str.mid(row,length);
2 、组合字符串
QString cureTime = QString("%1%2%3").arg(timeHours).arg(":").arg(timeMinutes);
3 、数转字符串
QString str1 = QString::number(num,'f',2);//将浮点型转化为字符串,2为精度
QString str2 = QString::number(num,10); //将整数转化为字符串,10为十进制
QString str3 = QString("%1").arg(num, 8, 16, QLatin1Char('0')); //8代表宽度,16表示16进制,空位补零
4、分开字符
QStringList MyList = str.split("~");//将字符串以“~”分开
5 、填补字符
QString s = "apple";
QString t = s.leftJustified(8, '.'); // t == "apple..."
QString s = "apple";
QString t = s.rightJustified(8, '.'); // t == "...apple"
QString str = "Pineapple";
str = str.leftJustified(5, '.', true); // str == "Pinea"
6 、删除字符串中某个字符
QString s = "Montreal";
s.remove(1, 4);// s == "Meal"
QString t = "Ali Baba";
t.remove(QChar('a'), Qt::CaseInsensitive);// t == "li Bb"
7 、删除字符串后面几个字符
QString str = "Montreal";
str = str.chop(2); //删除后两个字符
7、SString类型转换为const char* (toLatin1)
Qstring str = "helloworld";
char *s;
QByteArray ba = str.toLatin1();
s = ba.data();
8、QString转 char*
QString str = "hello word!";
QByteArray temp = str.toLocal8bit();
char *name = temp.data();
9、char转QString
char buf[128];
QString str = QString::fromLocal8Bit(buf);
样式表
背影样式:
- background-color:背景颜色
- background-image:背景图片
- background-repeat:背景重复
- alternate-background-color:交替背景 //适用于QTableView、QTableWidget和QListView等。
边框样式:
- border-color:边框颜色
- border-style:边框风格
- none: 无样式;
- hidden: 同样是无样式,主要用于解决和表格的边框冲突;
- dotted: 点划线;
- dashed: 虚线;
- solid: 实线/立体;
- double: 双线,两条线加上中间的空白等于border-width的取值;
- groove: 槽状;
- ridge: 脊状,和groove相反;
- inset: 凹陷;
- outset:凸出,和inset相反;
- border-width:边框宽度
- border-image:边框图片
- border-radius:元素的外边框圆角
- border-top-left-radius
- border-top-right-radius
- border-bottom-right-radius
- border-bottom-left-radius
- border-top
- border-top-color
- border-top-style
- border-top-width
- border-right
- border-right-color
- border-right-style
- border-right-width
- border-bottom
- border-bottom-color
- border-bottom-style
- border-bottom-width
- border-left
- border-left-color
- border-left-style
- border-left-width
字体样式:
- color:字体颜色
- font:字体样式
- font-family:字体类型
- font-size:字体大小 //font:13pt 或 font-size:13pt
- font-style:字体风格
- font-weight:字体粗细 //font-weight: bold 黑体
轮廓样式:
- outline:轮廓属性
- outline-color:设置一个元素轮廓的颜色
- outline-offset:设置 outline 与元素边缘或边框之间的间隙
- outline-style:设置元素轮廓的样式
- outline-radius:设置元素的轮廓圆角
- outline-bottom-left-radius
- outline-bottom-right-radius
- outline-top-left-radius
- outline-top-right-radius
padding:
PADDING:是包围content的矩形区域,主要是窗口部件内容与边缘线(border)之间的缝隙,通过padding属性可以定义padding的宽度。
- padding-top
- padding-bottom
- padding-left
- padding-right
内容(content)、填衬(padding)、边框(border)、边距(margin)。使用background-image来指定背景图片,如果希望背景图片随着部件的大小变化,就必须使用border-image。image属性可以用来在border-image之上绘制一个图片、图片对齐参考image-position属性。
基本语法
下面列出了一些基本组合,可以任意组合,各个组合间通过,
分割即可。
选择器
{
属性: 值;
}
QPushButton
{
color: red;
}
选择器 : 状态
{
属性: 值;
}
QPushButton : hover
{
color: red;
}
选择器 :: 辅助控制器
{
属性 : 值;
}
QCheckBox :: indicator
{
color : red;
}
选择器 : 状态
{
属性 : 值;
}
QPushButton : hover
{
color : red;
}
选择器 :: 辅助控制器 : 状态
{
属性 : 值;
}
QTabBar::tab:selected, QTabBar::tab:hover
{
background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #E0E0E0, stop: 1 #FFFFFF);
}
样式表使用方法
1、程序中实现
ui->pushButton->setStyleSheet("background-color:red; color: blue");
ui->pushButton->setStyleSheet("QPushButton{background-color:red; color: blue}");
ui->pushButton->setStyleSheet("QPushButton{background-color:rgb(23,234,245); color: blue}");
ui->pushButton->setStyleSheet("QPushButton{background-color:#00ffff; color: blue}");
2、UI界面实现
设置背景
1、设置背景图片
控件->setStyleSheet("background-image: url(:/new/prefix1/image/cut.png);");
background-image: url(:/new/prefix1/ICO/check_adjust.png);
background-position:center;//图片居中
background-repeat:no-repeat;//图片没有重复
background-color: #B9F8F8;//背景颜色
background-color:transparent;//继承父窗口的背景色
border-image与background-image的区别:
- border-image
border-image:url(:/refresh.png);
border:1px solid red;
- background-image
background-image:url(:/refresh.png);
border:1px solid red;
background-image: url(:/refresh.png);
border:1px solid red;
background-repeat:no-repeat; //不重复
background-position:center; //在中心位置显示
总结
(1)border-image:图片可以自动居中显示,但是设置边框属性无效。
(2)background-iamge:虽然图片不会自动居中显示,但是可以设置其属性,使其居中显示,还可以设置边框的属性。个人觉得background-image比较灵活。
2 、背景渐变色
if(num > 100)
{
num = 100;
}
qreal realValue = num/100.0;
if(realValue == 1)
{
realValue = 0.999;
}
QString qss = QString("QPushButton{border-radius: 0; background: qlineargradient(x1:0,y1:0,x2:1,y2:0,\
stop:0 #15CED0,stop:%1 #15CED0,stop:%2 #B9F8F8,stop:1 #B9F8F8);}")
.arg(realValue).arg(realValue+0.0001);
ui->teButton->setStyleSheet(qss);
按键风格(QPushButon)
1、按键四角圆弧设置
ui->pushButton->setStyleSheet("QPushButton{background-color: rgb(225, 225, 225);border-color:gray;\
border-width:2px;border-radius:20px;border-style:outset groove;}");
2、将按键设置为圆形
首先将按键的长宽设置为一样,将border-radius设置为宽高值的一半,其他设置不变!比如我这里宽高大小为100,那么border-radius就是50px。【原因:圆角大小,因为矩形的一半为50,所以圆角大小 设置为50以后,将会成为一个圆型,小于50,就是圆角矩形了。】
3、按键按下和释放状态不一样
代码设置:
ui->pushButton->setStyleSheet("QPushButton{background-color: rgb(225, 225, 225);border-color:gray;\
border-width:2px;border-radius:20px;border-style:outset groove;}"
"QPushButton:pressed{background-color:rgb(204, 228, 247);border-style: inset;}");
ui界面设置:
方法一:
#pushButton //pushButton为按键名
{
background-color: rgb(225, 225, 225);
border-color:gray;
border-width:2px;
border-radius:10px;
border-style:outset groove;
padding:2px 4px;
}
#pushButton:pressed
{
background-color:rgb(204, 228, 247);
border-style: inset;
}
#pushButton:checked
{
}
#pushButton:disabled
{
}
若此样式在QPushButton上层控件样式表里设置(widget,TabWidget),则只针对按键名为“pushButton”有效。
方法二:
QPushButton
{
background-color: rgb(225, 225, 225);
border-color:gray;
border-width:2px;
border-radius:10px;
border-style:outset groove;
padding:2px 4px;
}
QPushButton:pressed
{
background-color:rgb(204, 228, 247);
border-style: inset;
}
QPushButton:checked
{
}
QPushButton:disabled
{
}
若此样式在QPushButton上层控件样式表里设置(widget,TabWidget),则此控件下所有QPushButton都有效。
QTabWidget样式 设置
1、QTabWidget各位置样式表示
2、示例(效果如上图)
QTabWidget::pane
{
border: 1px solid lightgray;
top:-1px;
background: rgb(245, 245, 245);
}
QTabBar::tab
{
background: rgb(230, 230, 230);
border:1px solid lightgray;
padding: 15px;
font:13pt;
font-weight: bold;
}
QTabBar::tab:selected
{
background: rgb(245, 245, 245);
margin-bottom: -1px;
}
qss实现渐变
圆锥渐变(qconicalgradient)
效果如下(图中花屏录屏软件的问题):
void MainWindow::slotTimerOut() //100ms刷一次
{
mValue--;// 初值为100
if(mValue == 0)
{
mValue = 0;
mTimer->stop();
}
qreal realValue = mValue/100.0;
QString qss = QString("border-radius:40px; border-style:solid;background-color:qconicalgradient(cx:0.5, cy:0.5, angle:90, stop:0 rgba(255, 255, 255,100),stop:%1 rgba(255, 255, 255,100),stop:%2 rgba(0, 85, 255,160),stop:1 rgba(0, 85, 255,160));}").arg(realValue).arg(realValue+0.000001);
ui->pushButton->setStyleSheet(qss);
}
实现扇形渐变的话,我们需要确定扇形的圆心(中心点)、扇形的半径、扇形的起始角度、扇形的跨度,以及扇形所填充颜色的渐变方向。不过这里我们不需要给定半径大小,因为按钮的大小和形状是未知的,所以我们可以认为qconicalgradient()已经将扇形半径设定为无限大了。
qconicalgradient()中的参数:
- cx和cy的值是中心点的逻辑坐标,所谓逻辑坐标就是将它所描述的对象(箱体模型)的左上顶点设为(0.0, 0.0),右下顶点设为(1.0,1.0)。所以这里的(cx:0.5, cy:0.5)就是指定扇形的圆心在按钮的中心点上。
- angle的值代表扇形的起始角度(单位:度),和数学上定义的一样,默认扇形的起始角度为0,即指向x轴的正方向,角度为正是逆时针方向,角度为负是顺时针方向。
- stop可以控制扇形的跨度和颜色,确切来说它控制的是扇形从哪里、以什么颜色开始渐变。stop 0 表示渐变开始的位置(以angle指定的的角度为90,逆时针转360度后为1),stop 01表示结束。rgba(),a表示透明度。
线性渐变(qlineargradient)
void MainWindow::slotTimerOut() //100ms一次
{
mValue++;
if(mValue >= 100)
{
mValue = 100;
mTimer->stop();
}
qreal realValue = mValue/100.0;
QString qss = QString("border-style:solid;background-color:qlineargradient(x1:0,y1:0,x2:1,y2:0, angle:90, stop:0 rgb(26, 156, 226),stop:%1 rgb(26, 156, 226),stop:%2 rgb(127, 186, 0),stop:1 rgb(127, 186, 0));}").arg(realValue).arg(realValue+0.000001);
ui->pushButton->setStyleSheet(qss);
}
QSerialPort(串口)
在 Qt5 中提供了QtSerialPort模块,方便编程人员快速的开发应用串口的应用程序。
当前的QtSerialPort模块中提供了两个C++类,分别是QSerialPort 和QSerialPortInfo。
QSerialPort 类提供了操作串口的各种接口。
QSerialPortInfo 是一个辅助类,可以提供计算机中可用串口的各种信息。
使用时需要在pro文件中增加:QT += serialport
实现串口调试助手
效果及界面:
程序实现:
/*********** .h ***************/
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QSerialPortInfo>
#include <QSerialPort>
#include <QPointer>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
public slots:
void SLOTgetSerialPortName(); //获取所有串口设备
void SLOTopenSerialPort(bool); //打开串口
void SLOTreadData(); //读取串口数据
private slots:
void on_SendBtn_clicked();
private:
Ui::MainWindow *ui;
QPointer<QSerialPort> m_serialPort;
};
#endif // MAINWINDOW_H
/*********** .cpp ***************/
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
#include <QMessageBox>
#include <QTextCodec>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
SLOTgetSerialPortName();
connect(ui->OpenSerialBtn,SIGNAL(clicked(bool)),this,SLOT(SLOTopenSerialPort(bool)),Qt::UniqueConnection);
}
void MainWindow::SLOTgetSerialPortName()
{
//列举出电脑上全部的串口设备
foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts())
{
qDebug() << "Name : " << info.portName();
qDebug() << "Description : " << info.description();
qDebug() << "Manufacturer: " << info.manufacturer();
qDebug() << "Serial Number: " << info.serialNumber();
qDebug() << "System Location: " << info.systemLocation();
ui->NameComboBox->addItem(info.portName());
}
}
void MainWindow::SLOTopenSerialPort(bool checked)
{
if(checked)
{
quint8 index;
m_serialPort = new QSerialPort(this);
m_serialPort->setPortName(ui->NameComboBox->currentText());
if(m_serialPort->open(QIODevice::ReadWrite))
{
ui->radioButton->setChecked(true);
ui->OpenSerialBtn->setText(tr("关闭串口"));
//设置波特率
m_serialPort->setBaudRate(ui->BaudComboBox->currentText().toInt());
//设置数据位
index = ui->DataComboBox->currentIndex();
switch(index)
{
case 0:
m_serialPort->setDataBits(QSerialPort::Data8);
break;
case 1:
m_serialPort->setDataBits(QSerialPort::Data7);
break;
case 2:
m_serialPort->setDataBits(QSerialPort::Data6);
break;
case 3:
m_serialPort->setDataBits(QSerialPort::Data5);
break;
default:
m_serialPort->setDataBits(QSerialPort::UnknownDataBits);
break;
}
//设置校验位
index = ui->CheckComboBox->currentIndex();
switch(index)
{
case 0:
m_serialPort->setParity(QSerialPort::NoParity);
break;
case 1:
m_serialPort->setParity(QSerialPort::OddParity);//奇校验
break;
case 2:
m_serialPort->setParity(QSerialPort::EvenParity);//偶校验
break;
default:
m_serialPort->setParity(QSerialPort::UnknownParity);
}
//设置停止位
index = ui->StopComboBox->currentIndex();
switch(index)
{
case 0:
m_serialPort->setStopBits(QSerialPort::OneStop);
break;
case 1:
m_serialPort->setStopBits(QSerialPort::OneAndHalfStop);
break;
case 2:
m_serialPort->setStopBits(QSerialPort::TwoStop);
break;
default:
m_serialPort->setStopBits(QSerialPort::UnknownStopBits);
}
connect(this->m_serialPort, SIGNAL(readyRead()), this, SLOT(SLOTreadData()));
}
else
{
QMessageBox::about(NULL, "提示", "没有找到串口!");
return;
}
}
else
{
ui->radioButton->setChecked(false);
ui->OpenSerialBtn->setText(tr("打开串口"));
}
}
void MainWindow::SLOTreadData()
{
QByteArray readData = this->m_serialPort->readAll();
ui->ShowTextEdit->setAlignment(Qt::AlignLeft);
if(!readData.isEmpty())
{
quint8 index = ui->ShowWayComboBox->currentIndex();
if(index == 0) //16进制
{
QByteArray showData = readData.toHex();
ui->ShowTextEdit->append(QString(showData));
}
else //10进制
{
QTextCodec *tc = QTextCodec::codecForName("GBK");//QTextCodec::codecForName("GBK")
QString readStr = tc->toUnicode(readData);
ui->ShowTextEdit->append(readStr);
}
readData.clear();
}
}
void MainWindow::on_SendBtn_clicked()
{
QByteArray sendData = ui->SendLineEdit->text().toLatin1();
if(!sendData.isEmpty())
{
this->m_serialPort->write(sendData);
ui->ShowTextEdit->setAlignment(Qt::AlignRight); //靠右显示
quint8 index = ui->ShowWayComboBox->currentIndex();
if(index == 0) //16进制
{
QByteArray showData = sendData.toHex();
ui->ShowTextEdit->append(QString(showData));
}
else //10进制
{
QTextCodec *tc = QTextCodec::codecForName("GBK");
QString sendStr = tc->toUnicode(sendData);
ui->ShowTextEdit->append(sendStr);
}
ui->SendLineEdit->clear();
}
}
MainWindow::~MainWindow()
{
delete ui;
}
正则表达式
Qt下使用正则表达式
首先先看两个例子:
1、限制输入框只能输入数字
QRegExp regx("[1-9][0-9]+$");
QValidator *validator = new QRegExpValidator(regx, ui->lineEdit);
ui->lineEdit->setValidator(validator);
2、提取有效字段
QRegExp rx("[A-Z]*$");//等价 QRegExp rx; rx.setPattern("[A-Z]*$);
QString str = "ADabc123ASFAFF";
int pos = rx.indexIn(str);
if(pos > -1)
{
QString s = rx.cap(0); //ASFAFF
qDebug() << s;
}
3、循环检测匹配字符
QRegExp rx("(\\d+)");
QString str = "Offsets: 12 14 99 231 7";
QStringList list;
int pos = 0;
while ((pos = rx.indexIn(str, pos)) != -1) //偏移量pos
{
list << rx.cap(0); // 第一个捕获到的文本
pos += rx.matchedLength(); // 上一个匹配的字符串的长度
}
qDebug() << list; // 结果:12,14,99,231,7
QRegExp和QRegExpValidator
QRegExpValidator为正则校验
验证的结果有三种状态:
enum State
{
Invalid, //验证通不过
Intermediate, //输入未完成,不确定是否能通过验证
Acceptable //验证通过
}
//正则
QRegExp mRegExp;
mRegExp.setPattern("[1-9][0-9]+$");
QRegExpValidator mRegExpV;
mRegExpV.setRegExp(mRegExp);
//判断是否可以使用正负号
qint32 pos = 0;
QString strSign = "-";
QValidator::State state = mRegExpV.validate(strSign, pos);
if(state == QValidator::Acceptable)
{
}
正则表达式常用语法
参考原文:(51条消息) Qt正则表达式_岁小草的草窝-CSDN博客_qt正则表达式
- 简单转义字符
表达式 | 匹配 |
/r,/n | 代表回车和换行符 |
/t | 制表符 |
// | 代表“/”本身 |
/^ | 匹配^本身 |
/$ | 匹配$本身 |
/. | 匹配.本身 |
- 能够与 '多种字符' 匹配的表达式
正则表达式中的一些表示方法,可以匹配 '多种字符' 其中的任意一个字符。比如,表达式 "/d" 可以匹配任意一个数字。虽然可以匹配其中任意字符,但是只能是一个,不是多个。
表达式 | 可匹配 |
/d | 任意一个数字,0~9 中的任意一个 |
/w | 任意一个字母或数字或下划线,也就是 A~Z,a~z,0~9,_ 中任意一个 |
/s | 包括空格、制表符、换页符等空白字符的其中任意一个 |
. | 小数点可以匹配除了换行符(/n)以外的任意一个字符 |
- 自定义能够匹配 '多种字符' 的表达式
使用方括号 [ ] 包含一系列字符,能够匹配其中任意一个字符。用 [^ ] 包含一系列字符,则能够匹配其中字符之外的任意一个字符。同样的道理,虽然可以匹配其中任意一个,但是只能是一个,不是多个。
表达式 | 说明 | 例子 |
[ ] | 包含一系列字符 | 1、[abc12]: 匹配 "a" 或 "b" 或 "c" 或 "1"或"2" 2、[a-z]:匹配a~z 3、[^A-F0-3]:匹配 "A"~"F","0"~"3" 之外的任意一个字符 |
[^ ] | 包含之外一系列字符 | [^abc]:包含abc之外的任意字符 |
- 修饰匹配次数的特殊符号
前面讲到的表达式,无论是只能匹配一种字符的表达式,还是可以匹配多种字符其中任意一个的表达式,都只能匹配一次。如果使用表达式再加上修饰匹配次数的特殊符号,那么不用重复书写表达式就可以重复匹配。
使用方法:"次数修饰"放在"被修饰的表达式"后边。比如:"[bcd][bcd]" 可以写成 "[bcd]{2}"。
表达式 | 作用 |
{n} | 表达式重复n次,比如:"/w{2}" 相当于 "/w/w";"a{5}" 相当于 "aaaaa" |
{m,n} | 表达式至少重复m次,最多重复n次,比如:"ba{1,3}"可以匹配 "ba"或"baa"或"baaa" |
{m,} | 表达式至少重复m次,比如:"/w/d{2,}"可以匹配 "a12","_456","M12344"... |
? | 匹配表达式0次或者1次,相当于 {0,1},比如:"a[cd]?"可以匹配 "a","ac","ad" |
+ | 表达式至少出现1次,相当于 {1,},比如:"a+b"可以匹配 "ab","aab","aaab"... |
* | 表达式不出现或出现任意次,相当于 {0,},比如:"/^*b"可以匹配 "b","^^^b"... |
举例1:表达式 "/d+/.?/d*" 在匹配 "It costs $12.5" 时,匹配的结果是:成功;匹配到的内容是:"12.5";匹配到的位置是:开始于10,结束于14。
举例2:表达式 "go{2,8}gle" 在匹配 "Ads by goooooogle" 时,匹配的结果是:成功;匹配到的内容是:"goooooogle";匹配到的位置是:开始于7,结束于17。
- 其他一些代表抽象意义的特殊符号
一些符号在表达式中代表抽象的特殊意义:
表达式 | 作用 |
^ | 与字符串开始的地方匹配,不匹配任何字符 |
$ | 与字符串结束的地方匹配,不匹配任何字符 |
/b | 匹配一个单词边界,也就是单词和空格之间的位置,不匹配任何字符 |
进一步的文字说明仍然比较抽象,因此,举例帮助大家理解。
举例1:表达式 "^aaa" 在匹配 "xxx aaa xxx" 时,匹配结果是:失败。因为 "^" 要求与字符串开始的地方匹配,因此,只有当 "aaa" 位于字符串的开头的时候,"^aaa" 才能匹配,比如:"aaa xxx xxx"。
举例2:表达式 "aaa$" 在匹配 "xxx aaa xxx" 时,匹配结果是:失败。因为 "$" 要求与字符串结束的地方匹配,因此,只有当 "aaa" 位于字符串的结尾的时候,"aaa$" 才能匹配,比如:"xxx xxx aaa"。
举例3:表达式 "./b." 在匹配 "@@@abc" 时,匹配结果是:成功;匹配到的内容是:"@a";匹配到的位置是:开始于2,结束于4。
进一步说明:"/b" 与 "^" 和 "$" 类似,本身不匹配任何字符,但是它要求它在匹配结果中所处位置的左右两边,其中一边是 "/w" 范围,另一边是 非"/w" 的范围。
举例4:表达式 "/bend/b" 在匹配 "weekend,endfor,end" 时,匹配结果是:成功;匹配到的内容是:"end";匹配到的位置是:开始于15,结束于18。
一些符号可以影响表达式内部的子表达式之间的关系:
表达式 | 作用 |
| | 左右两边表达式之间 "或" 关系,匹配左边或者右边 |
( ) | (1). 在被修饰匹配次数的时候,括号中的表达式可以作为整体被修饰 |
举例5:表达式 "Tom|Jack" 在匹配字符串 "I'm Tom, he is Jack" 时,匹配结果是:成功;匹配到的内容是:"Tom";匹配到的位置是:开始于4,结束于7。匹配下一个时,匹配结果是:成功;匹配到的内容是:"Jack";匹配到的位置时:开始于15,结束于19。
举例6:表达式 "(go/s*)+" 在匹配 "Let's go go go!" 时,匹配结果是:成功;匹配到内容是:"go go go";匹配到的位置是:开始于6,结束于14。
举例7:表达式 "¥(/d+/.?/d*)" 在匹配 "$10.9,¥20.5" 时,匹配的结果是:成功;匹配到的内容是:"¥20.5";匹配到的位置是:开始于6,结束于10。单独获取括号范围匹配到的内容是:"20.5"。
- 匹配次数中的贪婪与非贪婪
贪婪与非贪婪模式影响的是被量词修饰的子表达式的匹配行为。
贪婪模式在整个表达式匹配成功的前提下,尽可能多的匹配。
非贪婪模式在整个表达式匹配成功的前提下,尽可能少的匹配。
内容 | aa<div>test1</div>bb<div>test2</div>cc |
贪婪表达式 | <div>.*</div> |
贪婪匹配 | <div>test1</div>bb<div>test2</div> |
非贪婪表达式 | <div>.*?</div> |
非贪婪匹配 | <div>test1</div> |
Lambda表达式
一个lambda表达式表示一个可调用的代码单元。我们可以将其理解为一个未命名的内联函数。与任何函数类似,一个lambda具有一个返回类型、一个参数列表和一个函数,但与函数不同,lambda可能定义在函数内部。一个lambda表达式具有如下形式:
[capture list](parameter list)->return type {function body}
capture list:捕获列表,是一个lambda所在函数中定义的局部变量的列表(通常为空);通过捕获列表访问一些上下文中的数据。具体地,捕捉列表描述了上下文中哪些数据可以被Lambda使用,以及使用方式(以值传递的方式或引用传递的方式)。语法上,在“[]”包括起来的是捕捉列表,捕捉列表由多个捕捉项组成,并以逗号分隔。捕捉列表有以下几种形式:
- [var]表示值传递方式捕捉变量var;
- [=]表示值传递方式捕捉所有父作用域的变量(包括this);父作用域,也就是包含Lambda函数的语句块,说通俗点就是包含Lambda的“{}”代码块。
- [&var]表示引用传递捕捉变量var;
- [&]表示引用传递方式捕捉所有父作用域的变量(包括this);
- [this]表示值传递方式捕捉当前的this指针。
上面的捕捉列表还可以进行组合,例如:
- [=,&a,&b]表示以引用传递的方式捕捉变量a和b,以值传递方式捕捉其它所有变量;
- [&,a,this]表示以值传递的方式捕捉变量a和this,引用传递方式捕捉其它所有变量。
不过值得注意的是,捕捉列表不允许变量重复传递。下面一些例子就是典型的重复,会导致编译时期的错误。例如:
- [=,a]这里已经以值传递方式捕捉了所有变量,但是重复捕捉a了,会报错的;
- [&,&this]这里&已经以引用传递方式捕捉了所有变量,再捕捉this也是一种重复。
parameter list、return type和function body与任何普通函数一样,分别表示参数列表、返回类型和函数体。
QString str1("first use lambda expression");
QString str2("second use lambda expression");
connect(ui->pushButton, &QPushButton::clicked, [=](bool checked)
{
qDebug() << "str1=" << str1 << endl;
qDebug() << "checked=" << checked <<endl;
});
connect(ui->pushButton_2, &QPushButton::clicked, [=]()
{
qDebug() << "str2=" << str2 << endl;
});
QTimer::singleShot(0, this, [&](){
startAnimation();
});
Qt常用函数
1、设置控件大小
void resize(int w, int h); //给控件设置大小
void resize(const QSize &);
2、控件
方法一:setVisible(false);
方法二:hide();//实质调用setVisible(false)
3、foreach
foreach虽然是for循环的简化版本,但是并不是说foreach就比for更好用,foreach适用于循环次数未知,或者计算循环次数比较麻烦情况下使用效率更高,但是更为复杂的一些循环还是需要用到for循环效率更高。
QStringList slt = {"abc", "qwe", "upo"};
foreach(QString s,slt)
{
cout<<s<<endl;
}
// 输出结果为:abc qwe upo
4、Q_UNUSED
Q_UNUSED()消除未用变量警告
int ret;
Q_UNUSED(ret) //消除未用变量警告(如果ret在函数中未使用将会报警)