Qt 是一个跨平台的C++图形用户界面应用程序框架。它为应用程序开发者提供建立艺术级图形界面
所需的所有功能。它是完全面向对象的,很容易扩展,并且允许真正的组件编程。
常见GUI:
QT:支持多平台开发;支持css;面向对象特性体现突出;发展趋势良好。
MFC:只能在windows开发;运行程序效率高;库的安全性好;
Qt 按照不同的版本发行,分为商业版和开源版
按照默认安装即可
Qt 对不同的平台提供了不同版本的安装包,可根据实际情况自行下载安装,本文档使用
qt-opensource-windows-x86-mingw530-5.13.0 版本进行讲解(32 位和64 位均可安装)
跨平台,几乎支持所有的平台
接口简单,容易上手,学习QT 框架对学习其他框架有参考意义。
一定程度上简化了内存回收机制
开发效率高,能够快速的构建应用程序。
有很好的社区氛围,市场份额在缓慢上升。
可以进行嵌入式开发。
在使用Qt 向导生成的应用程序.pro 文件格式如下:
QT += core gui //包含的模块
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets //大于Qt4 版本才包含widget 模块
TARGET = QtFirst //应用程序名生成的.exe 程序名称
TEMPLATE = app //模板类型应用程序模板
SOURCES += main.cpp //源文件
mywidget.cpp
HEADERS += mywidget.h //头文件
.pro 就是工程文件(project),它是qmake 自动生成的用于生产makefile 的配置文件。.pro 文件的
写法如下:
#指定生成的应用程序名:
TARGET = QtDemo
#工程中包含的头文件
HEADERS += include/painter.h
#工程中包含的.ui 设计文件
FORMS += forms/painter.ui
#工程中包含的源文件
SOURCES += sources/main.cpp sources
#工程中包含的资源文件
RESOURCES += qrc/painter.qrc
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
这条语句的含义是,如果QT_MAJOR_VERSION 大于4(也就是当前使用的Qt5 及更高版本)需要
增加widgets 模块。如果项目仅需支持Qt5,也可以直接添加“QT += widgets”一句。不过为
了保持代码兼容,最好还是按照QtCreator 生成的语句编写。
#配置信息
CONFIG 用来告诉qmake 关于应用程序的配置信息。
CONFIG += c++11 //使用c++11 的特性
在这里使用“+=”,是因为我们添加我们的配置选项到任何一个已经存在中。这样做比使用“=”那
样替换已经指定的所有选项更安全。
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 重新更新
this->setWindowTitle("hello world"); // 更改UI内容
this->resize(600,400);
}
Widget::~Widget()
{
delete ui;
}
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 重新更新
this->setWindowTitle("hello world");
// 设置 完成之后可以拉伸
this->resize(600,400);
// 设置固定大小
this->setFixedSize(QSize(200,200));
QPushButton *button = new QPushButton;
// 设置父亲对象
button->setParent(this);
}
Widget::~Widget()
{
delete ui;
}
button->setText("红红红!");
button->move(50,50);
button->setFixedSize(QSize(400,400));
QPushButton *button2 = new QPushButton("第二个按钮",this); // 包括设置文本和父对象
在Qt中创建对象的时候会提供一个Parent对象指针,下面来解释这个parent到底
是干什么的。
当你创建一个QObject对象时,会看到QObject的构造函数接收一个QObject指针作为参数,这个参数就是 parent,也就是父对象指针。
这相当于,在创建QObject对象时,可以提供一个其父对象,我们创建的这个QObject对象会自动添加到其父对象的children()列表。
n 当父对象析构的时候,这个列表中的所有对象也会被析构。(注意,这里的父对象并不是继承意义上的父类!)
QWidget继承自QObject,因此也继承了这种对象树关系。一个孩子自动地成为父组件的一个子组件。因此,它会显示在父组件的坐标系统中,被父组件的边界剪裁。例如,当用户关闭一个对话框的时候,应用程序将其删除,那么,我们希望属于这个对话框的按钮、图标等应该一起被删除。事实就是如此,因为这些都是对话框的子组件。
坐标体系:
以左上角为原点(0,0),X向右增加,Y向下增加。
信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。
connect()函数最常用的一般形式:connect(sender, signal, receiver, slot);
参数解释:
sender:发出信号的对象
signal:发送对象发出的信号
receiver:接收信号的对象
slot:接收对象在接收到信号之后所需要调用的函数(槽函数)
那么系统自带的信号和槽通常如何查找呢,这个就需要利用帮助文档了,在帮助文档中比如我们上面的按钮的点击信号,在帮助文档中输入QPushButton,首先我们可以在Contents中寻找关键字 signals,信号的意思,但是我们发现并没有找到,这时候我们应该想到也许这个信号的被父类继承下来的,因此我们去他的父类QAbstractButton中就可以找到该关键字,点击signals索引到系统自带的信号有如下几个
#ifndef WIDGET_H
#define WIDGET_H
#include
#include
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
public slots: // 添加槽函数
void print();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 重新更新
this->setWindowTitle("hello world");
// 设置 完成之后可以拉伸
this->resize(600,400);
// 设置固定大小
this->setFixedSize(QSize(600,400));
// QPushButton *button = new QPushButton;
// 设置父亲对象
// button->setParent(this);
// button->setText("中国红!");
// // 按钮移动
// button->move(50,50);
// // 设置按钮大小
// button->setFixedSize(QSize(400,400));
QPushButton *button2 = new QPushButton("第二个按钮(关闭)",this);
# 定义信号函数
connect(button2,&QPushButton::clicked,this,&Widget::print);
}
Widget::~Widget()
{
delete ui;
}
void Widget::print(){
qDebug()<<"hello world!"; // 槽函数实现
}
自定义信号槽需要注意的事项:
一个信号可以和多个槽相连
如果是这种情况,这些槽会一个接一个的被调用,但是它们的调用顺序是不确定的。
多个信号可以连接到一个槽
只要任意一个信号发出,这个槽就会被调用
一个信号可以连接到另外的一个信号
当第一个信号发出时,第二个信号被发出。除此之外,这种信号-信号的形式和信号-槽的形式
没有什么区别。
槽可以被取消链接
这种情况并不经常出现,因为当一个对象delete 之后,Qt 自动取消所有连接到这个对象上面的
槽。
信号槽可以断开
利用disconnect 关键字是可以断开信号槽的
使用Lambda 表达式
在使用Qt5 的时候,能够支持Qt 5 的编译器都是支持Lambda 表达式的。
在连接信号和槽的时候,槽函数可以使用Lambda 表达式的方式进行处理。
重载信号时需要利用函数指针来确定执行的槽函数与信号函数
void (Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void (Student:: *studentSignal)(QString) = &Student::treat;
connect(zt,SIGNAL(hungry(QString)),st,SLOT(treat(QString)));
这里使用了SIGNAL 和SLOT 这两个宏,将两个函数名转换成了字符串。注意到connect()函数的
signal 和slot 都是接受字符串,一旦出现连接不成功的情况,Qt4 是没有编译错误的(因为一切
都是字符串,编译期是不检查字符串是否匹配),而是在运行时给出错误。这无疑会增加程序的不
稳定性。
Qt5 在语法上完全兼容Qt4,而反之是不可以的。
C++11 中的Lambda 表达式用于定义并创建匿名的函数对象,以简化编程工作。
Lambda表达式的基本构成:
[capture](parameters) mutable ->return-type
{
statement
}
QPushButton * myBtn = new QPushButton (this);
QPushButton * myBtn2 = new QPushButton (this);
myBtn2->move(100,100);
int m = 10;
connect(myBtn,&QPushButton::clicked,this,[m] ()mutable { m = 100 + 10; qDebug() << m; });
connect(myBtn2,&QPushButton::clicked,this,[=] () { qDebug() << m; });
qDebug() << m;
auto fun=[](){
qDebug()<<"hello world!222";
};
fun();
auto fun2=[](int a,int b){
qDebug()<<"hello world!333";
return a+b;
};
ClassIsOver();
qDebug()<
int a = 10;
auto fun3= [](int &a,int b){
qDebug()<<"hello world!333";
qDebug()<<"a==="<
QMainWindow 是一个为用户提供主窗口程序的类,包含一个菜单栏(menu bar)、多个工具栏(toolbars)、多个铆接部件(dock widgets)、一个状态栏(status bar)及一个中心部件(central widget),是许多应用程序的基础,如文本编辑器,图片编辑器等。
分别对应菜单栏,菜单,菜单项
//创建菜单栏:
#include
QMenuBar --> QMenuBar(QWidget *parent = Q_NULLPTR)
//添加菜单栏:
QMainWindow --> void setMenuBar(QMenuBar *menuBar)
//创建菜单:
#include
QMenu --> QMenu(const QString &title, QWidget *parent = Q_NULLPTR)
//添加菜单:
MenuBar --> QAction *addMenu(QMenu *menu)
//创建菜单项:
#include
QAction --> QAction(const QString &text, QObject *parent = nullptr)
//添加菜单项:
QMenu --> addAction(const QAction *action)
Qt 并没有专门的菜单项类,只是使用一个QAction 类,抽象出公共的动作。当我们把QAction 对象添加到菜单,就显示成一个菜单项,添加到工具栏,就显示成一个工具按钮。用户可以通过点击菜单项、点击工具栏按钮、点击快捷键来激活这个动作。
#include "mainwindow.h"
#include //菜单栏
#include //菜单
#include //菜单项
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
//**********窗口属性设置*****************
this->setWindowTitle("主窗口");
this->setFixedSize(800, 600);
//***********创建菜单栏******************
//创建菜单栏
//注意:如果只有菜单栏,则在窗口处没有现象
QMenuBar *menu_bar = new QMenuBar(this);
this->setMenuBar(menu_bar);
千锋智能物联网学院
//创建菜单
QMenu *menu1 = new QMenu("文件", this);
menu_bar->addMenu(menu1);
QMenu *menu2 = new QMenu("编辑", this);
menu_bar->addMenu(menu2);
QMenu *menu3 = new QMenu("构建", this);
menu_bar->addMenu(menu3);
//创建菜单项
QAction *act1 = new QAction("新建文件或项目", this);
menu1->addAction(act1);
QAction *act2 = new QAction("打开文件或项目", this);
menu1->addAction(act2);
//添加分割线
menu1->addSeparator();
QAction *act3 = new QAction("保存", this);
menu1->addAction(act3);
QAction *act4 = new QAction("另存为", this);
menu1->addAction(act4);
QAction *act5 = new QAction("复制", this);
act5->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_C));
menu2->addAction(act5);
QAction *act6 = new QAction("粘贴", this);
act6->setShortcut(QKeySequence(tr("Ctrl+V")));
menu2->addAction(act6);
QAction *act7 = new QAction("剪切", this);
menu2->addAction(act7);
//当单击菜单项时,做出相应的处理
connect(act5, &QAction::triggered, [=]{
qDebug()<<"复制正在执行";
});
connect(act6, &QAction::triggered, [=]{qDebug()<<"粘贴正在执行";
});
}
MainWindow::~MainWindow()
{
}
主窗口的工具栏上可以有多个工具条,通常采用一个菜单对应一个工具条的的方式,也可根据需要进行工具条的划分。
//创建工具栏:
#include
QToolBar --> QToolBar(QWidget *parent = Q_NULLPTR)
//添加工具栏:
QMainWindow -->
void addToolBar(QToolBar *toolbar)
void addToolBar(Qt::ToolBarArea area, QToolBar *toolbar)
Qt::LeftToolBarArea 左边显示
Qt::RightToolBarArea 右边显示
Qt::TopToolBarArea 上边显示
Qt::BottomToolBarArea 下边显示
直接调用QMainWindow 类的addToolBar()函数获取主窗口的工具条对象,每增加一个工具条
都需要调用一次该函数。
//创建工具栏
//注意:工具栏可以添加多个
QToolBar *toolbar = new QToolBar(this);
//将工具栏添加到窗口
//this->addToolBar(toolbar);//默认在最上面显示
this->addToolBar(Qt::LeftToolBarArea, toolbar); //设置默认在左边显示
//工具栏添加菜单项和分割线
QAction *act_tool1 = new QAction("欢迎", this);
QAction *act_tool2 = new QAction("编辑", this);
toolbar->addAction(act_tool1);
toolbar->addSeparator();
toolbar->addAction(act_tool2);
//设置工具栏的浮动状态,true:可以悬浮在窗口false:不可以
toolbar->setFloatable(false);
//设置运行工具栏的位置,设置为左边或者右边
toolbar->setAllowedAreas(Qt::LeftToolBarArea | Qt::RightToolBarArea);
创建状态栏:
QStatusBar -->
将控件添加到左边栏
void addWidget(QWidget *widget, int stretch = 0)
将控件添加到右边栏
void addPermanentWidget(QWidget *widget, int stretch = 0)
添加状态栏:
QMainWindow --> void setStatusBar(QStatusBar *statusbar)
//创建状态栏
//状态栏只能有一个
QStatusBar *statusbar = new QStatusBar(this);
//添加状态栏
this->setStatusBar(statusbar);
//给状态栏中添加文字信息或者按钮=
QLabel *label1 = new QLabel("左边信息", this);
statusbar->addWidget(label1);
QLabel *label2 = new QLabel("右边信息", this);
statusbar->addPermanentWidget(label2);
QPushButton *button = new QPushButton("设置", this);
statusbar->addWidget(button);
创建铆接部件:
QDockWidget -->
QDockWidget(const QString &title, QWidget *parent = Q_NULLPTR)
添加铆接部件:
QMainWindow -->
void addDockWidget(Qt::DockWidgetArea area, QDockWidget
*dockwidget)
Qt::LeftDockWidgetArea 左边
Qt::RightDockWidgetArea 右边
Qt::TopDockWidgetArea 上边
Qt::BottomDockWidgetArea 下边
//创建铆接部件
QDockWidget *dockwidget = new QDockWidget("这是一个铆接部件", this);
this->addDockWidget(Qt::TopDockWidgetArea, dockwidget);
除了以上几个部件,中心显示的部件都可以作为核心部件,例如一个记事本文件,可以利用QTextEdit 做核心部件
添加中心部件:
QMainWindow --> void setCentralWidget(QWidget *widget)
QTextEdit *edit = new QTextEdit("文本编辑器", this);
this->setCentralWidget(edit);
Qt 资源系统是一个跨平台的资源机制,用于将程序运行时所需要的资源以二进制的形式存储于可执行文件内部。如果你的程序需要加载特定的资源(图标、文本翻译等),那么,将其放置在资源文件中,就再也不需要担心这些文件的丢失。也就是说,如果你将资源以资源文件形式存储,它是会编译到可执行文件内部。使用Qt Creator 可以很方便地创建资源文件。我们可以在工程上点右键,选择“添加新文件…”,可以在Qt 分类下找到“Qt 资源文件”:
this->setAutoFillBackground(true);
//创建图片控件
QPixmap pix $=$ QPixmap(":/image/butterfly.png"). scaled(this->size());
// pix.load("://image/butterfly.png");
QPalette palette;
palette.setBrush(QPalette:: Background,QBrush(pix));
this->setPalette(palette);
this->setAutoFillBackground(true);
//创建图片控件
QPixmap pix = QPixmap(":/image/butterfly.png"). scaled(this->size());
// pix.load (":/image/butterfly.png");
QPalette palette;
palette.setBrush(QPalette:: Background, QBrush(pix));
this->setPalette(palette);
对话框是GUI 程序中不可或缺的组成部分。很多不能或者不适合放入主窗口的功能组件都必须放在对话框中设置。对话框通常会是一个顶层窗口,出现在程序最上层,用于实现短期任务或者简洁的用户交互。
Qt 中使用QDialog 类实现对话框。就像主窗口一样,我们通常会设计一个类继承QDialog。QDialog(及其子类,以及所有Qt::Dialog 类型的类)的对于其parent 指针都有额外的解释:如果parent
为NULL,则该对话框会作为一个顶层窗口,否则则作为其父组件的子对话框(此时,其默认出现的位置是parent 的中心)。顶层窗口与非顶层窗口的区别在于,顶层窗口在任务栏会有自己的位置,而非顶层窗口则会共享其父组件的位置。对话框分为模态对话框和非模态对话框。
所谓标准对话框,是Qt内置的一系列对话框,用于简化开发。事实上,有很多对话框都是通用的,比如打开文件、设置颜色、打印设置等。这些对话框在所有程序中几乎相同,因此没有必要在每一个程序中都自己实现这么一个对话框。Qt 的内置对话框大致分为以下几类:
QDialog dialog;
dialog.setWindowTitle(tr("Hello, dialog!"));
dialog.exec();
QDialog dialog(this);
dialog.setWindowTitle(tr("Hello, dialog!"));
dialog.show();
是不是事与愿违?对话框竟然一闪而过!这是因为,show()函数不会阻塞当前线程,对话框会显示出来,然后函数立即返回,代码继续执行。注意,dialog 是建立在栈上的,show()函数返回,MainWindow::open()函数结束,dialog 超出作用域被析构,因此对话框消失了。知道了原因就好改了,我们将dialog 改成堆上建立,当然就没有这个问题了:
QDialog *dialog = new QDialog;
dialog->setWindowTitle(tr("Hello, dialog!"));
dialog->show();
上面的代码是有问题的:dialog 存在内存泄露!dialog 使用new 在堆上分配空间,却一直没有delete。
解决方案也很简单:将MainWindow 的指针赋给dialog 即可。还记得我们前面说过的Qt 的对象系统吗?不过,这样做有一个问题:如果我们的对话框不是在一个界面类中出现呢?由于QWidget 的parent必须是QWidget 指针,那就限制了我们不能将一个普通的C++ 类指针传给Qt 对话框。另外,如果对内存占用有严格限制的话,当我们将主窗口作为parent 时,主窗口不关闭,对话框就不会被销毁,所以会一直占用内存。在这种情景下,我们可以设置dialog 的WindowAttribute:
QDialog *dialog = new QDialog;
dialog->setAttribute(Qt::WA_DeleteOnClose); // 在这里
dialog->setWindowTitle(tr("Hello, dialog!"));
dialog->show();
setAttribute()函数设置对话框关闭时,自动销毁对话框。
QMessageBox 用于显示消息提示。我们一般会使用其提供的几个static 函数:
void about(QWidget * parent, const QString & title, const QString & text)
这是一个最简单的对话框,其标题是title,内容是text,父窗口是parent。对话框只有一个OK 按钮。
void aboutQt(QWidget * parent, const QString & title = QString()):
StandardButton information(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = Ok,
StandardButton defaultButton
StandardButton question(QWidget * parent,const QString & title,
const QString & text,
StandardButtons buttons = StandardButtons( Yes | No ),
StandardButton defaultButton = NoButton)
StandardButton warning(QWidget * parent,
const QString & title,
const QString & text,
StandardButtons buttons = Ok,
StandardButton defaultButton = NoButton)
QMessageBox演示
if (QMessageBox::Yes == QMessageBox::question(this,
tr("Question"), tr("Are you OK?"),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::Yes))
{
QMessageBox::information(this, tr("Hmmm..."),
tr("I'm glad to hear that!"));
}
else
{
QMessageBox::information(this, tr("Hmmm..."),
tr("I'm sorry!"));
}
这个对话框的父窗口是this。QMessageBox 是QDialog 的子类,这意味着它的初始显示位置将会是在parent 窗口的中央。 第二个参数是对话框的标题。第三个参数是我们想要显示的内容。 第四个参数是关联的按键类型,我们可以使用或运算符(|)指定对话框应该出现的按钮。比如我们希望是一个Yes 和一个No。 最后一个参数指定默认选择的按钮。这个函数有一个返回值,用于确定用户点击的是哪一个按钮。按照我们的写法,应该很容易的看出,这是一个模态对话框,因此我们可以直接获取其返回值。QMessageBox 类的static 函数优点是方便使用,缺点也很明显:非常不灵活。
我们只能使用简单的几种形式。为了能够定制QMessageBox 细节,我们必须使用QMessageBox 的属性设置API。如果我们希望制作一个询问是否保存的对话框,我们可以使用如下的代码:
QMessageBox msgBox;
msgBox.setText(tr("The document has been modified."));
msgBox.setInformativeText(tr("Do you want to save your changes?"));
msgBox.setDetailedText(tr("Differences here..."));
msgBox.setStandardButtons(QMessageBox::Save
| QMessageBox::Discard
| QMessageBox::Cancel);
msgBox.setDefaultButton(QMessageBox::Save);
int ret = msgBox.exec();
switch (ret)
{
case QMessageBox::Save:
qDebug() << "Save document!";
break;
case QMessageBox::Discard:
qDebug() << "Discard changes!";
break;
case QMessageBox::Cancel:
qDebug() << "Close document!";
break;
}
msgBox 是一个建立在栈上的QMessageBox 实例。我们设置其主要文本信息为“The document has beenmodified.”,informativeText 则是会在对话框中显示的简单说明文字。下面我们使用了一个detailedText,也就是详细信息,当我们点击了详细信息按钮时,对话框可以自动显示更多信息。我们自己定义的对话框的按钮有三个:保存、丢弃和取消。然后我们使用了exec()是其成为一个模态对话框,根据其返回值进行相应的操作。
GUI 界面,归根结底,就是一堆组件的叠加。我们创建一个窗口,把按钮放上面,把图标放上面,这样就成了一个界面。在放置时,组件的位置尤其重要。我们必须要指定组件放在哪里,以便窗口能够按照我们需要的方式进行渲染。这就涉及到组件定位的机制。
Qt 提供了两种组件定位机制:绝对定位和布局定位。
Qt 提供的布局中以下三种是我们最常用的:
系统给我们提供的布局的控件
第二种布局方式是利用控件里的widget 来做布局,在Containers 中
在widget 中的控件可以进行水平、垂直、栅格布局等操作,比较灵活。再布局的同时我们需要灵活运用弹簧的特性让我们的布局更加的美观,下面是一个登陆窗口,利用widget 可以搭建出如下登陆界面:
Qt 为我们应用程序界面开发提供的一系列的控件,下面我们介绍两种最常用一些控件,所有控件的使用方法我们都可以通过帮助文档获取。
QLabel 是我们最常用的控件之一,其功能很强大,我们可以用来显示文本,图片和动画等。
通过QLabel 类的setText 函数设置显示的内容:
void setText(const QString &)
QLable *label = new QLable;
label->setText(“Hello, World!”);
QLabel * label = new QLabel(this);
label ->setText("Hello, World");
label ->setText("百度一下
");
label ->setOpenExternalLinks(true);
其中setOpenExternalLinks()函数是用来设置用户点击链接之后是否自动打开链接,如果参数指定为true 则会自动打开。
可以使用QLabel 的成员函数setPixmap 设置图片
void setPixmap(const QPixmap &)
首先定义QPixmap 对象,加载图片,设置到QLabel
QPixmap pixmap;
pixmap.load(":/Image/boat.jpg");
QLabel *label = new QLabel;
label.setPixmap(pixmap);
可以使用QLabel 的成员函数setMovie 加载动画,可以播放gif 格式的文件
void setMovie(QMovie * movie)
首先定义QMovied 对象,并初始化:
QMovie *movie = new QMovie(":/Mario.gif");
//播放加载的动画:
movie->start();
//将动画设置到QLabel 中:
QLabel *label = new QLabel;
label->setMovie(movie);
Qt 提供的单行文本编辑框。
获取编辑框内容使用text(),函数声明如下:
QString text() const
void setText(const QString &)
使用QLineEdit 类的setEchoMode () 函数设置文本的显示模式,函数声明:
void setEchoMode(EchoMode mode)
EchoMode 是一个枚举类型,一共定义了四种显示模式:
QLineEdit::Normal 模式显示方式,按照输入的内容显示。
QLineEdit::NoEcho 不显示任何 内容,此模式下无法看到用户的输入。
QLineEdit::Password 密码模式,输入的字符会根据平台转换为特殊字符。
QLineEdit::PasswordEchoOnEdit 编辑时显示字符否则显示字符作为密码。
另外,我们再使用QLineEdit 显示文本的时候,希望在左侧留出一段空白的区域,那么,就可以使
用QLineEdit 给我们提供的setTextMargins 函数:
void setTextMargins(int left, int top, int right, int bottom)
用此函数可以指定显示的文本与输入框上下左右边界的间隔的像素数。
// smallwidget.h
class SmallWidget : public QWidget
{
Q_OBJECT
public:
explicit SmallWidget(QWidget *parent = 0);
signals:
public slots:
private:
QSpinBox* spin;
QSlider* slider;
};
// smallwidget.cpp
SmallWidget::SmallWidget(QWidget *parent) : QWidget(parent)
{
spin = new QSpinBox(this);
slider = new QSlider(Qt::Horizontal, this);
// 创建布局对象
QHBoxLayout* layout = new QHBoxLayout;
// 将控件添加到布局中
layout->addWidget(spin);
layout->addWidget(slider);
// 将布局设置到窗口中
setLayout(layout);
// 添加消息响应
connect(spin,
static_cast(&QSpinBox::valueChanged),slider, &QSlider::setValue);
connect(slider, &QSlider::valueChanged,
spin, &QSpinBox::setValue);
}
事件(event)是由系统或者Qt 本身在不同的时刻发出的。当用户按下鼠标、敲下键盘,或者是窗口需要重新绘制的时候,都会发出一个相应的事件。
一些事件在对用户操作做出响应时发出,如键盘事件等;另一些事件则是由系统自动发出,如计时器事件。事件处理过程:
在所有控件的父类QWidget 中,定义了很多事件处理的回调函数。这些函数都是protected virtual 的,也就是说,我们可以在子类中重新实现这些函数。实现函数的要遵循虚函数的语法规则,自定义的类中保证函数名、参数的一致性。
//重写父类的虚函数
protected:
virtual void mousePressEvent(QMouseEvent *); //鼠标点击事件
virtual void mouseReleaseEvent(QMouseEvent *); //鼠标抬起事件
virtual void mouseDoubleClickEvent(QMouseEvent *); //鼠标双击事件
virtual void mouseMoveEvent(QMouseEvent *); //鼠标移动事件
//virtual void wheelEvent(QWheelEvent *); //鼠标滚轮滑动
//鼠标滚轮滑动
void Widget::wheelEvent(QWheelEvent *e)
{
if(e->orientation()== Qt::Vertical) //如果方向是垂直
{
QPoint point = e->angleDelta();
QString str = QString("滚轮垂直滑动(%1, %2)")
.arg( point.x() ).arg(point.y());
ui->label->setText(str);
}
}
//virtual void keyPressEvent(QKeyEvent *); //键盘按下事件
//virtual void keyReleaseEvent(QKeyEvent *); //键盘抬起事件
//键盘按下事件
void Widget::keyPressEvent(QKeyEvent *e)
{
QString str;
switch(e->modifiers()) //修饰键盘
{
case Qt::ControlModifier:
str = "Ctrl+";
break;
case Qt::AltModifier:
str = "Alt+";
break;
}
switch(e->key()) //普通键
{
case Qt::Key_Left:
str += "Left_Key Press";
break;
case Qt::Key_Right:
str += "Rigth_Key Press";
break;
case Qt::Key_Up:
str += "Up_Key Press";
break;
case Qt::Key_Down:
str += "Down_Key Press";
break;
case Qt::Key_Z:
str += "Z_Key Press";
break;
}
ui->label->setText(str);
}
当窗口大小发生变化时被调用,参考代码:
//virtual void resizeEvent(QResizeEvent *); //大小改变事件
//大小改变事件
void Widget::resizeEvent(QResizeEvent *e)
{
//变化前的窗口大小
qDebug() << "e->oldSize() = " << e->oldSize();
//变化后的窗口大小
qDebug() << "e->size() = " << e->size();
}
//virtual void enterEvent(QEvent *); //进入事件
//virtual void leaveEvent(QEvent *); //离开事件
//进入事件
void Widget::enterEvent(QEvent *)
{qDebug() << "enterEvent";
}
//离开事件
void Widget::leaveEvent(QEvent *)
{
qDebug() << "leaveEvent";
}
Qt 的绘图机制为屏幕显示和打印显示提供了统一的API 接口,主要有三部分组成:QPainter 类、QPaintDevice
类和QPaintEngine 类
l QPainter 类提供了画图操作的各种接口,可方便地绘制各种各样的图形。
l QPaintDevice 类提供可用于画图的空间,及画图容器。
lPaintEngine 类是抽象类,提供了QPainter 如何在指定的平台上给指定的设备绘画的抽象接口,对开发者而言,
一般不会用到。
void Widget::paintEvent(QPaintEvent *e)
{
qDebug()<<"in paintEvent"<<"recet"<rect(); //得到需要重新绘制的区域
QPainter paint(this); //定义画家(请了一个画家来画画),画在主窗口上
//画家画图片,作为背景图片
paint.drawPixmap(0,0,this->width(),this->height(),
QPixmap("../Image/bk.jpg"));
QPen pen; //定义一只画笔
pen.setColor(QColor(255,0,255)); //设置画笔的颜色
pen.setWidth(5); //设置画笔的宽度
pen.setStyle(Qt::DashDotLine); //设置画笔线条的风格
paint.setPen(pen); //画家使用这只画笔
paint.drawLine(30,30,500,30);//画家画水平的线条
paint.drawLine(30,30,30,500);//画家画垂直的线条
pen.setColor(Qt::yellow);//设置画笔的颜色
pen.setStyle(Qt::SolidLine);//设置画笔线条的风格
pen.setWidth(3);//设置线条的宽度
paint.setPen(pen);//画家使用这只画笔
QBrush brush(Qt::blue);//定义一把蓝色的画刷
brush.setStyle(Qt::DiagCrossPattern);//设置画刷的风格
paint.setBrush(brush);//画家使用这把画刷
paint.drawRect(50,50,150,200);//画家画矩形
paint.setPen(QPen());
paint.setBrush(QBrush(QColor(255,187,255),Qt::Dense3Pattern));
paint.drawEllipse(280,60,180,250);//画家画椭圆
}
//绘图事件
void Widget::*paintEvent*(QPaintEvent *)
{
QPainter p(this); //在窗口上绘图
p.drawPixmap(x,200,100,100,QPixmap("../Image/face.png"));
p.drawPixmap(i,j,100,100,QPixmap("../Image/face.png"));
}
void Widget::on_pushButton_clicked()
{
x += 20;
if(x > this->width())
{
x = 0;
}
this->update(); //刷新绘图区
}
void Widget::*mousePressEvent*(QMouseEvent *e)
{i = e->pos().x();
j = e->pos().y();
this->update(); //刷新绘图区域
}
参考学习视频