目录
Qtchart绘制折线图
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 文件的格式定义
顺序号 | 数据 | 类型 | 备注 |
---|---|---|---|
1 | rowCount | qintl6 | 行数 |
2 | colCount | qintl6 | 列数 |
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 | 测深 |
10 | qreal | 垂深 | |
11 | qreal | 方位 | |
12 | qreal | 位移 | |
13 | QString | 固井质量 | |
14 | bool | 是否测井取样 | |
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); }