《总之,好记性不如烂笔头!把你遗忘的都记下来吧!》
Qt基础
Qt元对象编辑器moc
元对象编辑器moc是负责解析c++中不存在的例如:signals、slot、emit等关键字,moc通过解析包含Q_OBJECT宏的类,生成能够处理信号和槽连接代码。
解析属性宏,生成相应的代码。
能使得Qt在运行时进行反射操作,比如查找类的方法、属性以及信号的槽。
Qt元对象系统:
元对象系统是Qt框架中独特的拓展,用来增强C++语言动态特性。
使用元对象系统必须包括以下三个方面:
1、QObject类是所有使用元对象系统的类的基类
2、必须在一个类的开头部分插入宏Q_OBJECT,这样这个类才能使用元对象系统的特性。
3、MOC为每个QObject的子类提供必要的代码实现元对象系统的特性。
支持的特性:
- 动态属性系统
- 信号和槽机制
- 反射机制
- 动态类型信息
坐标系统
获取当前标签位置:
pos()函数返回的是子窗口的左上角相对于父窗口的位置:
QPoint pos = ui->pushButton->pos();
mapToGlobal()函数返回控件的左上角坐标相对于整个屏幕的坐标
1 2
| QPoint pos = ui->pushButton->pos() QPoint posLeftUp = w.mapToGlobal(pos)
|
而对于事件QEvent,通过gloPos()函数可以直接获取事件的屏幕坐标
1
| QPoint point = event->globalPos()
|
类继承关系
属性:
sizePolicy 类型 QSizePolicy定义了组件在水平和垂直方向上的尺寸变化策略
QSizePolicy::fixed: 固定尺寸, QWidget的sizeHint()函数返回组件的建议尺寸作为组件的固定尺寸,即使使用了布局管理,组件也不会被放大或者缩小
作为窗口:
windowOpacity 设置窗口的透明度
信号:
void customContextMenuRequested(const QPoint &pos) 在组件上点击鼠标右键时发射,可以用于创建组件的快捷菜单
设置按钮背景图的方式
0、通过设置图标Icon来设置图片背景
1、通过QSS 设置 border-image
2、自定义继承按钮类,通过重写paintEvent,重画背景图片
QAction
QLineEdit
QTimer
创建定时器
1 2 3 4 5 6 7
| QTime *m_timeWait = new QTimer(this);
m_timeWait->setInterval(5000);
m_timeWait->start();
connect(m_timeWait, SIGNAL(timeout()), this, SLOT(doTimeSwitch()));
|
创建单次定时器
1 2 3 4
| m_animWait = new QTimer(this); m_animWait->singleShot(m_animContinue, Qt::PreciseTimer, this, [this](){ m_isAllowedLR = true; });
|
一个QTreeWidget组件显示内容分为表头和目录树两部分,表头和目录树结点都是QTreeWidgetItem对象
顶层节点:目录树中一行就是一个节点,目录树中最上层的节点成为顶层节点,顶层节点没有父节点,一个目录树中可以有多个顶层节点。
1 2
| void addTopLevelItem(QTreeWidgetItem *item); int indexOfTopLevelItem(QTreeWidgetItem *item);
|
**次级节点:**所有次级节点都直接或者间接挂在某个顶层节点下面。
隐藏的根节点:目录树中有一个隐藏的根节点,是所有顶层节点的父节点。
1
| QTreeWidgetItem *QTreeWidget::invisibleRootItem();
|
构造QTreeWidgetItem:
1
| QTreeWidgetItem(int type = Type);
|
可以传递一个整数表示节点类型,这个类型是自定义的
1 2 3 4 5
| enum TreeItemType{ TreeItemPro = 1, TreeItemDir = 2, TreeItemPic = 3, };
|
然后可以通过QTreeWidget::addTopLevelItem()
添加到顶层节点,或者通过QTreeWidgetItem::addChild()
将其添加为一个节点的子节点。
设置节点中每一列数据:
1 2 3 4 5 6 7
| item->setText(0, name); item->setIcon(0, QIcon(":/icon/icon/dir.png")); item->setToolTip(0, src_path);
item->setData(0, Qt::DisplayRole, name); item->setData(0, Qt::DecorationRole, QIcon(":/icon/icon/dir.png")); item->setData(0, Qt::ToolTipRole, src_path);
|
QLayout
setMargins();
setContentMargins();
作用:将多个控件当作一个整体,保证这个整体离布局的距离为(Left, Top, Right, Bottom)这几个参数。
控件间距调整:
setSpacing()
作用:设置某个布局下各个控件之间的间距
弹簧布局:
addStretch() setStretch()
作用:增加弹簧布局,参数大小代表弹簧弹力,不同的弹力大小代表控件比例,同类型的函数还有 setStretchFactor()。
QHBoxLayout
水平布局
QVBoxLayout
垂直布局
QGridLayout
网格布局
QFromLayout
表单布局,适用于两列管理的布局
QStackedLayout
堆叠布局,适用于多个页面切换的布局
QSpacerItem
布局中的占位符,可以用来填充剩余空间
QSplitter
分割条组件类,用来水平或者竖直的分割两个界面组件,使得两个控件所占空间能够随时改变
QEvent
什么情况是事件接受,什么情况是事件被接受
event->button()
返回单次按下的按键,不包括按下
event->buttons()
返回按下的组合按键,包括之前已经按下但未松开的按钮
Event->buttons()的返回是 Qt::MouseButton
返回值为以下几种类型:
Qt::NoButton |
0x00000000 |
Qt::LeftButton |
0x00000001 |
Qt::RightButton |
0x00000002 |
Qt::MidButton |
0x00000004 |
当左键按下时,返回值是1 右键 2 中键 4 左+右 3 左+中 5 右+中 6 左右中 7
QMimeData
QDialog
窗口类的重要特性设置
窗口显示或运行的一些特性可以通过QWidget的一些函数设置,如setAttribute() , setWindowFlag(), setWindowState()
模态(modal)窗口:窗口弹出后,没关闭之前,不可以对同一应用程序的其他窗口进行操作;
非模态(modeless)窗口:窗口弹出后,没关闭之前,可以对同一应用程序的其他窗口进行操作,可以同时和多个窗口进行交互;
setAttribute()
![1717816731342](D:\Documents\Tencent Files\2920611818\FileRecv\MobileFile\1717816731342.jpg)
setWindowFlag()
![1717816795244](D:\Documents\Tencent Files\2920611818\FileRecv\MobileFile\1717816795244.jpg)
setWindowState()
![1717817721460](D:\Documents\Tencent Files\2920611818\FileRecv\MobileFile\1717817721460.jpg)
setWindowModality()
![1717817816783](D:\Documents\Tencent Files\2920611818\FileRecv\MobileFile\1717817816783.jpg)
QFileDialog文件对话框
|
|
QString getOpenFileName() |
选择打开一个文件,返回选择文件的文件名 |
QStringList getOpenFileName() |
选择打开多个文件,返回选择的所有文件的文件名列表 |
QString getSaveFileName() |
选择保存一个文件,返回保存的文件的文件名 |
QString getExistingDirectory() |
选择一个已有的目录,返回所选目录的完整路径 |
QUrl getOpenFileUrl() |
选择打开一个文件,可选择打开远程网络文件 |
void SaveFileContent() |
将一个QByteArray类型的字节数据数组的内容保存为文件 |
1 2 3 4
| QString curPath = QDir::currentPath(); QString filter = "程序文件(*.h *.cpp);;文本文件(*.txt);;所有文件(*.*)"; QString fileLog = QFileDialog::getOpenFileName(this,"选择一个文件 ",curPath, filter);
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| QString curPath = QDir::currentPath(); QString filter = "h 文件(*.h);;C++文件(*.cpp);;文本文件(*.txt);;所有文件(*.*)"; QString aFileName = QFileDialog::getSaveFileName(this,"另存文件夹 ",curPath,filter); if(aFileName.isEmpty()) return;
QFileInfo fileInfo(aFileName); QDir::setCurrent(fileInfo.absolutePath()); QFile aFile(aFileName); if(!aFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QString str = ui->plainTextEdit->toPlainText(); QByteArray strBytes = str.toUtf8(); aFile.close();
|
QColorDialog颜色对话框
1 2
| QColor QColorDialog::getColor();
|
QFontDialog字体对话框
1 2
| QFont QFontDialog::getFont();
|
QMessageBox消息对话框
QIODevice
QCoreApplicaton
为无UI应用程序提供事件循环的类,所有应用程序的基类,其子类QGuiApplication是具有GUI的应用程序类,具有主事件循环,能够处理和派发来自操作系统或者其他来源的事件。
QGuiApplication的子类QApplication为QWidget应用程序提供支持,包括界面的初始化。
1 2 3 4 5 6 7 8 9 10 11 12 13
| QCoreApplication::setOrganizationName("HAOKS");
QCoreApplication::setApplicationName("FILE TEST");
QString str = QCoreApplication::applicationDirPath();
str.append("\n applicationFilePath: " + QApplication::applicationFilePath());
str.append("\n applicationName: " + QApplication::applicationName()); ui->plainTextEdit->appendPlainText(str + '\n');
QCoreApplication::exit();
|
QFile
主要进行文件内容的读写,还可用于文件的操作,如复制文件,删除文件,重命名文件。
QFileInfo
用于获取文件的各种信息。
QSaveFile
QSaveFile专门用来保存文件,可以用来保存文本文件或二进制文件。
在保存文件时,QSaveFile会在目标问价所在的目录下创建一个临时文件,向文件写入数据是先写入临时文件,如果写入操作没有错误,调用QSaveFile的函数Commit()提交修改时临时文件里的内容才被移入目标文件,然后临时文件会被删除。
在调用函数commit()之间,如果写入操作产生异常导致程序异常结束,目标文件不会由损失,避免了破坏文件结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| QString fileName = ui->lineEdit->text(); QSaveFile aFile(fileName); if(!aFile.open(QIODevice::WriteOnly | QIODevice::Text)) qDebug()<<"open error"; aFile.setDirectWriteFallback(false); try{ QString str = ui->plainTextEdit->toPlainText(); QByteArray strBytes = str.toUtf8(); aFile.write(strBytes, strBytes.length()); aFile.commit(); }catch(QException &e){ qDebug()<<"发生错误: "<<e.what(); aFile.cancelWriting(); }
|
QDir
进行目录操作的类,在构造函数中传递一个目录字符串作为当前目录,或者使用setPath()设置目录。
1 2
| QDir dir("C:/Users/web"); dir.setPath("C:/Users/web");
|
获取当前目录路径:
1
| QString curPath = QDir::currentPath();
|
返回当前目录下的文件fileName的含有绝对路径的文件名
1
| QString dist_path = dir.absoluteFilePath(fileName);
|
QTemporaryDir
用于创建临时目录
QTemporaryFile
用于创建临时文件,临时文件可以保存在系统的临时目录、指定目录或者应用程序当前目录下。QTemporaryFile的父类为QFile。
QFileSystemWatcher
对目录和文件进行监视的类,父类为QObject。把某些目录或者文件添加到QFileSystemWatcher对象的监视列表后;
当目录发生新建、删除文件等操作时,QFileSystemWatcher会发射directoryChanged()信号;
当所监视的文件发生修改、重命名等操作时,QFileSystemWatcher会发射fileChanged()信号。
读写文本文件
1、使用QFile
1 2 3 4 5 6 7 8 9 10
| QFile aFile(ui->lineEdit->text()); if(!aFile.exists()) return ; if(!aFile.open(QIODevice::ReadOnly | QIODevice::WriteOnly)) return ; QByteArray info = aFile.readAll(); QString text = QString::fromUtf8(info); ui->plainTextEdit->appendPlainText(text); aFile.close();
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| QString curPath = QDir::currentPath(); QString filter = "h 文件(*.h);;C++文件(*.cpp);;文本文件(*.txt);;所有文件(*.*)"; QString aFileName = QFileDialog::getSaveFileName(this,"另存文件夹 ",curPath,filter); if(aFileName.isEmpty()) return;
QFileInfo fileInfo(aFileName); QDir::setCurrent(fileInfo.absolutePath()); QFile aFile(aFileName); if(!aFile.open(QIODevice::WriteOnly | QIODevice::Text)) return ; QString str = ui->plainTextEdit->toPlainText(); QByteArray strBytes = str.toUtf8();
aFile.write(strBytes, strBytes.length()); aFile.close();
|
2、使用QFile和QTextStream
1 2 3 4 5 6 7 8 9 10 11
| QString fileName = ui->lineEdit->text(); QFile aFile(fileName); if(!aFile.open(QIODevice::ReadOnly | QIODevice::Text)) qDebug()<<"open error"; QTextStream aStream(&aFile);
aStream.setAutoDetectUnicode(true); QString str = aStream.readAll(); ui->plainTextEdit->setPlainText(str); aFile.close();
|
读写二进制文件
可以单使用QFile读写二进制文件,一般结合使用QFile和QDataStream读写二进制文件。
Qt SQL
数据库连接 |
QSqlDataBase |
用于建立与数据库连接 |
数据库中的对象 |
QSqlRecord |
表示数据表中一项记录的类 |
|
QSqlField |
表示数据库或视图的字段的类 |
|
QSqlIndex |
表示数据库中索引的类 |
模型类 |
QSqlTableModel |
表示单个数据表的模型类 |
|
QSqlQueryModel |
表示SQL查询结果数据的只读模型类 |
其它功能类 |
QSqlQuery |
运行各种SQL语句的类 |
|
QDataWidgetMapper |
用于建立界面组件与字段的映射关系的类 |
|
QSqlError |
用于表示数据库错误信息的类,访问上一次的错误信息 |
关系模型类 |
QSqlRelationalTableModel |
表示关系数据表的模型类 |
|
QSqlRelationalDelegate |
用于QSqlRelationalTableModel模型的一个编辑字段的代理类,这个代理类提供一个QComboxBox组件作为编辑器 |
|
QSqlRelation |
用于表示数据表外键信息的类 |
以ODBC为例连接MySQL数据库
1 2 3 4 5 6 7 8 9 10
| QSqlDatabase DB; DB = QSqlDatabase::addDatabase("QODBC"); DB.setHostName("127.0.0.1"); DB.setPort(3306); DB.setUserName("root"); DB.setPassword("123456"); DB.setDatabaseName("hotel"); if(!DB.open()){ ui->labelDataBase->setText("数据库连接失败!");
|
数据模型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| tabModel = new QSqlTableModel(this,DB);
tabModel->setTable("user");
tabModel->setEditStrategy(QSqlTableModel::OnManualSubmit);
tabModel->setSort(tabModel->fieldIndex("account"),Qt::AscendingOrder);
if(!(tabModel->select())){ qDebug()<<"错误信息:"<<tabModel->lastError().text(); return ; }
tabModel->setHeaderData(tabModel->fieldIndex("id"), Qt::Horizontal, "身份证号"); tabModel->setHeaderData(tabModel->fieldIndex("account"),Qt::Horizontal,"手机号"); tabModel->setHeaderData(tabModel->fieldIndex("pwd"),Qt::Horizontal, "密码"); tabModel->setHeaderData(tabModel->fieldIndex("username"),Qt::Horizontal,"姓名"); tabModel->setHeaderData(tabModel->fieldIndex("permission"),Qt::Horizontal, "权限"); tabModel->setHeaderData(tabModel->fieldIndex("ava"),Qt::Horizontal,"头像"); tabModel->setHeaderData(tabModel->fieldIndex("gender"),Qt::Horizontal, "性别");
|
选择模型
1 2 3
| selModel = new QItemSelectionModel(tabModel, this);
|
模型/视图结构
1 2 3 4 5 6
| ui->tableViewUser->setModel(tabModel); ui->tableViewUser->setSelectionModel(selModel);
ui->tableViewUser->setColumnHidden(tabModel->fieldIndex("ava"),true);
|
数据到界面组件映射
1 2 3 4 5 6 7 8 9 10 11 12 13
| QDataWidgetMapper *dataMapper; dataMapper= new QDataWidgetMapper(this); dataMapper->setSubmitPolicy(QDataWidgetMapper::AutoSubmit); dataMapper->setModel(qryModel);
dataMapper->addMapping(ui->dbSpinEmpNo, rec.indexOf("empNo")); dataMapper->addMapping(ui->dbEditName, rec.indexOf("Name")); dataMapper->addMapping(ui->dbComboSex, rec.indexOf("Gender")); dataMapper->addMapping(ui->dbEditBirth, rec.indexOf("Birthday"));
dataMapper->toFirst();
|
单个数据记录QSqlRecord
1 2 3 4 5 6 7 8
| QSqlRecord rec = tabModelRoom->record();
tabModelRoom->insertRecord(tabModelRoom->rowCount(), rec);
tabModelRoom->submitAll();
QSqlRecord curRec = tabModelRoom->record(i);
|
执行SQL语句
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| QSqlQuery resultPwd;
resultPwd.prepare("select pwd, permission from user where user.account = :account");
resultPwd.bindValue(":account",account);
resultPwd.exec();
resultPwd.next(); LoginAttri res;
if(resultPwd.value("pwd").toString() != pwd){ QMessageBox::information(this,"info","密码错误"); return; }
while (q.next()) { QString username = q.value("username").toString(); qDebug() << "Username:" << username; }
|
QPainter绘图
使用QPainter在绘图设备上绘图,绘图设备见类继承关系,注意:当绘图设备为QWidget时,QPainter只能在paintEvent()内部使用。
QPainter
绘图主要是利用QPainter接口函数在绘图设备上绘制各种基本的图形
QPen
设置绘图时的线条特性,主要包括线宽,颜色,线形状等。
QBrush
定义QPainter绘图时的一个区域的填充特性,包括填充颜色,填充样式,材质填充时的材质图片等。
渐变填充效果
- QLinearGradient:线性渐变
- QRadioGradient:辐射渐变
- QConicalGradient:圆锥形渐变
使用QPainter绘制图形举例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| void Widget::paintEvent(QPaintEvent *event) { QPainter painter(this); painter.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing); int W = this->width(); int H = this->height(); QRect rect(W/4, H/4, W/2, H/2); QPen pen; pen.setWidth(3); pen.setColor(Qt::blue); pen.setStyle(Qt::SolidLine); pen.setCapStyle(Qt::FlatCap); pen.setJoinStyle(Qt::BevelJoin); painter.setPen(pen); QPixmap texturePixmap(":/209ab910dba69ea54d89a31e10bf82d6_4983283784718022512.png"); QBrush brush; brush.setStyle(Qt::TexturePattern); brush.setTexture(texturePixmap); painter.setBrush(brush); painter.drawRect(rect); event->accept(); }
|
QPainter绘制基本图形接口
通过函数接口绘制各种基本的图形,包括绘制图片,具体接口
可以用QPainterPath记录绘制图形的路径
1 2 3
| QPixmap splice(m_width * (m_imageCount + 2), m_height); QPainter painter(&splice);
|
坐标系统和坐标变化
1、平移
2、旋转
3、缩放
4、状态恢复和保存
视口和窗口定义:
视口是指绘图设备的任意一个矩形区域,使用物理坐标系。默认情况下,视口等于绘图设备的整个矩形区域。
窗口和视口是同一个矩形区域但是窗口是用逻辑坐标系定义的,窗口可以直接定义矩形区域的逻辑坐标范围。
物理坐标系叫做视口坐标系,逻辑坐标系也叫做窗口。通过内部坐标变化矩阵,QPainter能自动将逻辑坐标变化为绘图设备的物理坐标。
默认情况下视口等于绘图设备的整个矩形区域,它可以被设定为绘图设备的任意一个矩形区域,使用物理坐标系。
QPainter::setViewPort(int x, int y, int width, int height);
窗口可以任意定义矩形区域的逻辑坐标范围,在这个范围内显示个内容会映射到视口中。
QPainter::serWindow(int x, int y, int width, int height);
有关图片处理类
QImage
类说明:与硬件无关的表示图片类,是为设备输入输出优化设计类,可以直接进行图片像素数据的访问和操作。
像素知识补充:
像素
px(pixel),可以理解为一个最小图像单元(只能涂一个颜色)的小方块,就是1px,是一小块面积,但是一般并不强调面积的大小,只是说这是一个最小单元。
1px是一个小方块,但是这个小方块的边长却不是固定的,不同的图片、显示设备都可能是不同的,甚至这个小方块可以是长方形,就是说表示为1px的小方块的宽和高,真实对应的长度可能是不同的。我们可以把一个像素理解为一个点,因为我们经常会忽略像素的大小,平时关注更多的是像素数,也就是分辨率。想象有一个投影,或远或近的打到墙面上,大小会有变化,其实像素数没变。再想象显示器有不同尺寸的,分辨率(像素数)却是相同的。这些都可以理解为是像素大小不同导致的。
分辨率
像素是一个小方块,用这些小方块排成一个大的长方形,这个长方形就是图像,图像的分辨率为:图像宽排列的像素数 × 图像高排列的像素数。如果把像素想象成点,那么分辨率就是 宽像素数 × 高像素数。
4K分辨率:是指水平方向每行像素值达到或者接近4096个(4096×2160)
DPI(Dots Per Inch,每英寸点数),图像每英寸(1 英寸 = 25.4 毫米)长度内的像素点数。
我们还是应该把像素理解为小方块,dpi就可以理解为是一英寸长度内排列的像素数。通过图像的dpi我们就可以计算出在这个图像中像素的边长,如果也知道图像的分辨率(宽高像素数),就可以知道该图像的真实尺寸了。
DPM(Dots Per Meter, 每米点数), 1 DPI = 0.0254 DPM
点距(dot pitch),就是把像素理解为点的时候,点距就是两个像素点的距离。我们把像素理解为小方块,那点距其实就是像素的边长
点距与DPI之间转换,点距一般用毫米表示,DPI表示1英寸(也就是25.4mm)长度内的像素数,所以点距(像素的边长)就等于 25.4 / DPI(总长度/个数=每个长度)
显示器规格:
属性 |
值 |
分辨率 |
1366 * 768 |
尺寸 |
13寸(英寸,对角线长度) |
计算过程 |
|
我们理解像素是个小正方形,所以显示器的宽高比例也是1366 : 768,
很容易求出,宽:11.33英寸,高:6.37英寸,
DPI :1366 / 11.33(或 768 / 6.37)= 120.55,
点距:25.4 / 120.55 = 0.2107 mm
QPixmap
类说明:为了在屏幕上显示图片而优化设计的类。
缩放到指定高度
缩放到指定宽度
缩放到指定宽度和高度
1
| scaled(const QSize &size, Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio, Qt::TransformationMode transformMode = Qt::FastTransformation)
|
QImage与QPixmap的区别
1、QPixmap主要是用于绘图,针对屏幕显示而最佳化设计,QImage主要是为图像I/O、图片访问和像素修改而设计的
2、QPixmap依赖于所在的平台的绘图引擎,故例如反锯齿等一些效果在不同的平台上可能会有不同的显示效果,QImage使用Qt自身的绘图引擎,可在不同平台上具有相同的显示效果
3、目前的Qt会把QPixmap都存储在graphics memory中,QImage是存储在客户端的,是独立于硬件的。在 X11, Mac 以及 Symbian平台上,QPixmap 是存储在服务器端,而QImage则是存储在客户端,在Windows平台上,QPixmap和QImage都是存储在客户端,并不使用任何的GDI资源。
4、由于QImage是独立于硬件的,也是一种QPaintDevice,因此我们可以在另一个线程中对其进行绘制,而不需要在GUI线程中处理,使用这一方式可以很大幅度提高UI响应速度。
5、QImage可通过setPixpel()和pixel()等方法直接存取指定的像素。当图片较大时,我们可以先通过QImage将图片加载进来,然后把图片缩放成需要的尺寸,最后转换成QPixmap 进行显示。
QBitmap
是QPixmap的子类,用于表示一位色深的单色位图
QPicture
可以记录和重现QPainter的各条命令
图形/视图架构
采用QPainter需要在绘图设备事件处理函数paintEvent()编写代码来实现绘图,绘制的是位图。对于绘制复杂可交互的图形使用图形/视图架构,每个图像都是可选择的,可拖放,可修改的。
由三部分组成 1、场景 2、视图 3、图形项
1、QGraphicsScene场景
场景是一个抽象的管理图形的容器,可以向场景中添加图形项,可以获取场景中的图形项。
主要功能:
提供管理大量图形项的快速接口
将事件传播给每个图形项
管理每个图形项的状态,如:选择状态,焦点状态
管理未经变换的渲染功能,主要用于打印
场景中同时除了图形项还存在 背景层和 前景层
setBackgroundBrush() 设置背景层画刷
setForegroundBrush() 设置前景层画刷
2、QGraphicsView视图
间接父类为QWidget是一个界面组件,用于显示场景中的内容。可以为一个场景设置多个视图,用于对用一个场景提供不同的显示界面。默认情况下,视图大于场景时,场景在视图的中央显示,也可通过设置视图的Alignment属性控制场景在视图中显示的位置。
视图通过接受键盘和鼠标输入并转换为场景的事件,进行坐标变换后这些事件被传送给可视场景。
3、QGraphicsItem图形项
所有的图像项都是从QGraphicsItem继承而来的,其没有父类。图形项相当于模型中的数据,一个图形项存储了绘制这个图形项的各种参数,场景管理所有图形项,视图组件负责绘制这些图形项。
支持的操作:
一个图形项还可以包含子图形项,图形项之间还支持碰撞检测。
图形/视图架构坐标系
图形/视图架构有三个有效的坐标系:场景坐标系,视图坐标系,图形项坐标系
1、场景坐标系
场景坐标系定义了所有图形项的基础坐标, 场景坐标系描述了每个顶层图形项的位置.
1 2
| scene = new QGraphicsScene(-400, -300, 800, 600);
|
2、视图坐标系
视图坐标系就是视图组件的物理坐标系, 单位为像素, 视图坐标系只与视图组件和视口有关,与场景无关. QGraphicsview视口的左上角坐标总是(0, 0), 所有的鼠标事件,拖放事件的坐标首先是由视图坐标系定义, 然后用户将视图坐标映射为场景坐标, 和图形交互.
3、图形坐标系
图形项使用自己的局部坐标系, 以自己的中心为原点(0,0).
图形项的位置就是指其中心在父对象项坐标系中的坐标, 没有父图形项的图形项, 父对象就是场景.
QGraphicsItem::pos() 返回图形项在父对象中的坐标
4、坐标映射
QGraphicsView::mapToScene() 将视图坐标映射为场景坐标
QGraphicsScene::itemAt() 获取场景中鼠标光标处的图形项
创建图形/视图举例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| QRectF rect(-200, -100, 400, 200); scene = new QGraphicsScene(rect, this); ui->graphicsView->setScene(scene);
QGraphicsRectItem *item = new QGraphicsRectItem(rect); item->setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); QPen pen; pen.setWidth(2); item->setPen(pen);
scene->addItem(item); QGraphicsEllipseItem *item2 = new QGraphicsEllipseItem(-100, -50, 200, 100);
item2->setPos(0,0); item2->setBrush(QBrush(Qt::blue));
item2->setFlag(QGraphicsItem::ItemIsMovable); item2->setFlag(QGraphicsItem::ItemIsSelectable); item2->setFlag(QGraphicsItem::ItemIsFocusable); scene->addItem(item2); QGraphicsEllipseItem *item3 = new QGraphicsEllipseItem(-50, -50, 100, 100); item3->setPos(rect.right(),rect.bottom()); item3->setBrush(QBrush(Qt::red)); item3->setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable |QGraphicsItem::ItemIsFocusable); scene->addItem(item3);
scene->clearSelection();
|
QChart绘图
QAnimation
Qt常见功能类
QPagedPaintDevice
QPainter
用于打印输出的类
QPdfWriter
用于生成pdf文件的绘图设备类
QGraphicsDropShadowEffect
创建阴影效果
1 2 3 4 5 6 7 8 9 10
| QGraphicsDropShadowEffect *shadow_effect = new QGraphicsDropShadowEffect(this);
shadow_effect->setOffset(0, 0);
shadow_effect->setColor(Qt::red);
shadow_effect->setBlurRadius(20);
m_pLoginPhoneLabel->setGraphicsEffect(shadow_effect);
|
常见问题:
字符串编码错误:
使用Qt的时候,时常会遇到中文乱码问题,qDebug打印日志乱码,或者Widget界面乱码等等。
原因呢,大多是因为使用MSVC编译器问题导致,而Qt 自带的MinGW一般不会出现乱码问题。
1 2 3 4
| #if _MSC_VER >= 1600 #pragma execution_character_set("utf-8") #endif
|
QSS
QSS官方说明:Customizing Qt Widgets Using Style Sheets | Qt Widgets 6.7.1
盒子模型
使用样式表时,每个widget都被视为包含四个同心矩形的框
:边距矩形(margin rectangle)、边框矩形(border rectangle)、填充矩形(padding rectangle)和内容矩形(content rectangle)。
常见样式举例:
1 2 3 4 5 6 7 8 9
| QPushButton { border:none; border-radius: 4px; color:rgb(244, 216, 168); background-color: rgb(57, 59, 64); } QPushButton::hover { background-color: rgba(57, 59, 64, 200); }
|
QComboBox
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| QComboBox { border:none; font: normal normal 16px "Microsoft YaHei"; background-color: rgb(243, 243, 243); }
QComboBox::drop-down{ subcontrol-origin: padding; subcontrol-position: top right; border-left-width: 1px; border-left-color: darkgray; width: 20px; }
QComboBox::down-arrow{ image: url(:/res/down.png); width: 20px; height: 20px }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| QCheckBox::indicator{ border-radius: 5px; border:none; width:30px; height:30px; } QCheckBox::indicator:unchecked{ image:url(:/new/bg/res/unchecked.png); border: 0px; } QCheckBox::indicator:checked{ image:url(:/new/bg/res/checked.png); border: 0px; background-color:rgb(57, 59, 64); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| `QRadioButton::indicator{ border:none; width:30px; height:30px; } QRadioButton::indicator:unchecked{ image: url(:/new/bg/res/radio button unselect.png); border: 0px; } QRadioButton::indicator:checked{ image: url(:/new/bg/res/radio button select.png); border: 0px; }`
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| QToolButton { color:rgb(112, 74, 29); background-color:rgb(255, 202, 11); border: 2px; border-radius: 4px; } QToolButton::menu-arrow{ image:none; }
QToolButton::menu-button{ width: 35px; image: url(:/res/mession.png); }
QToolButton::hover { background-color:rgb(255, 206, 45); }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| QScrollArea{ border: 0px solid; border-right-width: 1px; border-right-color: #dcdbdc; background-color: #f5f5f7; } QScrollBar:vertical { border: none; background: #ffffff; width: 10px; margin: 0px 0 0px 0; } QScrollBar::handle:vertical { background: Gainsboro; min-height: 20px; border-radius: 5px; border: none; } QScrollBar::add-line:vertical { border: 0px solid grey; background: #32CC99; height: 0px; subcontrol-position: bottom; subcontrol-origin: margin; } QScrollBar::sub-line:vertical { border: 0px solid grey; background: #32CC99; height: 0px; subcontrol-position: top; subcontrol-origin: margin; } QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical { background: none; width: 0px; height: 0px; }
|
QLineEdit
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| QLineEdit { border-radius: 3px; padding-left: 5px; background-color:rgb(243, 243, 243); color: rgb(0, 0, 0); selection-background-color: #A0A0A0; selection-color: #F2F2F2; font-family: "Microsoft YaHei"; font-size: 20px; }
QLineEdit:hover { border-radius: 3px; selection-color: #F2F2F2; }
QLineEdit[echoMode="2"] { lineedit-password-character: 9679; lineedit-password-mask-delay: 2000; }
QLineEdit:disabled { border: 1px solid #CDCDCD; background-color: #CDCDCD; color: #B4B4B4; }
QLineEdit:read-only { background-color: #CDCDCD; color: #F2F2F2; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| QTabWidget::pane { border: 0; }
QTabBar::tab { background: transparent; font-family:"微软雅黑"; color:rgb(255, 255, 255); font-size:16px; font: bold; padding-left:5px; padding-right:5px; min-width: 85px; min-height:30px; } QTabBar::tab:selected { border-bottom: 3px solid rgb(255, 210, 132); } QTabBar::tab:hover { color: rgb(255, 210, 132); } QStackedWidget { background: transparent; } QStackedWidget > QWidget { background-color: rgba(20,20,20,80); }
|