Qt学习心得

目录

Qt特性

Qt核心特点

Qt容器

Qt快捷键

Qt类库模块

Qt控件的使用

QSpinBox、QDoubleSpinBox

QTextEdit

进度条

时间控件

QPlainTextEdit

QComBox

QListWidget

QTreeWidget

QtableWidget

Model、View结构

QFileSystemModel

QStringListModel

QStandardItemModel

QItemSelectionModel

自定义代理

Qt对话框

QFileDialog

QColorDialog

QFontDialog

字符输入对话框

整形输入对话框

浮点数输入对话框

条目输入对话框

Question消息框

information消息框

warning消息框

critical消息框

about消息框

自定义对话框及调用

多窗体应用程序设计

SPlash和登录窗口

文本文件读写

QFile IODevice读写文件

QTextSteam读写文件

解决汉字乱码问题

二进制文件读写

使用QDataStream读写stm类型文件

使用QDataStream读写dat类型文件

使用DataStream读取.dat文件

文件目录操作

QPainter基本绘制

坐标系统和坐标转换

视口坐标和窗口坐标

QtCharts

Qtchart绘制折线图​​​​​​​

QBarChart

绘制饼状图(QPieChart)

绘制堆积图(QStackedBar)

绘制散点图(Scatterchart)

Qt特性

Qt核心特点

元对象编译器(Meta-Object Compiler,MOC)是一个预处理器 先将Qt的特性程序转换为标准C++程序,在由标准C++编译器进行编译

使用信号与槽机制,只有添加Q_OBJECT宏,moc才能对类里的信号与槽进行预处理

Qt为C++语言增加的特性在Qt Core模块里实现,由Qt的元对象系统实现。 包括:信号与槽机制、属性系统、动态类型转换等。

元对象系统(Meta-Object System)

QObject类是所有使用元对象系统的类的基类 在一个类的private部分声明Q_OBJECT宏 MOC(元对象编译器)为每个QObject的子类提供必要的代码

可以使用Qobject对象对Qt的控件进行控制

QObject *obj = new QMyWidget; QWidget *widget = qobject_cast<QWidget *>(obj); QMyWidget *myWidget = qobject_cast<QMyWidget *>(obj); QLabel *label = qobject_cast<QLabel *>(obj); //不会报错,label为NULL

qobject_cast<QWidget *> 为类型转换,加了之前就相当于调用了指向QWidget的指针,可以对QWidget进行操作

qobject_cast<QLabel *>(obj);//obj原本指向QWidget,但使用QLabel对其进行指向,QWidget不包含QWidget的内容,因此返回的东西为Null;

Q_PROPERTY宏定义一个返回类型为type,名称为name的属性

class TestWidget : public QWidget
{
    Q_OBJECT
    Q_CLASSINFO("author", "liu")
};
    TestWidget * test = new TestWidget;
    qDebug() << test->metaObject()->classInfo(0).name();
    qDebug() << test->metaObject()->classInfo(0).value();

QClassInfo可以记录类的附加信息,通过metaobject进行调用获取

Qt容器

QMap是键值对关系 key不能重复 QMultiMap的key可以重复

QHash 和 QMap的区别 : QMap是连续存储的,里面的值也是按顺序存储的 QHash里面的值不一定是按顺序存储的,而是按映射存储的

QSet是基于散列表的

C++ Map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值) 对于迭代器来说,可以修改实值,而不能修改key

C++vector容器的定义 vector<int>::iterator i; //定义正向迭代器

vector<int>::reverse_iterator j; //用反向迭代器遍历容器

Qt快捷键

F4 头文件和cpp进行切换 F2定义和实现之间进行切换 F1光标所在的符号显示帮助

Qt类库模块

其他模块都依赖于Qt Core模块,使用 qmake 构建,此模块会自动被加入项目 QT -= gui qmake 构建时,Qt GUI 模块是自动被加入项目的。如果项目中不使用 GUI 功能: QT += multimedia multimediawidgets QT += sql

Qt控件的使用

QSpinBox、QDoubleSpinBox

QSpinBox常用于现在整数prefix为前缀,sufix为后缀

QDoubleSpinBox常用于显示double,可以设置显示的小数点位数,前后缀方式与QSpinbox相同

QTextEdit

QTextEdit的palatte可以用来显示颜色,可做控制面板使用

QColor  color;
int R=ui->SliderRed->value();  //读取SliderRed的当前值
int G=ui->SliderGreen->value();//读取 SliderGreen 的当前值
int B=ui->SliderBlue->value();//读取 SliderBlue 的当前值
int alpha=ui->SliderAlpha->value();//读取 SliderAlpha 的当前值
color.setRgb(R,G,B,alpha); //使用QColor的setRgb()函数 获得颜色
​
QPalette pal=ui->textEdit->palette();//获取textEdit原有的 palette
pal.setColor(QPalette::Base,color); //设置palette的基色(即背景色)
​
ui->textEdit->setPalette(pal);//设置为textEdit的palette,改变textEdit的底色

进度条

QSlider为滑动条,值改变的槽函数为valuechanged(int)

QScollBar也为滑动条,类似网页下面的滑动条,值改变的槽函数为valuechanged(int)

QProgressBa为进度条,可以显示百分比及进度,类似软件界面启动加载界面,值改变的槽函数为valuechanged(int),但不可滑动类型QSlider和QScollBar改变他的值

QDial类似一个钟表,滑动可以改变他的值,值改变的槽函数为valuechanged(int)

QLCDNumber

QLCDNumber常用于显示数字和时间等,可以进行二进制、八进制、十进制、十六进制转换显示,也可以设置显示的位数,通过display设置显示的内容

ui->LCDDisaplay为ui界面的QLCDNumber控件

ui->LCDDisplay->display(value);
//设置LCD显示二进制数
ui->LCDDisplay->setDigitCount(8);
ui->LCDDisplay->setBinMode();
//设置LCD显示八进制数
ui->LCDDisplay->setDigitCount(4);
ui->LCDDisplay->setOctMode();
//设置LCD显示十六进制数
ui->LCDDisplay->setDigitCount(3);
ui->LCDDisplay->setHexMode();
//设置LCD显示十进制数
ui->LCDDisplay->setDigitCount(3);
ui->LCDDisplay->setDecMode();

时间控件

QTimeEdit用于显示当前时间的时分秒

QDateTime curDateTime=QDateTime::currentDateTime(); //读取当前日期时间
​
//editTime为QlineEdit控件,使用字符转换显示时间
ui->timeEdit->setTime(curDateTime.time()); //设置时间
ui->editTime->setText(curDateTime.toString("hh:mm:ss"));//转换为字符串显示

QDateEdit用于显示年月日

//editDate为QlineEdit控件,使用字符转换显示时间
ui->dateEdit->setDate(curDateTime.date());//设置日期
ui->editDate->setText(curDateTime.toString("yyyy-MM-dd"));//转换为字符串显示

QDateTimeedit用于显示完整的时间年月日时分秒

//editDateTime为QlineEdit控件,使用字符转换显示时间
ui->dateTimeEdit->setDateTime(curDateTime);//设置日期时间
ui->editDateTime->setText(curDateTime.toString("yyyy-MM-dd hh:mm:ss"));//转换为字符串显示

QCalendarWidget为日历控件,用于显示日历,槽函数为selectionChanged()函数,使用QDate可以获取日历上选择的时间

void Dialog::on_calendarWidget_selectionChanged()
{ //在日历上选择日期
    QDate dt=ui->calendarWidget->selectedDate(); //读取选择的日期时间
    QString str=dt.toString("yyyy年M月d日");//转换为字符串
    ui->editCalendar->setText(str); //字符串显示日期
}

QPlainTextEdit

可以通过设置Qt界面的Property中的lineWrapMode属性来设置是否自动换行,NoWrap为不自动换行

appendPlainText()为在QPlainTextEdit后面添加内容

QPlainTextEdit的文字内容以QTextDocument类型储存,函数document返回这个文档对象的指针。 QTextDocument是内存中的文本对象,以文本块的方式储存,每个段落以换行符结束 QTextDocument提供一些函数实现对文本内容的存取 int blockCount(),返回文本块个数 QTextBlock finBlockByNumber(int ),读取一个文本块,序号从0开始

QTextDocument * doc = ui->plainTextEdit->document();
int count = doc->blockCount();
 QIcon ico(":/imasges/icons/aim.ico");
    for (int i = 0; i < count ; i++)
    {
        ui->comboBox->addItem(ico, doc->findBlockByNumber(i).text());
    }

QComBox

  QIcon ico(":/imasges/icons/UNIT.ICO");
    QMap<QString, int> City_Zone;
    City_Zone.insert("北京",10);
    City_Zone.insert("上海",21);
    City_Zone.insert("天津",22);
    City_Zone.insert("大连",411);
    City_Zone.insert("锦州",416);
    City_Zone.insert("徐州",516);
    City_Zone.insert("福州",591);
    City_Zone.insert("青岛",532);
​
    foreach(auto str, City_Zone.keys())
    {
        ui->comboBox2->addItem(ico, str, City_Zone.value(str));
    }
 通过foreach设置Qcombox的icon和值,addItem的第一个参数为icon,第二个参数为显示的内容,第三个参数为value
槽事件 currentIndexChanged(const QSting & arg1);
 if(!arg1.isEmpty())
    {
        //获取的是QComBox的第三个设置的值
        QString zone = ui->comboBox2->currentData().toString();
        ui->plainTextEdit->appendPlainText(arg1 + "区号" + zone);
    }
    
槽事件中返回的参数为additem的第二个参数,currentData()为addItem中设置的第三个参数

QListWidget

通过QListWidgetItem来获取QListWidget上的表项

QListWidgetItem * aItem = ui->listWidget->item(i);
//通过setFlags来设置QListWidget上的表项的可用、可编辑、可选择等
aItem->setFlags(Qt::ItemIsSelectable|Qt::ItemIsEditable|
Qt::ItemIsUserCheckable|Qt::ItemIsEnabled);

QListWidgetItem可在前面添加Icon

QListWidgetItem * aItem;
QIcon icon(":/images/icons/check2.ico");
QString str = QString::asprintf("New Insert append");
aItem = new QListWidgetItem(str);
aItem->setIcon(icon);
aItem->setCheckState(Qt::Checked);
ui->listWidget->addItem(aItem);

QActon可添加QMenu

QMenu * menu = new QMenu(this);
menu->addAction(ui->actSelALL);
menu->addAction(ui->actSelNone);
menu->addAction(ui->actSelInvs);
ui->actSelPopMenu->setMenu(menu);

QDockWidegt

QDockWidegt设置可见性和浮动性

void MainWindow::on_actDockVisible_triggered(bool arg1)
{
    ui->dockWidget->setVisible(arg1);
}
​
void MainWindow::on_actDockFloat_triggered(bool checked)
{
    ui->dockWidget->setFloating(checked);
}

QDockWidegt自身具体槽事件,来监听QDockWidegtd的可见性状态和浮动性状态topLevelChanged(bool topLevel)和visibilityChanged(bool visible)

void MainWindow::on_dockWidget_topLevelChanged(bool topLevel)
{
    ui->actDockFloat->setChecked(topLevel);
}
​
void MainWindow::on_dockWidget_visibilityChanged(bool visible)
{
    ui->actDockVisible->setChecked(visible);
}

QTreeWidget

QTreeWidget通过QTreeWidgetItem来获取QTreeWidget的某项数据,QTreeWidgetItem的数据分为两部分

可以通过枚举类型对QTreeWidget节点类型进行区分

//枚举类型treeItemType, 用于创建 QTreeWidgetItem 时作为节点的type, 自定义类型必须大于1000
//itTopItem 顶层节点;  itGroupItem 组节点; itImageItem 图片
enum  treeItemType{itTopItem=1001,itGroupItem,itImageItem};
//枚举类型,表示列号
enum  treeColNum{colItem=0, colItemType=1}; //目录树列的编号定义
QTreeWidgetItem * parItem = ui->treeWidget->currentItem();
QTreeWidgetItem * item = new QTreeWidgetItem(itGroupItem);
QIcon icon(":/images/icons/open3.bmp");
item->setIcon(colItem, icon);
item->setText(colItem, dir);
item->setText(colItemType, "type:group");
item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsAutoTristate); //设置节点选项
item->setCheckState(colItem,Qt::Checked); //节点选中
​
//通过setData向QTreeWidgetItem里面设置数据
item->setData(colItem,Qt::UserRole,QVariant(fullname)); //设置角色为Qt::UserRole的Data,存储完整目录名称
​
parItem->addChild(item); //在父节点下面添加子节点
//QTreeWidget的表项改变事件
void MainWindow::on_treeWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{
    Q_UNUSED(previous);
    if(current==NULL) return;
    
    //获取之前设置的枚举类型
    int var = current->type();
    switch (var)
    {
        case itTopItem:
            ui->actAddFiles->setEnabled(true);
            ui->actAddFolder->setEnabled(true);
            ui->actDeleteItem->setEnabled(true);
        break;
        case itGroupItem:
            ui->actAddFiles->setEnabled(true);
            ui->actAddFolder->setEnabled(true);
            ui->actDeleteItem->setEnabled(true);
        break;
        case itImageItem:
            ui->actAddFiles->setEnabled(true);
            ui->actAddFolder->setEnabled(false);
            ui->actDeleteItem->setEnabled(true);
            ui->actZoomIn->setEnabled(true);
            ui->actZoomFitH->setEnabled(true);
            ui->actZoomFitW->setEnabled(true);
            ui->actZoomOut->setEnabled(true);
            ui->actZoomRealSize->setEnabled(true);
            LabFileName.setText(current->data(colItem,Qt::UserRole).toString());
            
            //获取QTreeWidgetItem之前设置的数据
            curPixmap.load(current->data(colItem,Qt::UserRole).toString());
            on_actZoomFitW_triggered();
    }
}

QtableWidget

通过ui界面设置tabsCloseable设置QtableWidget是否具有关闭按钮。

//将ui的center设置为Qtablewidget
setCentralWidget(ui->tabWidget);
​
//设置是否可见
ui->tabWidget->setVisible(false);
​
//设置全屏显示
//setWindowState(Qt::WindowMaximized);

Model、View结构

•数据:如数据库的一个数据表或SQL查询结果,内存中的一个 StringList,或磁盘文件结构等。

•Model:与数据通信,并为视图组件提供数据接口。

•View:是屏幕上的界面组件,视图从数据模型获得每个数据项的模型索引(model index),通过模型索引获取数据

•代理:定制数据的界面显示和编辑方式。在标准的视图组件中,代理功能显示一个数据,当数据被编辑时,提供一个编辑器,一般是QLineEdit 。

模型、视图和代理之间使用信号和槽通信

数据类型

Model 用途
QStringListModel用于处理字符串列表数据的数据模型类
QStandardltemModel标准的基于项数据的数据模型类,每个项数据可以是任何数据类型
QFileSystemModel计算机上文件系统的数据模型类
QSortFilterProxyModel与其他数据模型结合,提供排序和过滤功能的数据模型类
QSqlQueryModel用于数据库SQL查询结果的数据模型类
QSqlTableModel用于数据库的一个数据表的数据模型类
QSqlRelationalTableModel用于关系型数据表的数据模型类

数据模型中存储数据的基本单元都是项(item),每个项有一个行号、一个列号,还有一个父项

QModelIndex 表示模型索引的类。模型索引提供数据存取的一个临时指针

//Table Model
QModelIndex indexA = model->index(0, 0, QModelIndex());
QModelIndex indexC = model->index(2, 1, QModelIndex());
//Tree Model
indexA 表示indexB的根节点
QModelIndex indexB = model->index(1, 0, indexA);

QFileSystemModel

如同 Widnows 的资源管理器一样。使用 QFileSystemModel 提供的接口函数,可以创建目录、删除目录、重命名目录,可以获得文件名称、目录名称、文件大小等参数,还可以获得文件的详细信息。

QFileSystemModel * model = new QFileSystemModel;
model->setRootPath(QDir::currentPath());

//通过QFileSystemModel,使用QTreeView、QListView、QTableView可以直接通过QModleIndex调用QFileSystemModel读取的内容

//给出this指针,当窗体关闭的时候,指针会自动进行回收
//直接给TreeView ListView tableView设置文件模型,即可显示文件基本信息(类似文件管理器)
fileMode = new QFileSystemModel(this);
fileMode->setRootPath(QDir::currentPath());
ui->treeView->setModel(fileMode);
ui->listView->setModel(fileMode);
ui->tableView->setModel(fileMode);
ui->tableView->verticalHeader()->setVisible(false);
​
//连接信号,当QTreeViewd的表项发生变化时,QListView、QTableView发生相应的变化
connect(ui->treeView, SIGNAL(clicked(QModelIndex)), ui->listView, SLOT(setRootIndex(QModelIndex)));
connect(ui->treeView, SIGNAL(clicked(QModelIndex)), ui->tableView, SLOT(setRootIndex(QModelIndex)));

可以通过QModelIndex来获取QFileSystemModel存取的信息

void MainWindow::on_treeView_clicked(const QModelIndex &index)
{
    //通过QFileSystemModel的QModelIndex来获取文件名、文件大小、文件类型、及是否是文件夹
    ui->labName->setText(fileMode->fileName(index));
    ui->labPath->setText(fileMode->filePath(index));
    ui->labType->setText(fileMode->type(index));
    unsigned sz = fileMode->size(index) / 1024;
​
    if(sz < 1024)
    {
        ui->labSize->setText(QString::asprintf("%d kb", sz));
    }
    else
    {
        ui->labSize->setText(QString::asprintf("%2F kb", (float)sz/1024));
    }
​
    ui->checkBox->setChecked(fileMode->isDir(index));
} 

QStringListModel

//定义QStringListModel
QStringListModel  *themodel;

//设置QStringListModel 的数据

theModle = new QStringListModel(this);
QStringList         theStrList; //保存初始 StringList
theStrList<<"北京"<<"上海"<<"天津"<<"河北"<<"山东"<<"四川"<<"重庆"<<"广东"<<"河南"; //初始化 StringList
theModle->setStringList(theStrList);
//给QListView设置模式,即将QStringListModel的值给给QListView设置模式
ui->listView_2->setModel(theModle);
 //获取QStringListModel设置的值
 QStringList strlist = theModle->stringList();
 
 //将从QStringListModel获取的值设置到QPlainTextEdit中去
 foreach(auto str, strlist)
 {
    ui->plainTextEdit_2->appendPlainText(str);
 }

QStandardItemModel

#define FixedColumnCount 6
QStandardItemModel  *theModel;//数据模型
QItemSelectionModel *theSelection;//Item选择模型
​
//为tableView设置数据模型 打通了Mode和View之间的关系
theModel = new QStandardItemModel(10, FixedColumnCount, this);
theSelection = new QItemSelectionModel(theModel);
ui->tableView->setModel(theModel); //设置数据模型
ui->tableView->setSelectionModel(theSelection);//设置选择模型

QStandardItemModel添加数据

void MainWindow::iniModelFromStringList(QStringList& aFileContent)
{ //从一个StringList 获取数据,初始化数据Model
    int rowCnt=aFileContent.count(); //文本行数,第1行是标题
    theModel->setRowCount(rowCnt-1); //实际数据行数
​
    //设置表头
    QString header=aFileContent.at(0);//第1行是表头
    //一个或多个空格、TAB等分隔符隔开的字符串, 分解为一个StringList
    QStringList headerList=header.split(QRegExp("\\s+"),QString::SkipEmptyParts);
    theModel->setHorizontalHeaderLabels(headerList); //设置表头文字
​
    //设置表格数据
    int j;
    QStandardItem   *aItem;
    for (int i=1;i<rowCnt;i++)
    {
        QString aLineText=aFileContent.at(i); //获取 数据区 的一行
        //一个或多个空格、TAB等分隔符隔开的字符串, 分解为一个StringList
        QStringList tmpList=aLineText.split(QRegExp("\\s+"),QString::SkipEmptyParts);
        for (j=0;j<FixedColumnCount-1;j++) //tmpList的行数等于FixedColumnCount, 固定的
        { //不包含最后一列
            aItem=new QStandardItem(tmpList.at(j));//创建item
            theModel->setItem(i-1,j,aItem); //为模型的某个行列位置设置Item
        }
​
        aItem=new QStandardItem(headerList.at(j));//最后一列是Checkable,需要设置
        aItem->setCheckable(true); //设置为Checkable
        if (tmpList.at(j)=="0")
        aItem->setCheckState(Qt::Unchecked); //根据数据设置check状态
        else
        aItem->setCheckState(Qt::Checked);
        theModel->setItem(i-1,j,aItem); //为模型的某个行列位置设置Item
    }
}
//设置QStandardItemModel表头
QStringList     headerList;
headerList<<"Depth"<<"Measured Depth"<<"Direction"<<"Offset"<<"Quality"<<"Sampled";
theModel->setHorizontalHeaderLabels(headerList); //设置表头文字
​
//设置QStandardItemModel行数
theModel->setColumnCount(5);

使用文件输入输出流读写文件

//打开文件
QString curPath=QCoreApplication::applicationDirPath(); //获取应用程序的路径
//调用打开文件对话框打开一个文件
QString aFileName=QFileDialog::getOpenFileName(this,"打开一个文件",curPath,
"井数据文件(*.txt);;所有文件(*.*)");
if (aFileName.isEmpty())
return; //如果未选择文件,退出
​
QStringList fFileContent;//文件内容字符串列表
QFile aFile(aFileName);  //以文件方式读出
if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) //以只读文本方式打开文件
{
    QTextStream aStream(&aFile); //用文本流读取文件
    ui->plainTextEdit->clear();//清空
    while (!aStream.atEnd())
    {
        QString str=aStream.readLine();//读取文件的一行
        ui->plainTextEdit->appendPlainText(str); //添加到文本框显示
        fFileContent.append(str); //添加到 StringList
    }
    aFile.close();//关闭文件
​
    this->LabCurFile->setText("当前文件:"+aFileName);//状态栏显示
    ui->actAppend->setEnabled(true); //更新Actions的enable属性
    ui->actInsert->setEnabled(true);
    ui->actDelete->setEnabled(true);
    ui->actSave->setEnabled(true);
​
    iniModelFromStringList(fFileContent);//从StringList的内容初始化数据模型
​
    //设置行列自适应
    ui->tableView->resizeRowsToContents();
    ui->tableView->resizeColumnsToContents();
}

使用文件输入输出流保存文件

{  
//打开文件
    QString curPath=QCoreApplication::applicationDirPath(); //获取应用程序的路径
    //调用打开文件对话框打开一个文件
    QString aFileName=QFileDialog::getSaveFileName(this,"选择一个文件",curPath,
    "井数据文件(*.txt);;所有文件(*.*)");
    if (aFileName.isEmpty())
    return; //如果未选择文件,退出
​
    QFile aFile(aFileName);  //以文件方式读出
    if (!aFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)) //以读写文本及覆盖文本方式打开文件
    return;
​
    //以文件流对文件进行操作
    QTextStream stream(&aFile);
    QString str;
    ui->plainTextEdit->clear();
​
    //获取表头数据
    QStandardItem * Item;
    for(int i = 0; i< theModel->columnCount(); i++)
    {
        Item = theModel->horizontalHeaderItem(i);
        //加入两个tab符,跟之前数据保持一致
        str = str + Item->text() + "\t\t";
    }
    //写入数据
    stream << str << "\n";
    ui->plainTextEdit->appendPlainText(str);
​
    //获取内容
    int j;
    //下表从0开始,因为上方已经将表头元素分开
    for (int i = 0; i < theModel->rowCount(); i++)
    {
    str = "";
​
    for (j = 0; j < theModel->columnCount() - 1; j++)
    {
        Item = theModel->item(i, j);
        str = str + Item->text()+ "\t\t";
    }
​
    //拿到最后一列
    Item = theModel->item(i, j);
    if(Item->checkState() == 1)
    str = str + "1";
    else
    str = str + "0";
​
    //写入数据
    stream << str << "\n";
    ui->plainTextEdit->appendPlainText(str);
}

QItemSelectionModel

QItemSelectionModel常与QStandardItemModel连用

theModel = new QStandardItemModel(10, FixedColumnCount, this); theSelection = new QItemSelectionModel(theModel);

QItemSelectionModel主要用于获取view中选择的数据项位于model的那个位置及表格的位置

向QStandardItemModel里面插入数据

//使用Qlist对数据进行添加行
QList<QStandardItem *> itemList;
​
QStandardItem * item;
//往Model里面添加数据
for (int i = 0; i < FixedColumnCount - 1; i++)
{
    item = new QStandardItem("000");
    itemList<<item;
}
//获取表头元素最后一列的数据
QString str = theModel->headerData(theModel->columnCount() -1, Qt::Horizontal,Qt::DisplayRole).toString();
​
//设置最后一行
item = new QStandardItem(str);
item->setCheckState(Qt::Checked);
itemList<<item;
​
int curRow = theSelection->currentIndex().row();
//在Model最后一行添加数据
theModel->insertRow(curRow,itemList);
​
//重新设置最后一行的选择模式
theSelection->clearSelection();
QModelIndex index = theModel->index(curRow, 0);
theSelection->setCurrentIndex(index,QItemSelectionModel::Select);

自定义代理

使用代理必须实现以下几个函数:

•createEditor():创建用于编辑模型数据的widget组件,如QSpinBox,QComboBox。

•setEditorData():从数据模型获取数据,供widget组件进行编辑 。

•setModelData():将widget上的数据更新到数据模型。

•updateEditorGeometry():用于给widget组件设置一个合适的大小。

QStyledItemDelegate为代理类,如果想要实现代理,需要继承这个类,按f2进去可以了解要代理的部分,主要包括painting、editing、editor factory

将QlineEdit通过代理换成QSpinBox

//创建用于编辑模型数据的widget组件
QWidget *QIntDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QSpinBox * editor = new QSpinBox(parent);
​
    //设置QSpinbox的属性
    editor->setMinimum(0);
    editor->setMaximum(1000);
    editor->setFrame(false);
​
    return editor;
}
​
//从数据模型获取数据,供widget组件进行编辑
void QIntDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
{
    //通过index获取model 在通过model获取数据
    int value = index.model()->data(index, Qt::EditRole).toInt();
​
    //将类型转换为QSpinbox类型
    QSpinBox * spinbox = static_cast<QSpinBox *>(editor);
​
    //设置值
    spinbox->setValue(value);
}
​
//将widget上的数据更新到数据模型
void QIntDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
{
    //将类型转换为QSpinbox类型
    QSpinBox * spinbox = static_cast<QSpinBox *>(editor);
​
    //拿到现在的取值
    spinbox->interpretText();
​
    //设置model
    int value = spinbox->value();
    model->setData(index, value, Qt::EditRole);
}
​
//用于给widget组件设置一个合适的大小
void QIntDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    //设置大小
    editor->setGeometry(option.rect);
}

写好代理类之后通过在tableview(视图)上设置即可使用

QIntDelegate intSpinDelegate;//设置自定义代理
//调用代理
//为第0列设置自定义代理
ui->tableView->setItemDelegateForColumn(0, &intSpinDelegate);

Qt对话框

标准对话框

QFileDialog

//选择单个文件
QString curPath=QDir::currentPath();//获取系统当前目录
//  QString  curPath=QCoreApplication::applicationDirPath(); //获取应用程序的路径
QString dlgTitle="选择一个文件"; //对话框标题
QString filter="文本文件(*.txt);;图片文件(*.jpg *.gif *.png);;所有文件(*.*)"; //文件过滤器
​
QString aFileName=QFileDialog::getOpenFileName(this,dlgTitle,curPath,filter);
​
if (!aFileName.isEmpty())
ui->plainTextEdit->appendPlainText(aFleName);

QColorDialog

//设置QplaintTextEdit字体颜色
QPalette pal = ui->plainTextEdit->palette();
QColor inicolor = pal.color(QPalette::Text);
​
//通过QColorDialog选择的颜色返回出来 inicolor为初始的颜色
QColor color = QColorDialog::getColor(inicolor, this, "选择颜色");
​
//将获取的样式设置到QplainTextEdit中
if(!color.isValid()) return;
pal.setColor(QPalette::Text, color);
ui->plainTextEdit->setPalette(pal);

QFontDialog

//设置字体
bool ok = false;
QFont iniFont = ui->plainTextEdit->font();
​
//第一个参数如果选择成功 则返回true 否则返回false
QFont font = QFontDialog::getFont(&ok, iniFont, this, "选择字体");
​
//为QPliantTextEdit设置选择的字体
if(!ok) return;
ui->plainTextEdit->setFont(font);

输入对话框

字符输入对话框

//输入字符串
QString dlgTitle="输入文字对话框";
QString txtLabel="请输入文件名";
QString defaultInput="新建文件.txt";
QLineEdit::EchoMode echoMode=QLineEdit::Normal;//正常文字输入
//    QLineEdit::EchoMode echoMode=QLineEdit::Password;//密码输入
​
bool ok=false;
QString text = QInputDialog::getText(this, dlgTitle,txtLabel, echoMode,defaultInput, &ok);

整形输入对话框

//输入整数
QString dlgTitle="输入整数对话框";
QString txtLabel="设置字体大小";
int defaultValue=ui->plainTextEdit->font().pointSize(); //现有字体大小
int minValue=6, maxValue=50,stepValue=1; //范围,步长
bool ok=false;
int inputValue = QInputDialog::getInt(this, dlgTitle,txtLabel,
defaultValue, minValue,maxValue,stepValue,&ok);
if (ok) //是否确认输入
{
    QFont   font=ui->plainTextEdit->font();
    font.setPointSize(inputValue);
    ui->plainTextEdit->setFont(font);
}

浮点数输入对话框

//输入浮点数
QString dlgTitle="输入浮点数对话框";
QString txtLabel="输入一个浮点数";
float defaultValue=3.13;
​
float minValue=0, maxValue=10000;  //范围
int decimals=2;//小数点位数
​
bool ok=false;
float inputValue = QInputDialog::getDouble(this, dlgTitle,txtLabel,
defaultValue, minValue,maxValue,decimals,&ok);
if (ok) //确认选择
{
    QString str=QString::asprintf("输入了一个浮点数:%.2f",inputValue);
    ui->plainTextEdit->appendPlainText(str);
}

条目输入对话框

//条目选择输入
QStringList items; //ComboBox 列表的内容
items <<"优秀"<<"良好"<<"合格"<<"不合格";
​
QString dlgTitle="条目选择对话框";
QString txtLabel="请选择级别";
int     curIndex=0; //初始选择项
bool    editable=true; //ComboBox是否可编辑
bool    ok=false;
QString text = QInputDialog::getItem(this, dlgTitle,txtLabel,items,curIndex,editable,&ok);
​
if (ok && !text.isEmpty())
ui->plainTextEdit->appendPlainText(text);

标准消息框

Question消息框

QString dlgTitle="Question消息框";
QString strInfo="文件已被修改,是否保存修改?";
​
QMessageBox::StandardButton  defaultBtn=QMessageBox::NoButton; //缺省按钮
​
QMessageBox::StandardButton result;//返回选择的按钮
result=QMessageBox::question(this, dlgTitle, strInfo,
QMessageBox::Yes|QMessageBox::No |QMessageBox::Cancel,
defaultBtn);
​
if (result==QMessageBox::Yes)
ui->plainTextEdit->appendPlainText("Question消息框: Yes 被选择");
else if(result==QMessageBox::No)
ui->plainTextEdit->appendPlainText("Question消息框: No 被选择");
else if(result==QMessageBox::Cancel)
ui->plainTextEdit->appendPlainText("Question消息框: Cancel 被选择");
else
ui->plainTextEdit->appendPlainText("Question消息框: 无选择");

information消息框

QString dlgTitle="information消息框";
QString strInfo="文件已经打开,字体大小已设置";
​
//QMessageBox::information(this, dlgTitle, strInfo);//使用缺省的按钮
QMessageBox::information(this, dlgTitle, strInfo,
QMessageBox::Ok,QMessageBox::NoButton);

warning消息框

QString dlgTitle="warning 消息框";
QString strInfo="文件内容已经被修改";
​
QMessageBox::warning(this, dlgTitle, strInfo);

critical消息框

QString dlgTitle="critical消息框";
QString strInfo="有不明程序访问网络";
QMessageBox::critical(this, dlgTitle, strInfo);

about消息框

QString dlgTitle="about消息框";
QString strInfo="我开发的数据查看软件 V1.0 \n 保留所有版权";
​
QMessageBox::about(this, dlgTitle, strInfo);

自定义对话框及调用

如果想要在一个窗体调用使用另外一个窗体的元素,可以通过写public方法,通过调用public方法实现调用,需要在被调用窗体发出信号供主窗体接收,如按确认按钮发出accept()信号

首先在头文件声明方法

int     rowCount();//获取对话框输入的行数
int     columnCount();//获取对话框输入的列数
void    setRowColumn(int row, int column); //初始对话框上两个SpinBox的值

在cpp实现方法

int QWDialogSize::rowCount()
{ //用于主窗口调用获得行数的输入值
    return  ui->spinBoxRow->value();
}
​
int QWDialogSize::columnCount()
{//用于主窗口调用获得列数的输入值
    return  ui->spinBoxColumn->value();
}
​
void QWDialogSize::setRowColumn(int row, int column)
{ //初始化数据显示
    ui->spinBoxRow->setValue(row);
    ui->spinBoxColumn->setValue(column);
}

在另外一个窗体添加头文件,new出来然后调用

QWDialogSize    *dlgTableSize=new QWDialogSize(this); //创建对话框
 dlgTableSize->setRowColumn(theModel->rowCount(),theModel->columnCount()); //对话框数据初始化
int ret=dlgTableSize->exec();// 以模态方式显示对话框,用户关闭对话框时返回 DialogCode值
if (ret==QDialog::Accepted) //OK键被按下,对话框关闭,若设置了setAttribute(Qt::WA_DeleteOnClose),对话框被释放,无法获得返回值
{ //OK键被按下,获取对话框上的输入,设置行数和列数
    int cols=dlgTableSize->columnCount();
    theModel->setColumnCount(cols);
​
    int rows=dlgTableSize->rowCount();
    theModel->setRowCount(rows);
}
delete dlgTableSize; //删除对话框
//如果不想删除可以调用窗体的属性,实现自动删除
//dlgTableSize->setAttribute(Qt::WA_DeleteOnClose);

调用父窗体的方法

MainWindow *parWind = (MainWindow*)parentWidget(); //获取主窗口
//首先在父窗体new出来 传入this,作为父窗体
dlgLocate = new QWDialogLocate(this); //创建对话框,传递指针
dlgLocate->setAttribute(Qt::WA_DeleteOnClose); //对话框关闭时自动删除对话框对象,用于不需要读取返回值的对话框
​
//后调用父窗口的public方法
#include "mainwindow.h"
void QWDialogLocate::on_btnSetText_clicked()
{//定位到单元格,并设置字符串
    int row=ui->spinBoxRow->value(); //行号
    int col=ui->spinBoxColumn->value();//列号
​
    MainWindow *parWind = (MainWindow*)parentWidget(); //获取主窗口
    parWind->setACellText(row,col,ui->edtCaption->text()); //设置单元格文字
    if (ui->chkBoxRow->isChecked()) //行增
        ui->spinBoxRow->setValue(1+ui->spinBoxRow->value());
​
    if (ui->chkBoxColumn->isChecked()) //列增
        ui->spinBoxColumn->setValue(1+ui->spinBoxColumn->value());
}

多窗体应用程序设计

//窗体的一些的属性设置
void QWidget::setWindowState(Qt::WindowStates windowstate);
常量意义
Qt::NonModal无模态,不会阻止其他窗口的输入
Qt::WindowModal窗口对于其父窗口、所有的上级父窗口都是模态的
Qt::ApplicationModal窗口对整个应用程序是模态的,阻止所有窗口的输入
//设置窗体透明度 参数 level 是 1.0(完全不透明)至 0.0(完全透明)之间的数。窗口透明度缺省值是 1.0,即完全不透明。
void QWidget::setWindowOpacity(qreal level); 
//设置窗体属性
void QWidget::setAttribute(Qt::WidgetAttribute attribute, bool on = true);
常量意义
Qt:: WA_AcceptDrops允许窗体接收拖放来的组件
Qt::WA_DeleteOnClose窗体关闭时删除自己,释放内存
Qt::WA_Hover鼠标进入或移出窗体时产生paint事件
Qt:: WAAcceptTouchEvents窗体是否接受触屏事件

void QWidget::setWindowFlags(Qt::WindowFlags type);
表示窗体类型的常量
Qt::Widget这是 QWidget 类的缺省类型。这种类型的窗体,如果它有父窗体,就作为父窗 体的子窗体;否则就作为一个独立的窗口
Qt::Window表明这个窗体是一个窗口,通常具有窗口的边框、标题栏,而不管它是否有父窗体
Qt::Dialog表明这个窗体是一个窗口,并且要显示为对话框(例如在标题栏没有最小化、 最大化按钮)。这是 QDialog 类的缺省类型
Qt::Popup表明这个窗体是用作弹出式菜单的窗体
Qt::Tool表明这个窗体是工具窗体,具有更小的标题栏和关闭按钮,通常作为工具栏的 窗体
Qt::ToolTip表明这是用于 Tooltip 消息提示的窗体
Qt::SplashScreen表明窗体是splash屏幕,是 QSplashScreen 类的缺省类型
Qt::Desktop表明窗体是桌面,这是 QDesktopWidget 类的类型
Qt::SubWindow表明窗体是子窗体,例如 QMdiSubWindow 就是这种类型
控制窗体显示效果的常量
Qt::MSWindowsFixedSizeDialogHint在 Windows 平台上,使窗口具有更窄的边框,用于固定大小的对话框
Qt::FramelessWindowHint创建无边框窗口
WindowHint要定义窗体外观定制窗体外观的常量,需要先设置 Qt::Customize
Qt::CustomizeWindowHint关闭缺省的窗口标题栏
Qt::WindowTitleHint窗口有标题栏
Qt::WindowSystemMenuHint有窗口系统菜单
Qt::WindowMinimizeButtonHint有最小化按钮
Qt::WindowMaximizeButtonHint有最大化按钮
Qt::WindowMinMaxButtonsHint有最小化、最大化按钮
Qt::WindowCloseButtonHint有关闭按钮
Qt::Windo wContextHelpButtonHint有上下文帮助按钮
Qt::WindowStaysOnTopHint窗口总是处于最上层
Qt::WindowStaysOnBottomHint窗口总是处于最下层
Qt::WindowTransparentForlnput窗口只作为输出,不接受输入

QMainWindow创建的时候可以使用其他窗体作为父窗体,如:

QMainWindow * testMain = new QMainWindow(this);
testMain->setAttribute(Qt::WA_DeleteOnClose);
testMain->setWindowTitle("多实例窗口,指定父窗口");
testMain->show();

但QWidget则一般不会使用QMainWindow作为它的父窗体,如果作为父窗体则贴在父窗体上不能移动,一般不传入this指针使用

//不加入this窗体关闭不会进行自动回收
QFormDoc * fordoc = new QFormDoc();
//设置关闭时自动删除
fordoc->setAttribute(Qt::WA_DeleteOnClose);
//设置窗口标题
fordoc->setWindowTitle("基于QWidget的窗体,无父窗口,关闭时删除");
//设置窗体透明度
fordoc->setWindowOpacity(0.7);
fordoc->show();

MDI应用程序设计

MDI模式的使用应加入头文件 #include "QMdiSubWindow"

//设置MDI模式 级联展开为分为几个不同窗体打开 平铺展开为几个窗体在同一个大窗体展开
void MainWindow::on_actViewMode_triggered(bool checked)
{
    if(checked)
    {
        //设置为TableView模式
        ui->mdiArea->setViewMode(QMdiArea::TabbedView);
​
        //设置tableview模式窗体可关闭
        ui->mdiArea->setTabsClosable(true);
​
        //设置平铺展开和级联展开不可用
        ui->actCascade->setEnabled(false);
        ui->actTile->setEnabled(false);
    }
    else
    {
        //设置为窗体模式(默认模式)
        ui->mdiArea->setViewMode(QMdiArea::SubWindowView);
​
        //设置平铺展开和级联展开可用
        ui->actCascade->setEnabled(true);
        ui->actTile->setEnabled(true);
    }
}
​
​
//这两种模式在QMdiArea::SubWindowView(窗体模式)进行使用
void MainWindow::on_actCascade_triggered()
{
    //设置QMdiArea级联模式
    ui->mdiArea->cascadeSubWindows();
​
}
​
void MainWindow::on_actTile_triggered()
{
    //设置QMdiArea平铺模式
    ui->mdiArea->tileSubWindows();
}
​
//当当前选择的Widget发生改变时,状态栏显示文件地址
void MainWindow::on_mdiArea_subWindowActivated(QMdiSubWindow *arg1)
{
    //如果没有窗口的话 设置剪切复制等为不可用 清空状态栏的内容
    if(ui->mdiArea->subWindowList().count() == 0)
    {
        ui->actCopy->setEnabled(false);
        ui->actCut->setEnabled(false);
        ui->actFont->setEnabled(false);
        ui->actPaste->setEnabled(false);
        ui->statusBar->clearMessage();
    }
    else
    {
        //显示主窗口的文件名
        FormDoc * mdoc = (FormDoc *)ui->mdiArea->activeSubWindow()->widget();
        ui->statusBar->showMessage(mdoc->GetcurrentFileName());
    }
}
//打开文件 FormDoc为自定义QWidget
void MainWindow::on_actDoc_Open_triggered()
{
    bool needNew = false;
    FormDoc * mdoc;
​
    //获取QMdiArea的个数
    if(ui->mdiArea->subWindowList().count() > 0)
    {
        // ui->mdiArea->activeSubWindow()获取的是QMdiSubWindow对象
        //如果想要获取相应的Qwidget 需要使用ui->mdiArea->activeSubWindow()->widget();后进行类型转换
        mdoc = (FormDoc*)ui->mdiArea->activeSubWindow()->widget();
        needNew = mdoc->isFileOpened();
    }
    else
    {
        needNew = true;
    }
​
    if(needNew)
    {
        mdoc = new FormDoc(this);
        //向获取QMdiArea里面添加Widget
        ui->mdiArea->addSubWindow(mdoc);
    }
​
    QString fileName = QFileDialog::getOpenFileName(this, "open", "", "C程序文件(.h *cpp);;所有文件" );
    mdoc->loadFromFile(fileName);
    mdoc->show();
    ui->actCopy->setEnabled(true);
    ui->actCut->setEnabled(true);
    ui->actFont->setEnabled(true);
    ui->actPaste->setEnabled(true);
}
//加载文件 使用QTextStream对文件进行读取
void FormDoc::loadFromFile(QString &aFileName)
{
    QFile file(aFileName);
​
    //QIODevice::ReadOnly设置为只读 QIODevice::Text设置为文本格式,会自动处理\n \t等字符
    if(file.open(QIODevice::ReadOnly)|QIODevice::Text)
    {
        //使用QTextStream对文本进行操作
        QTextStream stream(&file);
​
        //填充QPlainText
        ui->plainTextEdit->clear();
        ui->plainTextEdit->setPlainText(stream.readAll());
​
        //获取文件的路径和名称
        mCurrentFile = aFileName;
        QFileInfo fileinfo(aFileName);
        QString str = fileinfo.fileName();
        setWindowTitle(str);
​
        //设置为true,代表文档已经是打开的状态
        m_isOpen = true;
    }
}

SPlash和登录窗口

Qt有一个QSplashScreen类可以实现Splash窗口的功能,它提供了载入图片,自动设置窗口无边框效果等功能。

QSettings配置表的存入和读取

#include <QSettings>
//写入注册表
void DialogLogin::writeSettings()
{
    //使用QSettings将信息写入注册表中 第一个参数为库名 第二个参数为表名
    QSettings settings("LF-QT", "Simple6_5");
​
    //为注册表添加数据
    settings.setValue("Username", m_user);
    settings.setValue("PSWD", m_pswd);
    settings.setValue("saved", ui->chkBoxSave->isChecked());//是否保存
}
​
//读取配置表的数据
void DialogLogin::readSettings()
{
     QSettings settings("LF-QT", "Simple6_5");
​
     //获取配置表数据 进行类型转换
     //第一个参数为关键值 也就是SetValue的第一个参数,第二个参数为默认值
     bool saved = settings.value("saved", false).toBool();
     m_user = settings.value("Username", "user").toString();
​
     //设置默认密码 进行加密处理
     QString defaultPSWD = encrypt("123456");
     m_pswd = settings.value("PSWD", defaultPSWD).toString();
​
     //如果勾选了 自动填充账号
     if(saved)
     {
         ui->editUser->setText(m_user);
     }
     ui->chkBoxSave->setChecked(saved);
}

使用哈希算法对md5进行加密

#include <QCryptographicHash>
//对密码进行加密
QString DialogLogin::encrypt(const QString &str)
{
    QByteArray btArray;
    btArray.append(str);
​
    //使用哈希算法进行加密 加密格式为md5类型
    QCryptographicHash hash(QCryptographicHash::Md5);
    hash.addData(btArray);
​
    //接收加密后的结果 并进行十六进制类型转换存储
    QByteArray resultArray = hash.result();
    QString resultmd5 = resultArray.toHex();
    return resultmd5;
}

设置QDialog属性

ui->editPSWD->setEchoMode(QLineEdit::Password); //密码输入编辑框设置为密码输入模式
this->setAttribute(Qt::WA_DeleteOnClose);//设置为关闭时删除
this->setWindowFlags(Qt::SplashScreen); //设置为SplashScreen, 窗口无边框,不在任务栏显示

使用鼠标事件使得无标头的QDialog可以进行移动

#include <QMouseEvent>
​
//头文件
protected:
    //用于鼠标拖动窗口的鼠标事件操作
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void mouseReleaseEvent(QMouseEvent *event);
    bool    m_moving=false;//表示窗口是否在鼠标操作下移动
    QPoint  m_lastPos;  //上一次的鼠标位置
​
//cpp文件
void DialogLogin::mousePressEvent(QMouseEvent *event)
{
    if(event->buttton == Qt::LeftButton)
    {
        m_moving = true;
        
  //记录移动的距离 globalPos()为鼠标点击后的位置到(0,0)点距离  pos()为DialogLogin窗体到(0,0)点距离
        m_lastPos = event->globalPos() - pos();
    }
​
    return DialogLogin::mouseMoveEvent(event);
}
​
void DialogLogin::mouseMoveEvent(QMouseEvent *event)
{
    if(m_moving && (event->buttton == Qt::LeftButton))
    {
        move(event->globalPos() - m_lastPos);
        m_lastPos = event->globalPos() - pos();
    }
}
​
void DialogLogin::mouseReleaseEvent(QMouseEvent *event)
{
    m_moving = false;
}
​

文本文件读写

枚举值描述
QIODevice::ReadOnly以只读方式打开
QIODevice::WriteOnly以只写方式打开
QIODevice::ReadWrite以读写方式打开
QIODevice::Append新增加的内容将被追加到文件末尾
QIODevice::Truncate以重写的方式打开,原有内容会被删除
QIODevice::Text在读取时,将行结束符转换成 \n;在写入时,将行结束符转换成本地格式,例如 Win32 平台上是 \r\n

QFile IODevice读写文件

#include <QFileDialog>
//使用QFile读取文件
void MainWindow::on_actOpen_IODevice_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "打开文件";
    QString filter = "程序(*.h *.cpp);;文本( *.txt);; 所有文件(*.*)";
    QString fileName = QFileDialog::getOpenFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //使用QFile IODevice对文件进行读取
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        ui->plainTextEditIODevice->setPlainText(QString::fromLocal8Bit(file.readAll()));
        file.close();
        ui->tabWidget->setCurrentIndex(0);
    }
}
​
//使用QFile另存为文件 即写文件
void MainWindow::on_actSave_IODevice_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "打开文件";
    QString filter = "程序(*.h);;文本( *.txt);; 所有文件(*.*)";
    QString fileName = QFileDialog::getSaveFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //打开文件进行写操作
    QFile file(fileName);
    if(file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        //获取QPlainText的内容 并进行类型转换后写入文件内
        QString str = ui->plainTextEditIODevice->toPlainText();
​
        //写入文件
        QByteArray btyArray = str.toUtf8();
        file.write(btyArray, btyArray.length());
​
        //关闭文件
        file.close();
​
        //设置QtabWidget当前索引
        ui->tabWidget->setCurrentIndex(0);
    }
}

QTextSteam读写文件

#include <QFileDialog>
#include <QTextStream>
//使用QTextStream进行读取
void MainWindow::on_actOpen_TextStream_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "打开文件";
    QString filter = "程序(*.h *.cpp);;文本( *.txt);; 所有文件(*.*)";
    QString fileName = QFileDialog::getOpenFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //使用QFile对文件进行读取
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly | QIODevice::Text))
    {
        //QTextStream可以一行一行读取
        QTextStream stream(&file);
​
        //设置自动识别编码
        stream.setAutoDetectUnicode(true);
​
        //使用一行一行读取
        while(stream.atEnd())
        {
             ui->plainTextEditTextSteam->appendPlainText(stream.readLine());
        }
        //ui->plainTextEditTextSteam->setPlainText(stream.readAll());
        file.close();
        ui->tabWidget->setCurrentIndex(1);
    }
}
​
//使用QTextSTream进行另存为操作 即写操作
void MainWindow::on_actSave_TextStream_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "打开文件";
    QString filter = "程序(*.h);;文本( *.txt);; 所有文件(*.*)";
    QString fileName = QFileDialog::getSaveFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //打开文件进行写操作
    QFile file(fileName);
    if(file.open(QIODevice::WriteOnly | QIODevice::Text))
    {
        QTextStream stream(&file);
​
        //设置自动识别编码
        stream.setAutoDetectUnicode(true);
​
        //获取QPlainText的内容 并进行类型转换后写入文件内
        QString str = ui->plainTextEditTextSteam->toPlainText();
​
        //使用文件流写入文件
        stream<< str;
        file.close();
        ui->tabWidget->setCurrentIndex(1);
    }
}

解决汉字乱码问题

//解决汉字乱码问题 一般写在main函数内 其他文件读写操作都可解决乱码问题
QTextCodec *codec = QTextCodec::codecForName("UTF-8");
QTextCodec::setCodecForLocale(codec); //解决汉字乱码问题

二进制文件读写

二进制文件存储方式

主要分为两种,一种的大地址在前面,一种是小地址在前面。

0x1234567的存储方式

1、小地址在前 2、大地址在前

0x100 0x101 0x102 0x013 0x100 0x101 0x102 0x013

01 23 45 67 67 45 23 01

使用 QFile 和 QDataStream 进行二进制数据文件的读写

QFile 负责文件的 IO 设备接口,即与文件的物理交互; QDataStream 以数据流的方式读取文件内容或写入文件内容。Qt预定义编码 标准编码

以 Qt 预定义编码保存的 stm 文件的格式定义

顺序号数据类型备注
1rowCountqintl6行数
2colCountqintl6列数
3“Depth”QString表头标题1
4"Measured Depth"QString表头标题2
5"Direction"QString表头标题3
6"Offset"QString表头标题4
7"Quality"QString表头标题5
8"Sampled"QString表头标题6
9第1行各列数据qint16测深
10qreal垂深
11qreal方位
12qreal位移
13QString固井质量
14bool是否测井取样
15第2行各列数据

使用QDataStream 读取二进制文件(.stm,.dat都是二进制文件),首先写的时候要根据各种数据类型进行写入,读出的时候要根据写入的时候的数据类型进行写出,写入的时候要注意,因为是根据二进制代码进行写入,一个出错,其余都会跟着出错。

使用QDataStream读写stm类型文件

使用QDataStream 写.stm文件 stm文件需要设置版本好号

#include <QFileDialog>
#include <QDataStream>
//theModel为QStandardItemModel
​
//使用QDataStream进行写文件 需要根据流的方式进行写入
void MainWindow::on_actSave_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "保存文件";
    QString filter = "Qt预编码文件(*.stm)";
    QString fileName = QFileDialog::getSaveFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //使用QFile IODevice对文件进行读取
    QFile file(fileName);
​
    //QIODevice::Truncate对文件进行覆盖
    if(file.open(QIODevice::WriteOnly | QIODevice::Truncate))
    {
        //使用QDataStream读取二进制文件
        QDataStream stream(&file);
​
       //设置QDataStream的版本号 不设置默认会给一个版本号
        stream.setVersion(QDataStream::Qt_5_0);
​
        //存入表格行数和列数
        qint16 rowCount = theModel->rowCount();
        qint16 colCount = theModel->columnCount();
        stream<<rowCount;
        stream<<colCount;
​
        //存入表头文字
        for(int i = 0; i < colCount; i++)
        {
            stream<<theModel->horizontalHeaderItem(i)->text();
        }
​
        //数据区域
        qint16 Depth;
        qreal MeasuredDepth, Direction, Offset;
        QString Quality;
        bool Sampled;
​
        //从表格中获取数据填入文件中
        for(int i = 0 ; i < rowCount; i++)
        {
            Depth = theModel->item(i , 0)->data(Qt::DisplayRole).toInt();
            stream<<Depth;
​
            MeasuredDepth = theModel->item(i , 1)->data(Qt::DisplayRole).toFloat();
            stream<<MeasuredDepth;
​
            Direction = theModel->item(i , 2)->data(Qt::DisplayRole).toFloat();
            stream<<Direction;
​
            Offset = theModel->item(i , 3)->data(Qt::DisplayRole).toFloat();
            stream<<Offset;
​
            Quality = theModel->item(i , 4)->data(Qt::DisplayRole).toString();
            stream<<Quality;
​
            //最后一项为勾选框
            Sampled = (theModel->item(i , 5)->checkState() == Qt::Checked);
            stream<<Sampled;
        }
        file.close();
    }
}

使用QDataSteam读取二进制文件,需要按照写入的格式进行读取 读取.stm文件

#include <QFileDialog>
#include <QDataStream>
//theModel为QStandardItemModel
​
//打开二进制文件使用QStandardItemModel和QItemSelectionModel加载到Tabbleview中
void MainWindow::on_actOpen_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "打开文件";
    QString filter = "Qt预编码文件(*.stm)";
    QString fileName = QFileDialog::getOpenFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //使用QFile IODevice对文件进行读取
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly))
    {
        //使用QDataStream读取二进制文件
        QDataStream stream(&file);
​
        //设置QDataStream的版本号 不设置默认会给一个版本号
         stream.setVersion(QDataStream::Qt_5_0);
        
        //数据区域
        qint16 rowCount, colCount;
        stream>>rowCount;
        stream>>colCount;
        resetTableRow(rowCount);
​
        //将不需要的数据输出给str
        QString str;
        for(int i = 0; i < colCount; i++)
        {
             stream>>str;
        }
​
        //数据区域
        qint16 Depth;
        qreal MeasuredDepth, Direction, Offset;
        QString Quality;
        bool Sampled;
​
        //根据index获取Item,使用item填充数据 一共有六行数据
        QStandardItem * item;
        QModelIndex index;
        for(int i = 0; i < rowCount; i++)
        {
            stream>>Depth;
            index = theModel->index(i, 0);
            item = theModel->itemFromIndex(index);
            item->setData(Depth, Qt::DisplayRole);
​
            stream>>MeasuredDepth;
            index = theModel->index(i, 1);
            item = theModel->itemFromIndex(index);
            item->setData(MeasuredDepth, Qt::DisplayRole);
​
            stream>>Direction;
            index = theModel->index(i, 2);
            item = theModel->itemFromIndex(index);
            item->setData(Direction, Qt::DisplayRole);
​
            stream>>Offset;
            index = theModel->index(i, 3);
            item = theModel->itemFromIndex(index);
            item->setData(Offset, Qt::DisplayRole);
​
            stream>>Quality;
            index = theModel->index(i, 4);
            item = theModel->itemFromIndex(index);
            item->setData(Quality, Qt::DisplayRole);
​
            stream>>Sampled;
            index = theModel->index(i, 5);
            item = theModel->itemFromIndex(index);
            //设置选中状态
            if(Sampled)
                item->setCheckState(Qt::Checked);
            else
                item->setCheckState(Qt::Unchecked);
        }
        file.close();
    }
}

使用QDataStream读写dat类型文件

写dat文件 dat为标准编码,可以不设置版本号 但是需要设置编码格式

void MainWindow::on_actSaveBin_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "保存文件";
    QString filter = "Qt预编码文件(*.dat)";
    QString fileName = QFileDialog::getSaveFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //使用QFile IODevice对文件进行读取
    QFile file(fileName);
​
    //QIODevice::Truncate对文件进行覆盖
    if(file.open(QIODevice::WriteOnly | QIODevice::Truncate))
    {
        //使用QDataStream读取二进制文件
        QDataStream stream(&file);
​
        //设置编码规则 分为两种
        stream.setByteOrder(QDataStream::LittleEndian);
​
        //存入表格行数和列数
        qint16 rowCount = theModel->rowCount();
        qint16 colCount = theModel->columnCount();
​
        //写的时候 整形浮点型使用writeRawData() 该方法是根据地址和大小写入
        stream.writeRawData((char *) &rowCount, sizeof(qint16));
        stream.writeRawData((char *) &colCount, sizeof(qint16));
​
​
        //存入表头文字 QString型的写入使用writeBytes()
        QByteArray btArray;
        for(int i = 0; i < colCount; i++)
        {
            QString str = theModel->horizontalHeaderItem(i)->text();
            btArray = str.toUtf8();
            stream.writeBytes(btArray, btArray.length());
        }
​
        //数据区域
        qint16 Depth;
        qreal MeasuredDepth, Direction, Offset;
        QString Quality;
        bool Sampled;
​
        //从表格中获取数据填入文件中
        for(int i = 0 ; i < rowCount; i++)
        {
            Depth = theModel->item(i , 0)->data(Qt::DisplayRole).toInt();
            stream.writeRawData((char *) &Depth, sizeof(qint16));
​
            MeasuredDepth = theModel->item(i , 1)->data(Qt::DisplayRole).toFloat();
            stream.writeRawData((char *) &MeasuredDepth, sizeof(qreal));
​
            Direction = theModel->item(i , 2)->data(Qt::DisplayRole).toFloat();
            stream.writeRawData((char *) &Direction, sizeof(qreal));
​
            Offset = theModel->item(i , 3)->data(Qt::DisplayRole).toFloat();
            stream.writeRawData((char *) &Offset, sizeof(qreal));
​
            Quality = theModel->item(i , 4)->data(Qt::DisplayRole).toString();
            btArray = Quality.toUtf8();
            stream.writeBytes(btArray, btArray.length());
​
            //最后一项为勾选框
            Sampled = (theModel->item(i , 5)->checkState() == Qt::Checked);
            qint8 yes = 1, no = 0;
            if(Sampled)
            {
                stream.writeRawData((char *) &yes, sizeof(qint8));
            }
            else
            {
                stream.writeRawData((char *) &no, sizeof(qint8));
            }
        }
    }
}

使用DataStream读取.dat文件

//打开.dat文件
void MainWindow::on_actOpenBin_triggered()
{
    //设置QFileDialog 属性 获得打开文件的文件路径
    QString curPath = QCoreApplication::applicationDirPath();
    QString dlgTitle = "打开文件";
    QString filter = "标准编码(*.dat)";
    QString fileName = QFileDialog::getOpenFileName(this, curPath, dlgTitle, filter);
    if(fileName.isEmpty())  return;
​
    //使用QFile IODevice对文件进行读取
    QFile file(fileName);
    if(file.open(QIODevice::ReadOnly))
    {
        //使用QDataStream读取二进制文件
        QDataStream stream(&file);
​
        //设置编码规则 分为两种
        stream.setByteOrder(QDataStream::LittleEndian);
​
        qint16 rowCount,colCount;
​
        //根据数据类型的大小进行读取数据 int类型使用readRawData进行读取
        stream.readRawData((char *) &rowCount, sizeof(qint16));
        stream.readRawData((char *) &colCount, sizeof(qint16));
​
        //初始化表格
        resetTableRow(rowCount);
​
        //使用readBytes读取QString数据
        char * buf;
        uint strlen;  //也就是 quint32
        for(int i = 0; i < colCount; i++)
        {
             stream.readBytes(buf, strlen);
​
             //根据buf获取相应的字符串数据 改例子不需要使用
             //QString str = QString::fromLocal8Bit(buf, strlen);
        }
​
        //数据区域
        qint16 Depth;
        qreal MeasuredDepth, Direction, Offset;
        QString Quality;
​
        //使用readRawData时不支持bool类型,因此使用qint8较小的一个类型
        qint8 Sampled;
​
        //根据index获取Item,使用item填充数据 一共有六行数据
        QStandardItem * item;
        QModelIndex index;
        for(int i = 0; i < rowCount; i++)
        {
            stream.readRawData((char *) &Depth, sizeof(qint16));
            index = theModel->index(i, 0);
            item = theModel->itemFromIndex(index);
            item->setData(Depth, Qt::DisplayRole);
​
            stream.readRawData((char *) &MeasuredDepth, sizeof(qreal));
            index = theModel->index(i, 1);
            item = theModel->itemFromIndex(index);
            item->setData(MeasuredDepth, Qt::DisplayRole);
​
            stream.readRawData((char *) &Direction, sizeof(qreal));
            index = theModel->index(i, 2);
            item = theModel->itemFromIndex(index);
            item->setData(Direction, Qt::DisplayRole);
​
            stream.readRawData((char *) &Offset, sizeof(qreal));
            index = theModel->index(i, 3);
            item = theModel->itemFromIndex(index);
            item->setData(Offset, Qt::DisplayRole);
​
            stream.readBytes(buf, strlen);
            QString Quality = QString::fromLocal8Bit(buf, strlen);
            index = theModel->index(i, 4);
            item = theModel->itemFromIndex(index);
            item->setData(Quality, Qt::DisplayRole);
​
            stream.readRawData((char *) &Offset, sizeof(qint8));
            index = theModel->index(i, 5);
            item = theModel->itemFromIndex(index);
            //设置选中状态
            if(Sampled == 1)
                item->setCheckState(Qt::Checked);
            else
                item->setCheckState(Qt::Unchecked);
        }
        file.close();
    }
}

文件目录操作

文件操作相关的类

QCoreApplication:用于提取应用程序路径、程序名等文件信息 QFile:除了打开文件操作外,还有复制文件、删除文件等功能 QFileInfo:用于提取文件信息,包括路径、文件名、后缀 QDir:用于提取目录或文件信息,获取一个目录下的文件或目录列表,创建或删除目录和文件,文件重名等操作 QTemporaryDir 和 QTemporaryFile:用于创建临时目录和临时文件。 QFileSystemWatcher:监听目录下文件的添加、删除等变化

通过object对象获取QPushbutton对象

//第一种写法
void MainWindow::on_pushButton_68_clicked()
{
    //通过sender()的object对象获取QPushbutton对象 即可通过指针btn对点击的按钮进行操作
    QPushButton * btn = static_cast<QPushButton *>(sender());
​
    //将QPushbutton的文本和提示内容添加到QPlainTextEdit中去
    ui->plainTextEdit_3->appendPlainText(btn->text());
    ui->plainTextEdit_3->appendPlainText(btn->toolTip());
}
​
void MainWindow::on_pushButton_68_clicked()
{
    GetBtnInfo(sender());
    
    //获取当前的目录添加到QPlainTextEdit中去
    ui->plainTextEdit_3->appendPlainText(QCoreApplication::applicationDirPath());
}
​
//第二种写法
//获取点击按钮的文本和提示信息
void MainWindow::GetBtnInfo(QObject * obj)
{
    QPushButton * btn = static_cast<QPushButton *>(obj);
​
    //将QPushbutton的文本和提示内容添加到QPlainTextEdit中去
    ui->plainTextEdit_3->appendPlainText(btn->text());
    ui->plainTextEdit_3->appendPlainText(btn->toolTip());
}
QCoreApplication常用方法
applicationFilePath() : QString
applicationName() : QString
​
QFile常用方法
qint64 QFile::size() const  //获取当前文件的大小。对于打开的文件,该方法返回文件中可以读取的字节数。
bool QIODevice::getChar(char *c)    //从文件中读取一个字符,并存储到 c 中。读取成功时,方法返回 true,否则返回 false。
bool QIODevice::putChar(char c)     //向文件中写入字符 c,成功时返回 true,否则返回 false。
QByteArray QIODevice::read(qint64 maxSize)  //从文件中一次性最多读取 maxSize 个字节,然后返回读取到的字节。
qint64 QIODevice::read(char *data, qint64 maxSize)  //从文件中一次性对多读取 maxSize 个字节,读取到的字节存储到data指针指定的内存控件中。该方法返回成功读取到的字节数。
QByteArray QIODevice::readAll()     //读取文件中所有的数据。
qint64 QIODevice::readLine(char *data, qint64 maxSize)  //每次从文件中读取一行数据或者读取最多 maxSize-1 个字节,存储到 data 中。该方法返回实际读取到的字节数。
qint64 QIODevice::write(const char *data, qint64 maxSize)   //向 data 数据一次性最多写入 maxSize 个字节,该方法返回实际写入的字节数。
qint64 QIODevice::write(const char *data)   //将 data 数据写入文件,该方法返回实际写入的字节数。
qint64 QIODevice::write(const QByteArray &byteArray)    //将 byteArray 数组中存储的字节写入文件,返回实际写入的字节数。
bool QFile::copy(const QString &newName)    //将当前文件的内容拷贝到名为 newName 的文件中,如果成功,方法返回 true,否则返回 false。copy 方法在执行复制操作之前,会关闭源文件。
bool QFile::rename(const QString &newName)  //对当前文件进行重命名,新名称为 newName,成功返回 true,失败返回 false。
bool QFile::remove()            //删除当前文件,成功返回 true,失败返回 false。
    
QFileInfo常用方法   
一般用法:
QFilelnfo filelnfo(path);
QFilelnfo filelnfo;filelnfo.setFile(path);
bool exists(); //判断文件是否存在,若存在返回true。
qint64 size();//获取文件大小,返回bytes。
QString path();//返回文件路径,不包含文件名。
QString filePath();//返回文件路径,包含文件名。
QString fileName();//返回文件名称。
bool isFile();//判断是否是文件。
bool isDir();//判断是否是路径。
bool isSymLink();//判断是否是符号链接
QDateTime created();//创建时间
QDateTime lastModified();//最近修改时间
QDateTime lastRead();//最近读时间
​
QDird的常用使用方法
mkdir();//创建一个目录;
rename();//对关联目录进行重命名;
rmdir();//移除一个目录;
exists();//检测目录是否存在;
refresh();//刷新目录内容。
​
QTemporaryDir方法
QString errorString() const
如果isValid()返回false,则此函数返回错误字符串,该错误字符串解释了为什么创建临时目录失败。否则,这个函数返回一个空字符串。
QString filePath(const QString &fileName) const
返回临时目录中文件的路径名称。不检查文件是否确实存在于目录中。冗余多重分隔符或“。” 和fileName中的“..”目录不会被删除。
bool isValid() const
判断生成的临时目录是否有效。
QString path() const
返回临时目录的路径。如果无法创建QTemporaryDir,则为空。
bool remove()
删除临时目录,包括其所有内容,并返回删除状态。
void setAutoRemove(bool b)
如果b为真,则将QTemporaryDir设置为自动删除模式。
​
QTemporaryFile方法
void QTemporaryFile::setFileTemplate(const QString&name)
将文件名称的静态部分设置为名称。如果文件模板包含将自动替换为文件名的唯一部分的XXXXXX,否则文件名将根据指定的静态部分自动确定。
如果name包含相对文件路径,则路径将相对于当前工作目录。如果你想使用系统的临时目录,你可以使用QDir :: tempPath()来构造名字。
bool open()
一个QTemporaryFile将永远被打开了QIODevice::ReadWrite 模式,这可以方便地访问文件中的数据。该函数在成功时将返回true,并将fileName()设置为使用的唯一文件名。
    
QFileSystemWatcher方法
 bool addPath(const QString & path)
如果路径存在,则添加至文件系统监控,如果路径不存在或者已经被监控了,那么不添加。如果路径是一个目录,内容被修改或删除时,会发射directoryChanged()信号;否则,当文件被修改、重命名或从磁盘上删除时,会发出fileChanged()信号。如果监控成功,返回true;否则,返回false.监控失败的原因通常依赖于系统,但也包括资源不存在、接入失败、或总的监控数量限制等原因。
QStringList addPaths(const QStringList & paths)
添加每一个路径至添加至文件系统监控,如果路径不存在或者已经被监控了,那么不添加。返回值是不能被监控的路径列表。
QStringList directories() const
返回一个被监控的目录路径列表。
QStringList files() const
返回一个被监控的文件路径列表。
bool removePath(const QString & path)
从文件系统监控中删除指定的路径。如果监控被成功移除,返回true。删除失败的原因通常是与系统相关,但可能是由于路径已经被删除。
QStringList removePaths(const QStringList & paths)
从文件系统监控中删除指定的路径。返回值是一个无法删除成功的路径列表。

QPainter基本绘制

Qt可以使用相同的 API 在屏幕和绘图设备上进行绘制,它主要基于QPainter、QPaintDevice 和 QPaintEngine 这三个类。 QPainter:用来进行绘图操作的类 QPaintDevice:抽象的二维界面,是中间媒介 QPaintEngine:提供了一些接口,可用于 QPainter 在不同的设备上进行绘制

QPainter 可以在继承自 QPaintDevice 类的任何对象上进行绘制操作

QPainter 一般在部件的绘图事件 paintEvent() 中进行绘制。当窗口程序需要升级或者重新绘制时,调用此成员函数。使用 repaint()和 update() 后,调用函数 paintEvent()。

QPainter的3个主要设置是: pen, brush, fontpainter.setPen(QPen(..));painter.setBruch(QBrush(..));painter.setFont(QFont(..));painter.setRenderHint(QPainter::Antialiasing);设置了bursh之后, 画的是效果即填充QPainter的属性影响绘制的图形 通常使用painter.drawXXX(..)来绘制图形

//设置派生类 Q_DECL_OVERRIDE表示父类一定要存在 否则会提示报错
void paintEvent(QPaintEvent * event) Q_DECL_OVERRIDE;
#include<QPainter>
void Widget::paintEvent(QPaintEvent * event)
{
    QPainter painter(this);
​
    //获取窗体的长和宽
    int w = this->width();
    int h = this->height();
​
    //设置点抗锯齿和文字抗锯齿
//    painter.setRenderHint(QPainter::Antialiasing);
//    painter.setRenderHint(QPainter::TextAntialiasing);
​
    QPen pen;
​
    //设置画笔的宽度
    pen.setWidth(20);
​
    //设置画笔的颜色
    pen.setColor(Qt::red);
​
    //设置线的类型 设置为圆和虚线形
    pen.setStyle(Qt::DashDotDotLine);
​
    //设置接口出处类型 设置为圆角类型
    pen.setJoinStyle(Qt::RoundJoin);
​
    //为画家设置画笔
    painter.setPen(pen);
​
    //设置填充颜色和类型
    QBrush brush;
    brush.setColor(Qt::yellow);
    brush.setStyle(Qt::Dense1Pattern);
    painter.setBrush(brush);
    
设置线性渐变
//    QLinearGradient  linearGrad(rect.left(),rect.top(),rect.right(),rect.bottom()); //对角线
//    QLinearGradient  linearGrad(rect.left(),rect.top(),rect.right(),rect.top());//从左到右
//    linearGrad.setColorAt(0,Qt::blue);//起点颜色
//    linearGrad.setColorAt(0.5,Qt::green);//起点颜色
//    linearGrad.setColorAt(1,Qt::red);//终点颜色
//    linearGrad.setSpread(QGradient::ReflectSpread);  //展布模式
QGradient::PadSpread ,QGradient::RepeatSpread, QGradient::ReflectSpread
//    painter.setBrush(linearGrad););
    
//    //画矩形
//    QRect rect(w/4, h/4, w/2, h/2);
//    painter.drawRect(rect);
    
//    //画图片和文字
//    QRect rect(w/4, h/4, w/2, h/2);
//    QImage image(":images/images/qt.jpg");
//    painter.drawImage(rect, image);
//    QFont font;
//    font.setPointSize(30);
//    painter.setFont(font);
//    painter.drawText(rect, "Hello Qt");
​
    //绘制多边形
    QPoint points[] = {QPoint(w/3, h/3), QPoint(w/2, h/2), QPoint(w/5, 2 * h/5)};
    painter.drawPolyline(points, 3);
}

坐标系统和坐标转换

对坐标进行平移和旋转,实际上是对原始坐标系统进行平移旋转,即改变了原点(0,0)位置和方向

分组函数原型功能
坐标变换void translate(qreal dx,qreal dy) void rotate(qreal angle) void scale(qreal sx,qreal sy) void shear(qrael sh,qreal sy)坐标系统一定的偏移量,坐标原点平移到新的点 坐标系统顺时针旋转一个角度 坐标系统缩放 坐标系统做扭转变换
状态保存与恢复void save() void restore() void resetTransform()保存painter当前的状态,就是将当前状态压入栈 恢复上一次状态,就是从堆栈中弹出上次的状态 复位所有的坐标变换
void Widget::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
​
    //设置画笔的样式 创建时一定要传入this对象
    QPainter painter(this);
    QPen pen;
    pen.setStyle(Qt::SolidLine);
    painter.setPen(pen);
​
    //设置抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
​
    //设置填充的样式和颜色
    QBrush brush;
    brush.setColor(Qt::yellow);
    brush.setStyle(Qt::SolidPattern);
    painter.setBrush(brush);
​
    //画五角星 设五角星的中心为中点 中点到顶点的距离为R
    qreal R = 100;
​
    //将每个角度的长度转换为弧度
    qreal deg = PI * (360 / 5) / 180;
    QPoint points[5] =
    {
        QPoint(R,0),
        QPoint(R*qCos(deg), -R*qSin(deg)),
        QPoint(R*qCos(2*deg), -R*qSin(2*deg)),
        QPoint(R*qCos(3*deg), -R*qSin(3*deg)),
        QPoint(R*qCos(4*deg), -R*qSin(4*deg))
    };
​
    //根据点的路径画线段
    QPainterPath starPath;
    starPath.moveTo(points[0]);
    starPath.lineTo(points[2]);
    starPath.lineTo(points[4]);
    starPath.lineTo(points[1]);
    starPath.lineTo(points[3]);
    starPath.closeSubpath(); //闭合路径,最后一个点与第一个点相连
​
    //设置字体
    QFont   font;
    font.setPointSize(12);
    font.setBold(true);
    painter.setFont(font);
​
    //在路径上添加文字
    starPath.addText(points[0],font,"0"); //显示端点编号
    starPath.addText(points[1],font,"1");
    starPath.addText(points[2],font,"2");
    starPath.addText(points[3],font,"3");
    starPath.addText(points[4],font,"4");
​
    //保存坐标状态
    painter.save();
​
    //移动原点坐标
    painter.translate(100, 120);
​
    //画线段
    painter.drawPath(starPath);
​
    //在中心画文字,因为进行了平移,所以中心点大概在平移后的0,0位置
    painter.drawText(0, 0, "s1");
​
    //恢复到保存时的坐标状态 画旋转后的五角星
    painter.restore();
    painter.translate(300, 120);
    painter.rotate(90);         //设置旋转角度
    painter.scale(0.7, 0.7);    //缩小
    painter.drawPath(starPath);
    painter.drawText(0, 0, "s2");
​
​
    //恢复到最初的状态
    painter.resetTransform();
    painter.translate(500, 120);
    painter.rotate(-90);         //设置旋转角度
    painter.scale(1.1, 0.7);    //长度扩大 宽度缩小
    painter.drawPath(starPath);
    painter.drawText(0, 0, "s2");
}

视口坐标和窗口坐标

视口: 绘图设备的任意一个矩形区域的物理坐标,可以只选取物理坐标的一个矩形区域用于绘图。视口默认情况下等于绘图设备的整个矩形区。 窗口: 对应于视口的矩形区域,只不过是用逻辑坐标定义的坐标系,窗口坐标的中心在矩形中心。

void Widget::paintEvent(QPaintEvent * event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    int w = this->width();
    int h = this->height();
​
    //设置抗锯齿
    painter.setRenderHint(QPainter::Antialiasing);
​
    //设置视口的大小 根据窗口的最小长度设置矩形框
    int side = qMin(w, h);
    QRect rect( (w - side) / 2, (h - side) / 2, side, side);
    painter.drawRect(rect);
​
    //设置视口坐标
    painter.setViewport(rect);
​
    //画椭圆 设置窗口坐标 左上角坐标为-100,100 中心点为0,0 长度为200,宽度为200
    painter.setWindow(-100, -100, 200, 200);
​
//    //相当于在0,0点画了一个矩形 再到矩形框内画椭圆
//    painter.drawEllipse(0, 0, 50, 50);
​
    //设置颜色渐变效果 前两个参数为渐变的起始点 后两个坐标为渐变的终止点
    QLinearGradient linearGrad(0, 0, 100, 0);
​
    //设置起始点颜色和终止点颜色 0为起点 1为终点
    linearGrad.setColorAt(0, Qt::yellow);
    linearGrad.setColorAt(1, Qt::green);
​
    //设置发散的形式 为按边界颜色发散
    linearGrad.setSpread(QGradient::PadSpread);
    painter.setBrush(linearGrad);
​
    //设置复合模式
    painter.setCompositionMode(QPainter::CompositionMode_Difference);
​
    //根据旋转画图案
    for (int i = 0; i < 36; i++)
    {
        //旋转
        painter.rotate(10);
​
        //设置椭圆的中心点 使用窗口坐标绘制 50相当于是半径
        painter.drawEllipse(QPoint(50,0), 50, 50);
    }
}

QtCharts

Qt Charts概述

Qt Charts基于Qt的Graphics View架构,其核心组件是QChartView和QChart • QChartView是显示图标的视图,基类为QGraphicsView • QChart的基类是QGraphicsItem

要在项目中使用 Qt Charts 模块,必须在项目的配置文件 . pro 文件中增加下面的一行语句 : QT += charts 在需要使用 QtCharts 的类的头文件或源程序文件中 , 要使用如下的包含语句 : #include <QtCharts> //using namespace QtCharts ; QT_CHARTS_USE_NAMESPACE //使用宏定义

//,pro中加charts
QT += charts
​
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QChartView>
#include <QLineSeries>
#include <QtMath>
#include <QValueAxis>
​
//加入宏定义 或者就要加入命名空间 using namespace QtCharts ;
QT_CHARTS_USE_NAMESPACE
​
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    QChartView * chartView = new QChartView(this);
    QChart * chart = new QChart;
    chart->setTitle("简单函数曲线");
​
    //给chartview设置chart并铺满整个窗体
    chartView->setChart(chart);
    this->setCentralWidget(chartView);
​
    //创建折线序列
    QLineSeries * series0 = new QLineSeries;
    QLineSeries * series1 = new QLineSeries;
    series0->setName("sin曲线");
    series1->setName("cos曲线");
​
    //为表格添加曲线
    chart->addSeries(series0);
    chart->addSeries(series1);
​
    //为序列添加数值
    qreal t=0,y1,y2,intv=0.1;
    int cnt=100;
    for(int i=0;i<cnt;i++)
    {
        y1=qSin(t);//+qrand();
        series0->append(t,y1);
        y2=qCos(t);
        series1->append(t,y2);
        t+=intv;
    }
​
    //创建坐标轴
    QValueAxis * axisX =new QValueAxis;
    QValueAxis * axisY = new QValueAxis;
​
    //设置x轴
    axisX->setRange(0, 10);
    chart->setAxisX(axisX, series0);
    chart->setAxisX(axisX, series1);
​
    //设置Y轴
    axisY->setRange(-1, 1);
    chart->setAxisY(axisY, series0);
    chart->setAxisY(axisY, series1);
}

Qtchart绘制折线图

对QChart的进行方法缩小

//chartview为QChartView控件 chart为Qhart控件 chartview->setchart(chart);
//缩小表格
void MainWindow::on_actZoomOut_triggered()
{
    ui->chartview->chart()->zoom(0.8);
}
//放大表格
void MainWindow::on_actZoomIn_triggered()
{
    ui->chartview->chart()->zoom(1.2);
}
//恢复原始大小
void MainWindow::on_actZoomReset_triggered()
{
    ui->chartview->chart()->zoomReset();
}

创建图表

//头文件
#include <QtCharts>
#include <QValueAxis>
QT_CHARTS_USE_NAMESPACE
private:
    Ui::MainWindow *ui;
    QLineSeries * curSeries;
    QValueAxis * curAxis;
​
//创建图表
void MainWindow::createChart()
{
    QChart * chart = new QChart();
    chart->setTitle("简单的曲线");
    ui->chartview->setChart(chart);
​
    //设置抗锯齿模式
    ui->chartview->setRenderHint(QPainter::Antialiasing);
​
    QLineSeries * series0 = new QLineSeries;
    QLineSeries * series1 = new QLineSeries;
    series0->setName("sin曲线");
    series1->setName("cos曲线");
    curSeries = series0;
​
    //设置笔的样式
    QPen pen;
    pen.setStyle(Qt::DotLine);
    pen.setWidth(2);
    pen.setColor(Qt::red);
    series0->setPen(pen);
    pen.setStyle(Qt::SolidLine);
    pen.setColor(Qt::blue);
    series1->setPen(pen);
​
    //为Chart添加序列
    chart->addSeries(series0);
    chart->addSeries(series1);
​
    //设置坐标轴
    QValueAxis * axisX = new QValueAxis;
    QValueAxis * axisY = new QValueAxis;
    curAxis = axisX;
​
    //设置坐标轴属性
    axisX->setRange(0, 10);
    axisX->setTitleText("time(secs)");
​
    //设置坐标轴为一位小数
    axisX->setLabelFormat("%.1f");
​
    //设置中间格子一共多少条线
    axisX->setTickCount(11);
​
    //设置小分格
    axisX->setMinorTickCount(4);
​
    axisY->setRange(-1.5, 1.5);
    axisY->setTickCount(3);
    axisY->setMinorTickCount(4);
    axisY->setTitleText("value");
​
    //为chart设置坐标轴
    chart->setAxisX(axisX, series0);
    chart->setAxisX(axisX, series1);
    chart->setAxisY(axisY, series0);
    chart->setAxisY(axisY, series1);
}

为图标添加数据

//更新数据
void MainWindow::prepareData()
{
    //获取chart表格的序列
    QLineSeries * series0 = (QLineSeries *)ui->chartview->chart()->series().at(0);
    QLineSeries * series1 = (QLineSeries *)ui->chartview->chart()->series().at(1);
​
    //为序列添加数据
    series0->clear();
    series1->clear();
    int cnt = 100;
    srand(QTime::currentTime().second());
    qreal t = 0, y1, y2, intv = 0.1;
    qreal rd;
    for (int i = 0; i < cnt; i++)
    {
        rd=(qrand() % 10)-5; //随机数,-5~+5
        y1=qSin(t)+rd/50;
        *series0<<QPointF(t,y1);  //序列添加数据点
//        series0->append(t,y1);  //序列添加数据点
​
        rd=(qrand() % 10)-5; //随机数,-5~+5
        y2=qCos(t)+rd/50;
//        series1->append(t,y2); //序列添加数据点
        *series1<<QPointF(t,y2); //序列添加数据点
        t+=intv;
    }
}

设置图表和图例

//设置图表的标题
void MainWindow::on_btnSetTitle_clicked()
{
    QChart * chart = ui->chartview->chart();
    chart->setTitle(ui->editTitle->text());
}
​
//设置图表标题字体
void MainWindow::on_btnSetTitleFont_clicked()
{
    QFont font = ui->chartview->chart()->titleFont();
    bool ok =false;
    font = QFontDialog::getFont(&ok, font);
    if(ok)
    {
        ui->chartview->chart()->setTitleFont(font);
    }
}
​
//设置图例的位置  图例为显示曲线名字的一小块区域
void MainWindow::on_radioButton_clicked()
{
    ui->chartview->chart()->legend()->setAlignment(Qt::AlignTop);
}
void MainWindow::on_radioButton_2_clicked()
{
    ui->chartview->chart()->legend()->setAlignment(Qt::AlignBottom);
}
void MainWindow::on_radioButton_3_clicked()
{
    ui->chartview->chart()->legend()->setAlignment(Qt::AlignLeft);
}
void MainWindow::on_radioButton_4_clicked()
{
    ui->chartview->chart()->legend()->setAlignment(Qt::AlignRight);
}
​
//设置图例是否可见
void MainWindow::on_chkLegendVisible_clicked(bool checked)
{
    ui->chartview->chart()->legend()->setVisible(checked);
}
//设置图例背景是否可见
void MainWindow::on_chkBoxLegendBackground_clicked(bool checked)
{
    ui->chartview->chart()->legend()->setBackgroundVisible(checked);
}
​
//设置图例的字体
void MainWindow::on_btnLegendFont_clicked()
{
    QFont font = ui->chartview->chart()->legend()->font();
    bool ok =false;
    font = QFontDialog::getFont(&ok, font);
    if(ok)
    {
        ui->chartview->chart()->legend()->setFont(font);
    }
}
​
//设置图例标签颜色
void MainWindow::on_btnLegendlabelColor_clicked()
{
    QColor color = ui->chartview->chart()->legend()->labelColor();
    color = QColorDialog::getColor(color);
    if(color.isValid())
    {
         ui->chartview->chart()->legend()->setLabelColor(color);
    }
}
​
//设置图表的边距 spinMarginBottom,spinMarginTop为QSpinBox用于控制边距的距离
void MainWindow::on_btnSetMargin_clicked()
{
    QMargins mgs;
    mgs.setBottom(ui->spinMarginBottom->value());
    mgs.setTop(ui->spinMarginTop->value());
    mgs.setLeft(ui->spinMarginLeft->value());
    mgs.setRight(ui->spinMarginRight->value());
    ui->chartview->chart()->setMargins(mgs);
}
​
//设置图表的动画效果 具体可以进入Qt函数进行了解 通过枚举进行设置
void MainWindow::on_cBoxAnimation_currentIndexChanged(int index)
{
    ui->chartview->chart()->setAnimationOptions((QChart::AnimationOption) index);
}
​
//设置图表的主题
void MainWindow::on_cBoxTheme_currentIndexChanged(int index)
{
    ui->chartview->chart()->setTheme(QChart::ChartTheme(index));
}

QDialgoPen获取画笔

//头文件
#include <QDialog>
#include <QPen>
public:
    explicit DialogPen(QWidget *parent = nullptr);
    ~DialogPen();
​
    //使用静态函数获取画笔
    static QPen getPen(QPen pen,bool & ok);
    void    setPen(QPen pen); //设置QPen,用于对话框的界面显示
    QPen    getPen(); //获取对话框设置的QPen的属性
​
private:
    QPen m_pen;
​
//cpp
#include "dialogpen.h"
#include "ui_dialogpen.h"
#include <QColorDialog>
​
DialogPen::DialogPen(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogPen)
{
    ui->setupUi(this);
​
    //“线型”ComboBox的选择项设置
    ui->comboPenStyle->clear();
    ui->comboPenStyle->addItem("NoPen",0);
    ui->comboPenStyle->addItem("SolidLine",1);
    ui->comboPenStyle->addItem("DashLine",2);
    ui->comboPenStyle->addItem("DotLine",3);
    ui->comboPenStyle->addItem("DashDotLine",4);
    ui->comboPenStyle->addItem("DashDotDotLine",5);
    ui->comboPenStyle->addItem("CustomDashLine",6);
​
    ui->comboPenStyle->setCurrentIndex(1);
}
​
DialogPen::~DialogPen()
{
    delete ui;
}
​
//使用静态函数获取画笔
QPen DialogPen::getPen(QPen inipen, bool &ok)
{
    QPen pen;
    DialogPen * dlg = new DialogPen;
    dlg->setPen(inipen);
    int ret = dlg->exec();
    if(ret == QDialog::Accepted)
    {
        pen = dlg->getPen();
        ok = true;
    }
    else
    {
        pen = inipen;
        ok = false;
    }
​
    delete  dlg;
    return  pen;
}
​
void DialogPen::setPen(QPen pen)
{ //设置QPen,并刷新显示界面
    m_pen=pen;
​
    ui->spinWidth->setValue(pen.width()); //线宽
    int i=static_cast<int>(pen.style());  //枚举类型转换为整型
    ui->comboPenStyle->setCurrentIndex(i);
​
    QColor  color=pen.color();
    ui->btnColor->setAutoFillBackground(true); //设置颜色按钮的背景色
    QString str=QString::asprintf("background-color: rgb(%d, %d, %d);",
                                  color.red(),color.green(),color.blue());
    ui->btnColor->setStyleSheet(str);
}
​
QPen DialogPen::getPen()
{//获得设置的属性
    m_pen.setStyle(Qt::PenStyle(ui->comboPenStyle->currentIndex())); //线型
    m_pen.setWidth(ui->spinWidth->value()); //线宽
​
    QColor  color;
    color=ui->btnColor->palette().color(QPalette::Button);
    m_pen.setColor(color); //颜色
    return  m_pen;
}
​
//选择颜色
void DialogPen::on_btnColor_clicked()
{
    QColor color = m_pen.color();
    color = QColorDialog::getColor(color);
​
    if(color.isValid())
    {
        QString str = QString::asprintf("background-color: rgb(%d, %d, %d);", color.red(), color.green(), color.blue());
        ui->btnColor->setStyleSheet(str);
    }
}

设置曲线和坐标点

//根据RadioButton判断选中的是哪个曲线
void MainWindow::on_radioSeries0_clicked()
{
    if(ui->radioSeries0->isChecked())
    {
        curSeries = (QLineSeries *)ui->chartview->chart()->series().at(0);
    }
    else
    {
        curSeries = (QLineSeries *)ui->chartview->chart()->series().at(1);
    }
​
    //获取curSeries的值,更新界面
    ui->editSeriesName->setText(curSeries->name());
    ui->chkSeriesVisible->setChecked(curSeries->isVisible());
    ui->chkPointVisible->setChecked(curSeries->pointsVisible());
    ui->sliderSeriesOpacity->setValue(curSeries->opacity() * 10);
    ui->chkPointLabelVisible->setChecked(curSeries->pointLabelsVisible());
}
void MainWindow::on_radioSeries1_clicked()
{
    on_radioSeries0_clicked();
}
​
//设置曲线的名字
void MainWindow::on_btnSeriesName_clicked()
{
    curSeries->setName(ui->editSeriesName->text());
}
​
//设置系列是否可见
void MainWindow::on_chkSeriesVisible_clicked(bool checked)
{
    curSeries->setVisible(ui->chkSeriesVisible->isChecked());
}
​
//设置数据点是否可见
void MainWindow::on_chkPointVisible_clicked(bool checked)
{
    curSeries->setPointsVisible(ui->chkPointVisible->isChecked());
}
​
//设置曲线颜色
void MainWindow::on_btnSeriesColor_clicked()
{
    QColor color = curSeries->color();
    color = QColorDialog::getColor(color);
    if(color.isValid())
    {
        curSeries->setColor(color);
    }
}
​
//设置曲线的pen
void MainWindow::on_btnSeriesPen_clicked()
{
    bool ok = false;
    QPen pen = curSeries->pen();
    pen = DialogPen::getPen(pen, ok);
    if(ok)
    {
        curSeries->setPen(pen);
    }
}
​
//改变曲线的透明度
void MainWindow::on_sliderSeriesOpacity_valueChanged(int value)
{
    curSeries->setOpacity(value / 10.0);
}
​
//设置数据点标签是否可见 数据点标签是在曲线周围显示曲线的x,y的标签
void MainWindow::on_chkPointLabelVisible_clicked(bool checked)
{
    curSeries->setPointLabelsVisible(checked);
}
​
//设置数据点标签的颜色
void MainWindow::on_btnSeriesLabColor_clicked()
{
    QColor color = curSeries->pointLabelsColor();
    color = QColorDialog::getColor(color);
    if(color.isValid())
    {
        curSeries->setPointLabelsColor(color);
    }
}
​
//设置数据点标签字体
void MainWindow::on_btnSeriesLabFont_clicked()
{
    QFont font = curSeries->pointLabelsFont();
    bool ok = false;
    font = QFontDialog::getFont(&ok, font);
    if(ok)
    {
        curSeries->setPointLabelsFont(font);
    }
}
​
//根据RadioButton选择的是哪个设置数据点标签样式 显示y的值 显示x和y的值
//"@xPoint, @yPoint" 10,20 无括号 "(@xPoint, @yPoint)" (10, 20)有括号
void MainWindow::on_radioSeriesLabFormat0_clicked()
{
    if(ui->radioSeriesLabFormat0->isChecked())
    {
        curSeries->setPointLabelsFormat("@yPoint");
    }
    else
    {
        curSeries->setPointLabelsFormat("(@xPoint, @yPoint)");
    }
}
void MainWindow::on_radioSeriesLabFormat1_clicked()
{
    on_radioSeriesLabFormat0_clicked();
}

设置坐标轴

坐标轴分为x轴和y轴,根据QValueAxis获取x轴或y轴。

坐标轴有两种网格线,一种是大格子,一种是小格子,小格子为大格子再切分,setTickCount设置大格子条数,setMinorTickCount设置小格子条数。具体案例参考samp9_2

QValueAxis * curAxis;
//根据RadioButton选择的是x轴还是y轴进行设置
void MainWindow::on_radioX_clicked()
{
    //获取当前坐标轴
    // 在Qt 5.12.1中编译时提示 QChart::axisX()和QChart::axisY()函数过时,应使用 QChart::axes()函数
    //    if (ui->radioX->isChecked())
    //        curAxis=(QValueAxis*)ui->chartView->chart()->axisX();
    //    else
    //        curAxis=(QValueAxis*)ui->chartView->chart()->axisY();
​
    //  下面是针对Qt 5.12.1修改的代码,在Qt5.9.1里编译也没问题
    QList<QAbstractAxis*> axes;
    if (ui->radioX->isChecked())
        axes=ui->chartview->chart()->axes(Qt::Horizontal);
    else
        axes=ui->chartview->chart()->axes(Qt::Vertical);
    curAxis=(QValueAxis*)axes[0];
​
​
    //获取坐标轴的各种属性,显示到界面上
    ui->spinAxisMin->setValue(curAxis->min());
    ui->spinAxisMax->setValue(curAxis->max());
​
    ui->editAxisTitle->setText(curAxis->titleText());
    ui->chkBoxAxisTitle->setChecked(curAxis->isTitleVisible());
​
    ui->editAxisLabelFormat->setText(curAxis->labelFormat());
    ui->chkBoxLabelsVisible->setChecked(curAxis->labelsVisible());
​
    ui->chkGridLineVisible->setChecked(curAxis->isGridLineVisible());
    ui->chkAxisLineVisible->setChecked(curAxis->isLineVisible());
​
    ui->spinTickCount->setValue(curAxis->tickCount());
    ui->chkAxisLineVisible->setChecked(curAxis->isLineVisible());
​
    ui->spinMinorTickCount->setValue(curAxis->minorTickCount());
    ui->chkMinorTickVisible->setChecked(curAxis->isMinorGridLineVisible());
}
void MainWindow::on_radioY_clicked()
{
    on_radioX_clicked();
}
​
//设置坐标轴是否可见
void MainWindow::on_chkBoxVisible_clicked(bool checked)
{
    curAxis->setVisible(checked);
}
​
//设置坐标轴的范围
void MainWindow::on_btnSetAxisRange_clicked()
{
    curAxis->setRange(ui->spinAxisMin->value(), ui->spinAxisMax->value());
}
​
//设置坐标轴的标题
void MainWindow::on_btnAxisSetTitle_clicked()
{
    curAxis->setTitleText(ui->editAxisTitle->text());
}
​
//设置坐标轴标题是否可见
void MainWindow::on_chkBoxAxisTitle_clicked(bool checked)
{
    curAxis->setTitleVisible(checked);
}
​
//设置轴刻度标签格式
void MainWindow::on_pushButton_clicked()
{
    curAxis->setLabelFormat(ui->editAxisLabelFormat->text());
}
​
//设置轴刻度标签文字的颜色
void MainWindow::on_btnAxisLabelColor_clicked()
{
    QColor color= curAxis->labelsColor();
    color = QColorDialog::getColor(color);
    if (color.isValid())
       curAxis->setLabelsColor(color);
}
​
//设置轴刻度标签文字的字体
void MainWindow::on_btnAxisLabelFont_clicked()
{
    QFont font=curAxis->labelsFont();
    bool ok=false;
    font=QFontDialog::getFont(&ok,font);
    if (ok)
       curAxis->setLabelsFont(font);
}
​
//设置轴刻度标签是否可见
void MainWindow::on_chkBoxLabelsVisible_clicked(bool checked)
{
    curAxis->setLabelsVisible(checked);
}
​
//设置坐标轴网格线的颜色
void MainWindow::on_btnGridLineColor_clicked()
{
    QColor color = curAxis->gridLineColor();
    color = QColorDialog::getColor(color);
    if (color.isValid())
       curAxis->setGridLineColor(color);
}
​
//设置坐标轴网格线的pen
void MainWindow::on_pushButton_10_clicked()
{
    QPen pen;
    pen = curAxis->gridLinePen();
    bool ok=false;
    pen = DialogPen::getPen(pen,ok);
    if (ok)
      curAxis->setGridLinePen(pen);
}
​
//设置坐标轴大格子竖线的数量
void MainWindow::on_spinTickCount_valueChanged(int arg1)
{
    curAxis->setTickCount(arg1);
}
​
//设置坐标轴小格子竖线的数量
void MainWindow::on_spinMinorTickCount_valueChanged(int arg1)
{
    curAxis->setMinorTickCount(arg1);
}
​
//设置坐标轴线是否可见
void MainWindow::on_chkAxisLineVisible_clicked(bool checked)
{
    curAxis->setLineVisible(checked);
}
​
//设置坐标轴线的pen
void MainWindow::on_btnAxisLinePen_clicked()
{
    QPen pen;
    pen = curAxis->linePen();
    bool ok = false;
    pen = DialogPen::getPen(pen, ok);
    if (ok)
      curAxis->setLinePen(pen);
}
​
//设置坐标轴线的颜色
void MainWindow::on_btnAxisLinePenColor_clicked()
{
    QColor color = curAxis->linePenColor();
    color = QColorDialog::getColor(color);
    if(color.isValid())
        curAxis->setLinePenColor(color);
}
​
//设置坐标轴小格子线是否可见
void MainWindow::on_chkMinorTickVisible_clicked(bool checked)
{
    curAxis->setMinorGridLineVisible(checked);
}
​
//设置坐标轴小格子线的颜色
void MainWindow::on_btnMinorColor_clicked()
{
    QColor color = curAxis->minorGridLineColor();
    color = QColorDialog::getColor(color);
    if(color.isValid())
        curAxis->setMinorGridLineColor(color);
}
​
//设置坐标轴小格子线的pen
void MainWindow::on_btnMinorPen_clicked()
{
    QPen pen;
    pen = curAxis->minorGridLinePen();
    bool ok = false;
    pen = DialogPen::getPen(pen, ok);
    if (ok)
      curAxis->setMinorGridLinePen(pen);
}
​

常见图表的绘制

QBarChart

QBarChart为柱状图,可以显示多个柱状图,通过QBarSet设置数据,QBarSeries添加QBarSet数据集

通过QStandardItemModel设置数据

//头文件
#include    <QStandardItemModel>
#include    <QItemSelectionModel>
​
#include    <QtCharts>  //必须这么设置
QT_CHARTS_USE_NAMESPACE
​
#define     fixedColumnCount   5    //数据模型的列数
#define     iniDataRowCount    6   //学生个数
​
#define     colNoName       0   //姓名的列编号
#define     colNoMath       1   //数学的列编号
#define     colNoChinese    2   //语文的列编号
#define     colNoEnglish    3   //英语的列编号
#define     colNoAverage    4   //平均分的列编号
    
QStandardItemModel  *theModel;//数据模型
​
void    iniData();//初始化数据
void    surveyData();//统计数据
​
void    iniBarChart(); //柱状图初始化
void    buildBarChart();//构建柱状图
​
//cpp
//初始化数据
void MainWindow::iniData()
{
    //为model设置表头
    QStringList headerList;
    headerList<<"姓名"<<"数学"<<"语文"<<"英语"<<"平均分";
    theModel->setHorizontalHeaderLabels(headerList);
​
    //为model添加数据
    for (int i = 0; i < theModel->rowCount(); i++)
    {
        QString stuName = QString::asprintf("学生%2d", i + 1);
        QStandardItem * aItem = new QStandardItem(stuName);
        aItem->setTextAlignment(Qt::AlignHCenter);
        theModel->setItem(i, colNoName, aItem);
        qreal avgScore = 0;
        for (int j = colNoMath; j <= colNoEnglish; j++)
        {
            qreal score = 50 + qrand() % 50;//随机生成一个50-99的数
            aItem = new QStandardItem(QString::asprintf("%.0f", score));
            aItem->setTextAlignment(Qt::AlignHCenter);
            theModel->setItem(i, j, aItem);
            avgScore += score;
        }
​
        //求取平均分进行填充
        aItem = new QStandardItem(QString::asprintf("%.1f", avgScore/3));
        aItem->setTextAlignment(Qt::AlignHCenter);
​
        //设置平均分数据不可修改
        aItem->setFlags(aItem->flags() & !Qt::ItemIsEditable);
        theModel->setItem(i, colNoAverage, aItem);
    }
}
​
//统计数据
void MainWindow::surveyData()
{
    for (int i = colNoMath; i <= colNoAverage; i++)
    {
        qreal minVal = 100, maxVal = 0, val, sum = 0;
        int cnt50 = 0, cnt60 =0, cnt70 = 0, cnt80 = 0, cnt90 = 0;
        for (int j = 0; j < theModel->rowCount(); j++)
        {
            val = theModel->item(j, i)->text().toDouble();
            if(val > maxVal) maxVal = val;
            if(val < minVal) minVal = val;
​
            if(val < 60) cnt50++;
            else if(val < 70) cnt60++;
            else if(val < 80) cnt70++;
            else if(val < 90) cnt80++;
            else cnt90++;
            sum += val;
        }
​
        //选择设计的Qtree只有父节点 所以都是topLevelItem
        QTreeWidgetItem * aItem = ui->treeWidget->topLevelItem(0);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(cnt50));
​
        aItem = ui->treeWidget->topLevelItem(1);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(cnt60));
​
        aItem = ui->treeWidget->topLevelItem(2);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(cnt70));
​
        aItem = ui->treeWidget->topLevelItem(3);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(cnt80));
​
        aItem = ui->treeWidget->topLevelItem(4);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(cnt90));
​
        aItem = ui->treeWidget->topLevelItem(5);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(sum / iniDataRowCount));
​
        aItem = ui->treeWidget->topLevelItem(6);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(maxVal));
​
        aItem = ui->treeWidget->topLevelItem(7);
        aItem->setTextAlignment(i, Qt::AlignHCenter);
        aItem->setText(i, QString::number(minVal));
    }
}
​
//初始化数据
void MainWindow::on_actGenData_triggered()
{
    iniData();
}
​
//统计数据
void MainWindow::on_actTongJi_triggered()
{
    surveyData();
}

绘制柱状图(BarChart)

//初始化柱状图 chartViewBar为QChartView控件
void MainWindow::iniBarChart()
{
    QChart * chart = new QChart;
    chart->setTitle("Barchart演示");
​
    //设置动画效果
    chart->setAnimationOptions(QChart::SeriesAnimations);
    ui->chartViewBar->setChart(chart);
​
    //设置抗锯齿模式
    ui->chartViewBar->setRenderHint(QPainter::Antialiasing);
}
​
//构建柱状图
void MainWindow::buildBarChart()
{
    QChart * chart = ui->chartViewBar->chart();
​
    //先清除chart,因为经常要刷新,可能会形成多个坐标轴
    chart->removeAllSeries();
    if(chart->axisX() != NULL)
    {
        chart->removeAxis(chart->axisX());
        chart->removeAxis(chart->axisY());
    }
​
    //数据集 QBarSet用于显示柱状图即三门课的成绩 QLineSeries用于显示折线图即平均分
    QBarSet * setMath = new QBarSet(theModel->horizontalHeaderItem(colNoMath)->text());
    QBarSet * setChinese = new QBarSet(theModel->horizontalHeaderItem(colNoChinese)->text());
    QBarSet * setEnglish = new QBarSet(theModel->horizontalHeaderItem(colNoEnglish)->text());
    QLineSeries * Line = new QLineSeries;
​
    //为QLineSeries设置pen
    QPen pen;
    pen.setColor(Qt::red);
    pen.setWidth(2);
    Line->setPen(pen);
    Line->setName(theModel->horizontalHeaderItem(colNoAverage)->text());
​
    //从model从取到数据,为序列添加数据
    for (int i = 0; i < theModel->rowCount(); i++)
    {
        setMath->append(theModel->item(i, colNoMath)->text().toInt());
        setChinese->append(theModel->item(i, colNoChinese)->text().toInt());
        setEnglish->append(theModel->item(i, colNoEnglish)->text().toInt());
        Line->append(QPointF(i, theModel->item(i, colNoMath)->text().toFloat()));
    }
​
    //序列
    QBarSeries * seriers = new QBarSeries;
    seriers->append(setMath);
    seriers->append(setChinese);
    seriers->append(setEnglish);
​
    //为chartview添加序列
    chart->addSeries(seriers);
    chart->addSeries(Line);
​
    //设置坐标轴 QBarCategoryAxis为x轴 QValueAxis为Y轴
    QStringList categories;
    for(int i = 0; i < theModel->rowCount(); i++)
    {
        categories<< theModel->item(i, colNoName)->text();
    }
​
    QBarCategoryAxis * axisX = new QBarCategoryAxis;
    axisX->setCategories(categories);
    chart->setAxisX(axisX, seriers);
    chart->setAxisX(axisX, Line);
​
    QValueAxis * axisY = new QValueAxis;
    axisY->setRange(0, 100);
    axisY->setTitleText("分数");
    chart->setAxisY(axisY, seriers);
    chart->setAxisY(axisY, Line);
​
    //设置标签位于表格下面
    chart->legend()->setAlignment(Qt::AlignBottom);
}

绘制饼状图(QPieChart)

饼状图主要通过QPieSeries来设置数据,chart添加QPieSeries,为饼状图添加饼状块通过QPieSeries的a QPieSlice *QPieSeries::append(QString label, qreal value) 函数, 绘制饼状图时,需要绘制的对象都是一个系列series,使用apppend函数添加,第一个参数是series的名称,第二个参数是这个系列所占的比例大小float类型

//构建饼图
void MainWindow::buildPieChart()
{
    QChart * chart = ui->chartViewPie->chart();
​
    //先清除chart,因为经常要刷新,可能会形成多个坐标轴
    chart->removeAllSeries();
    if(chart->axisX() != NULL)
    {
        chart->removeAxis(chart->axisX());
        chart->removeAxis(chart->axisY());
    }
​
    //为QpieChart准备数据
    QPieSeries * seriers = new QPieSeries;
​
    //设置饼状图中间空白圆圈的大小
    seriers->setHoleSize(ui->spinHoleSize->value());
​
    //设置饼状图的大小
    seriers->setPieSize(ui->spinPieSize->value());
​
    //获取CheckBOX选中的科目
    int colNo = ui->cBoxCourse->currentIndex() + 1;
    for(int i = 0; i < 5; i++)
    {
        QTreeWidgetItem * item = ui->treeWidget->topLevelItem(i);
​
        //绘制饼状图时,需要绘制的对象都是一个系列series,使用apppend函数添加,
        //第一个参数是series的名称,第二个参数是这个系列所占的比例大小float类型
        //QPieSeries的append函数相当于就是添加了QPieSlice饼状块
        seriers->append( item->text(0), item->text(colNo).toFloat() );
    }
​
    //设置饼状块
    QPieSlice * slice;
    for (int i =0; i < 5; i++)
    {
        //获取分块
        slice =seriers->slices().at(i);
​
        //设置分块的标签
        slice->setLabel(slice->label()+QString::asprintf(": %.0f人, %.1f%%",
                        slice->value(),slice->percentage()*100));
​
        //当鼠标略过的时候,显示突出
        connect(slice, SIGNAL(hovered(bool)), this, SLOT(on_PieSliceHighlight(bool )));
    }
​
    //最后一个设置为exploded
    slice->setExploded(true);
​
    //只影响当前的slices,必须添加完slice之后再设置
    seriers->setLabelsVisible(true);
​
    //设置标题为当前展示的科目
    chart->setTitle("PieChart-------" + ui->cBoxCourse->currentText());
​
    //为饼状图添加序列
    chart->addSeries(seriers);
​
    //将标签放在饼状图右边
    chart->legend()->setAlignment(Qt::AlignRight);
}
​
void MainWindow::on_btnDrawPieChart_clicked()
{
    iniPiewChart();
    buildPieChart();
}
​
//当鼠标掠过饼块时突出显示
void MainWindow::on_PieSliceHighlight(bool show)
{
    //获取掠过的饼块
    QPieSlice * slice = (QPieSlice*)sender();
​
    //设置是否突出显示
    slice->setExploded(show);
}
​
//根据槽函数设置饼状图内部圆圈大小
void MainWindow::on_spinHoleSize_valueChanged(double arg1)
{
    QPieSeries * series;
    series = (QPieSeries *)ui->chartViewPie->chart()->series().at(0);
    series->setHoleSize(arg1);
}
​
//根据槽函数设置饼状图圆圈大小
void MainWindow::on_spinPieSize_valueChanged(double arg1)
{
    QPieSeries * series;
    series = (QPieSeries *)ui->chartViewPie->chart()->series().at(0);
    series->setPieSize(arg1);
}
​
//根据枚举量设置主题
void MainWindow::on_cBoxTheme_currentIndexChanged(int index)
{
    ui->chartViewPie->chart()->setTheme(QChart::ChartTheme(index));
}

绘制堆积图(QStackedBar)

堆积图是指一个柱状图里面包括多份数据,可以用来设置一个学生的总分,根据堆积图可以清晰地看出每个学生的每门科目的分数及总分。

//堆积图初始化
void MainWindow::iniStackedBar()
{
    QChart * chart = new QChart;
    chart->setTitle("Stackedchart演示");
​
    //设置动画效果
    chart->setAnimationOptions(QChart::SeriesAnimations);
    ui->chartViewStackedBar->setChart(chart);
​
    //设置抗锯齿模式
    ui->chartViewStackedBar->setRenderHint(QPainter::Antialiasing);
}
​
//构建堆积图
void MainWindow::buildStackedBar()
{
    QChart * chart = ui->chartViewStackedBar->chart();
​
    //先清除chart,因为经常要刷新,可能会形成多个坐标轴
    chart->removeAllSeries();
    if(chart->axisX() != NULL)
    {
        chart->removeAxis(chart->axisX());
        chart->removeAxis(chart->axisY());
    }
​
    //数据集 QBarSet用于显示柱状图即三门课的成绩
    QBarSet * setMath = new QBarSet(theModel->horizontalHeaderItem(colNoMath)->text());
    QBarSet * setChinese = new QBarSet(theModel->horizontalHeaderItem(colNoChinese)->text());
    QBarSet * setEnglish = new QBarSet(theModel->horizontalHeaderItem(colNoEnglish)->text());
​
    //为堆积图添加数据集
    QStringList categories;
    for(int i = 0; i < theModel->rowCount(); i++)
    {
        categories << theModel->item(i, colNoName)->text();
        setMath->append(theModel->item(i, colNoMath)->text().toFloat());
        setChinese->append(theModel->item(i, colNoChinese)->text().toFloat());
        setEnglish->append(theModel->item(i, colNoEnglish)->text().toFloat());
    }
​
    QStackedBarSeries * series = new QStackedBarSeries;
    series->append(setMath);
    series->append(setChinese);
    series->append(setEnglish);
​
    //添加坐标轴
    QBarCategoryAxis * axisX = new QBarCategoryAxis;
    axisX->append(categories);
    chart->setAxisX(axisX, series);
​
    QValueAxis *axisY = new QValueAxis;
    axisY->setRange(0, 300);
    axisY->setTitleText("总分");
    chart->setAxisY(axisY);
​
​
    //为表格添加序列化
    chart->addSeries(series);
}

绘制百分比堆积图(QPercentBar)

QPercentBar类似于QStackedBar,但是QPercentBar显示的是各个部分占总部分的百分比。

//初始化
void MainWindow::iniPercentBar()
{
    QChart * chart = new QChart;
    chart->setTitle("PercentBar演示");
​
    //设置动画效果
    chart->setAnimationOptions(QChart::SeriesAnimations);
    ui->chartViewPercentBar->setChart(chart);
​
    //设置抗锯齿模式
    ui->chartViewPercentBar->setRenderHint(QPainter::Antialiasing);
}
​
//构建图表
void MainWindow::buildPercentBar()
{
    QChart * chart = ui->chartViewPercentBar->chart();
​
    //先清除chart,因为经常要刷新,可能会形成多个坐标轴
    chart->removeAllSeries();
    if(chart->axisX() != NULL)
    {
        chart->removeAxis(chart->axisX());
        chart->removeAxis(chart->axisY());
    }
​
    //数据集 QBarSet用于显示柱状图即三门课的成绩
    QBarSet * setMath = new QBarSet(theModel->horizontalHeaderItem(colNoMath)->text());
    QBarSet * setChinese = new QBarSet(theModel->horizontalHeaderItem(colNoChinese)->text());
    QBarSet * setEnglish = new QBarSet(theModel->horizontalHeaderItem(colNoEnglish)->text());
​
    //为堆积图添加数据集
    QStringList categories;
    for(int i = 0; i < 5; i++)
    {
        categories << ui->treeWidget->topLevelItem(i)->text(colNoName);
        setMath->append(ui->treeWidget->topLevelItem(i)->text(colNoMath).toFloat());
        setChinese->append(ui->treeWidget->topLevelItem(i)->text(colNoChinese).toFloat());
        setEnglish->append(ui->treeWidget->topLevelItem(i)->text(colNoEnglish).toFloat());
    }
​
    QStackedBarSeries * series = new QStackedBarSeries;
    series->append(setMath);
    series->append(setChinese);
    series->append(setEnglish);
​
    //添加坐标轴
    QBarCategoryAxis * axisX = new QBarCategoryAxis;
    axisX->append(categories);
    chart->setAxisX(axisX, series);
​
    QValueAxis *axisY = new QValueAxis;
    axisY->setRange(0, 100);
    axisY->setTitleText("分数");
    chart->setAxisY(axisY);
​
​
    //为表格添加序列化
    chart->addSeries(series);
}

绘制散点图(Scatterchart)

散点采用QScatterSeries,可以对散点大小及样式进行设置,使用append进行添加点,表格addSeries将序列加入。

 //初始化
void MainWindow::iniScatterChart()
{
    QChart * chart = new QChart;
    chart->setTitle("ScatterChart演示");
​
    //设置动画效果
    chart->setAnimationOptions(QChart::SeriesAnimations);
    ui->chartViewStackedBar->setChart(chart);
​
    //设置抗锯齿模式
    ui->chartViewStackedBar->setRenderHint(QPainter::Antialiasing);
}
​
//构建图表
void MainWindow::buildScatterChart()
{
   //获取ScatterChart指针
   QChart * chart = ui->chartViewScatter->chart();
​
   //清除之前的序列
   chart->removeAllSeries();
​
   //防止出现多个坐标轴
   if(chart->axisX() != NULL)
   {
       chart->removeAxis(chart->axisX());
       chart->removeAxis(chart->axisY());
   }
​
   //设置线的样式
   QSplineSeries * seriesLine = new QSplineSeries;
   seriesLine->setName("spline");
   QPen pen;
   pen.setWidth(2);
   pen.setColor(Qt::red);
   seriesLine->setPen(pen);
​
   //设置散点的样式
   QScatterSeries * series0 = new QScatterSeries;
   series0->setName("散点");
   series0->setMarkerShape(QScatterSeries::MarkerShapeCircle);
   series0->setBorderColor(Qt::black);
   series0->setBrush(Qt::blue);
​
   //设置大小
   series0->setMarkerSize(12);
​
   //添加数据
   for(int i = 0; i < 10; i++)
   {
       int x = qrand() % 20;
       int y = qrand() % 20;
       series0->append(x, y);
       seriesLine->append(x, y);
   }
​
   //为表格添加序列
   chart->addSeries(series0);
   chart->addSeries(seriesLine);
​
   //创建默认坐标轴
   chart->createDefaultAxes();
   chart->axisX()->setTitleText("X轴");
   chart->axisX()->setRange(-2, 22);
   chart->axisY()->setTitleText("Y轴");
   chart->axisY()->setRange(-2, 22);
}
  • 1
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值