目录
- 对象树
- 示例代码
- 信号和槽
- 自定义信号和槽
- 自定义信号和槽出现重载
- lambda表达式
- 示例代码
- 第一次作业
- QMAINWINDOW
- 资源文件的添加
- 对话框
- 界面布局
- 控件
- 自定义控件封装
- 示例代码
- 鼠标事件
- 示例代码
- 定时器1
- 示例代码
- 定时器2
- event事件
- 事件过滤器
- QPainter 绘图
- 示例代码
- QPainter 高级设置
- QPainter 绘图设备
- 示例代码
- QFile
- 示例代码
- 翻金币项目
对象树
当创建一个对象在堆区时候,如果指定的父亲是QObject派生下来的类或者QObject子类派生下来的类,可以不用管理释放操作,该对象会放入到对象树中
一定程度上化简了内存回收机制
示例代码
mypushbutton.h 文件
#ifndef MYPUSHBUTTON_H
#define MYPUSHBUTTON_H
#include <QPushButton>
class MyPushButton : public QPushButton
{
Q_OBJECT
public:
explicit MyPushButton(QWidget *parent = nullptr);
~MyPushButton();
signals:
};
#endif // MYPUSHBUTTON_H
mypushbutton.cpp 文件
#include "mypushbutton.h"
#include <QDebug>
MyPushButton::MyPushButton(QWidget *parent) : QPushButton(parent)
{
qDebug() << "我的按钮调用";
}
MyPushButton::~MyPushButton()
{
qDebug() << "我的按钮析构";
}
mywidget.h 文件
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class myWidget; }
QT_END_NAMESPACE
class myWidget : public QWidget
{
Q_OBJECT // Q_OBJECT宏,允许类中使用信号和槽的机制
public:
myWidget(QWidget *parent = nullptr); // 构造函数
~myWidget(); // 析构函数
private:
Ui::myWidget *ui;
};
#endif // MYWIDGET_H
mywidget.cpp 文件
#include "mywidget.h"
#include "ui_mywidget.h"
#include "mypushbutton.h"
#include <QDebug>
#include <QPushButton> // 按钮控件的头文件
//快捷键
//注释 ctrl + /
//运行 ctrl +r
//编译 ctrl + b
//字体缩放 ctrl + 鼠标滚轮
//查找 ctrl + f
//整行移动 ctr+l + shift + 箭头
//帮助文档 F1
//自动对齐 ctrl + i
//同名之间的.h和.cpp的切换 F4
//帮助文档 D:\QT\5.14.2\mingw73_32\bin
myWidget::myWidget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::myWidget)
{
ui->setupUi(this);
// 创建一个按钮
QPushButton * btn = new QPushButton;
//btn->show(); // show以顶层方式弹出窗口控件
// 让btn对象 依赖在 myWidget 窗口中
btn->setParent(this);
// 显示文本
btn->setText("第一个按钮");
// 创建第二个按钮 按照控件的大小创建窗口
QPushButton * btn2 = new QPushButton("第二个按钮", this);
// 移动btn2按钮
btn2->move(100, 100);
// 重置窗口大小
resize(600, 400);
// 设置固定窗口大小
setFixedSize(600, 400);
// 设置窗口标题
setWindowTitle("第一个窗口");
// 创建一个自己的按钮对象
MyPushButton * myBtn = new MyPushButton;
myBtn->setText("我自己的按钮");
myBtn->move(200, 0);
myBtn->setParent(this); // 设置到对象树中
// 需求 点击我的按钮 关闭窗口
// connect (信号的发送者,发送的具体信号,信号的接受者,信号的处理(槽))
// 松散耦合:信号发送者和信号的接收者本身没有关联,通过connect连接将两端耦合在一起
// 参数1 信号的发送者 参数2 发送的信号(函数的地址) 参数3 信号的接收者 参数4 处理的槽函数
//connect(myBtn, &MyPushButton::clicked, this, &myWidget::close);
connect(myBtn, &QPushButton::clicked, this, &QWidget::close);
}
myWidget::~myWidget()
{
delete ui;
qDebug() << "myWidget的析构";
}
main 文件
#include "mywidget.h"
#include <QApplication> // 包含一个应用程序类的头文件
// 命令行变量的数目,命令行变量的内容
int main(int argc, char *argv[])
{
// a应用程序对象,在QT中,应用程序对象有且只有一个
QApplication a(argc, argv);
// 窗口对象 myWidget父类 -> QWidget
myWidget w;
w.show();
// 让应用程序对象进入消息循环,等待用户的操作
// 让代码阻塞到这行
return a.exec();
}
信号和槽
连接方式:connect
自定义信号和槽
自定义信号
- 写到signals下
- 返回void
- 需要声明,不需要实现
- 可以有参数,可以重载
自定义槽函数
- 返回void
- 需要声明,也需要实现
- 可以有参数,可以重载
- 可以写到public下
自定义信号和槽出现重载
- 需要利用函数指针,明确指向函数的地址
- void(Teacher:: *tSignal)(QString) = &Teacher::hungry;
- 信号可以连接信号
- 一个信号可以连接多个槽函数
- 信号和槽函数的参数必须类型一一对应
- 信号和槽的参数个数:信号的参数个数可以多于槽的参数个数,但是类型必须是一一对应
lambda表达式
- []标识符 匿名函数
- mutable 可以修改拷贝出的数据,改变不了本体
示例代码
widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <teacher.h>
#include <student.h>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
void classIsOver();
private:
Ui::Widget *ui;
Teacher* te;
Student* st;
};
#endif // WIDGET_H
widget.cpp 文件
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
// Teacher 类 老师类
// Student 类 学生类
// 下课后,老师会触发一个信号,饿了,学生响应信号,请客吃饭
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 创建一个老师对象
this->te = new Teacher(this);
// 创建一个学生对象
this->st = new Student(this);
// 老师饿了,学生请客的连接
// connect(te, &Teacher::hungry, st, &Student::treat);
// // 调用下课函数
// classIsOver();
// 指针 -> 地址
// 函数指针 -> 函数地址
void(Teacher:: *teacherSignal)(QString) = &Teacher::hungry;
void(Student:: *studentSlot)(QString) = &Student::treat;
connect(te, teacherSignal, st, studentSlot);
classIsOver();
// 点击一个下课按钮,再出发下课
QPushButton * btn = new QPushButton("下课", this);
// 重置窗口大小
resize(600, 400);
// 点击按钮 触发下课
// connect(btn, &QPushButton::clicked, this, &Widget::classIsOver);
// 无参的信号和槽连接
void(Teacher:: *teacherSignal2)(void) = &Teacher::hungry;
void(Student:: *studentSlot2)(void) = &Student::treat;
// 信号与信号连接,信号与槽连接
connect(te, teacherSignal2, st, studentSlot2);
connect(btn, &QPushButton::clicked, te, teacherSignal2);
// 断开信号连接
//disconnect(te, teacherSignal2, st, studentSlot2)
// 拓展
// 信号可以连接信号
// 一个信号可以连接多个槽函数
// 多个信号可以连接一个槽函数
// 信号和槽函数的参数必须类型一一对应
// 信号和槽的参数个数:信号的参数个数可以多于槽的参数个数,但是类型必须是一一对应
// QT4 版本以前的信号和槽连接方式
connect(te, SIGNAL(hungry()), st, SLOT(treat(QString)));
[=](){
// 指针指向的是同一个区域,所以值传递也可以修改
btn->setText("aaaaa");
}();
// [btn](){
// // 指针指向的是同一个区域,所以值传递也可以修改
// btn->setText("aaaaa");
// }();
// 利用lambda表达式实现点击按钮 关闭窗口
QPushButton * btn2 = new QPushButton;
btn2->setText("关闭");
btn2->move(100, 0);
btn2->setParent(this);
// connect(btn2, &QPushButton::click, this, &Widget::close);
connect(btn2, &QPushButton::clicked, this, [=](){
// this->close();
emit te->hungry("宫保鸡丁");
btn2->setText("aaa");
});
// lambda表达式 最常用 [=](){}
}
Widget::~Widget()
{
delete ui;
}
void Widget::classIsOver()
{
// 下课函数,调用后,触发老师饿了信号
// emit te->hungry();
emit te->hungry("宫保鸡丁");
}
teacher.h 文件
#ifndef TEACHER_H
#define TEACHER_H
#include <QObject>
class Teacher : public QObject
{
Q_OBJECT
public:
explicit Teacher(QObject *parent = nullptr);
signals:
// 自定义信号,写到singals下
// 返回值是void,只需要声明,不需要实现
// 可以有参数,可以重载
void hungry();
void hungry(QString foodName);
};
#endif // TEACHER_H
teacher.cpp 文件
#include "teacher.h"
Teacher::Teacher(QObject *parent) : QObject(parent)
{
}
student.h 文件
#ifndef STUDENT_H
#define STUDENT_H
#include <QObject>
class Student : public QObject
{
Q_OBJECT
public:
explicit Student(QObject *parent = nullptr);
// 返回值是void
// 需要声明,也需要实现
// 可以参数,也可以重载
void treat();
void treat(QString foodName);
signals:
};
#endif // STUDENT_H
student.cpp 文件
#include "student.h"
#include <QDebug>
Student::Student(QObject *parent) : QObject(parent)
{
}
void Student::treat()
{
qDebug() << "请客吃饭";
}
void Student::treat(QString foodName)
{
// QString -> char * 打印出来不带指针
// 先转成QByteArray(.toUtf8())再转成char *()(.data())
qDebug() << "请客吃饭,吃" << foodName.toUtf8().data();
}
main 文件
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
第一次作业
widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp 文件
#include "widget.h"
#include "ui_widget.h"
#include <QPushButton>
#include <QWidget>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
QPushButton * btn = new QPushButton("open", this);
btn->move(100, 200);
QPushButton * btn2 = new QPushButton("close", this);
btn2->move(300, 200);
resize(500, 500);
setWindowTitle("作业");
QWidget * newWidget = new QWidget;
// connect(btn, &QPushButton::clicked, newWidget, [=](){
// newWidget->show();
// });
// connect(btn2, &QPushButton::clicked, newWidget, [=](){
// newWidget->close();
// });
connect(btn, &QPushButton::clicked, newWidget, [=](){
if(btn->text()=="open"){
newWidget->show();
btn->setText("close");
}else{
newWidget->close();
btn->setText("open");
}
});
}
Widget::~Widget()
{
delete ui;
}
main 文件
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
QMAINWINDOW
示例代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMenuBar>
#include <QToolBar>
#include <QDebug>
#include <QPushButton>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 重置窗口大小
resize(600, 400);
// 菜单栏最多只能有一个
// 菜单栏创建
QMenuBar * bar = new QMenuBar();
// 将菜单栏放入到窗口中
setMenuBar(bar);
// 创建菜单
QMenu *fileMenu = bar->addMenu("文件");
QMenu *editMenu = bar->addMenu("编辑");
// 创建菜单项
QAction * newAction = fileMenu->addAction("新建");
// 添加分割线
fileMenu->addSeparator();
QAction * newAction2 = fileMenu->addAction("打开");
// 工具栏 可以有多个
QToolBar * toolBar = new QToolBar(this);
// 将工具栏放入到窗口中(修改默认停靠位置)
addToolBar(Qt::LeftToolBarArea, toolBar);
// 后期设置,只允许左右停靠
toolBar->setAllowedAreas(Qt::LeftToolBarArea|Qt::RightToolBarArea);
// 设置浮动
toolBar->setFloatable(false);
// 设置移动(总开关)
toolBar->setMovable(false);
// 工具栏中设置内容
toolBar->addAction(newAction);
// 添加分割线
toolBar->addSeparator();
toolBar->addAction(newAction2); // 相当于功能公用
// 工具栏中添加控件
QPushButton * btn = new QPushButton("aaa", this);
toolBar->addWidget(btn);
// 状态栏 最多只能有一个
QStatusBar * stBar = statusBar();
// 设置到窗口中
setStatusBar(stBar);
// 放标签控件
QLabel * label = new QLabel("提示信息", this);
stBar->addWidget(label);
QLabel * label2 = new QLabel("右侧提示信息", this);
stBar->addPermanentWidget(label2);
// 铆接部件(浮动窗口) 可以有多个(有多个的是add,只能有一个的是set)
QDockWidget *dockWidget = new QDockWidget("浮动", this);
// 将默认浮动位置设置为下面(核心窗口的下面)
addDockWidget(Qt::BottomDockWidgetArea, dockWidget);
// 设置后期停靠区域,只允许上下
dockWidget->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
// 设置中心部件 只能有一个
QTextEdit * edit = new QTextEdit(this);
setCentralWidget(edit);
}
MainWindow::~MainWindow()
{
delete ui;
}
资源文件的添加
- 将资源文件拷贝到项目位置下
- 右键项目—添加新文件—Qt—Qt resource file—给资源文件起名
- res 生成res.qrc
- open in edit 编辑资源
- 添加前缀 添加文件
- 使用 “:+ 前缀名 + 文件名”
对话框
示例代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 点击新建按钮 弹出一个对话框
connect(ui->actionnew, &QAction::triggered, [=](){
// 对话框 分类
// 模态对话框(不可以对其他窗口进行操作) 非模态对话框(可以对其他窗口进行操作)
// 模态对话框创建
// 这里不使用指针了吗 注意使用指针有可能造成内存泄露(频繁多次点击)
// QDialog * dig = new QDialog(this);
// // 设置大小
// dig->resize(200, 100);
// // 只有按x才能继续执行
// dig->exec();
// qDebug() << "模态对话框弹出了";
// 非模态对话框 必须要放到堆区中
QDialog * dig2 = new QDialog(this);
dig2->resize(200, 100);
dig2->show();
// 防止对象无限创建
dig2->setAttribute(Qt::WA_DeleteOnClose);
qDebug() << "非模态对话框弹出";
// 消息对话框
// 错误对话框
//QMessageBox::critical(this, "critial", "错误");
// 信息对话框
//QMessageBox::information(this, "info", "信息");
// 提问对话框
// 参数1 父亲 参数2 标题 参数3 提示内容 参数4 按键类型 参数5 默认关联回车按键
// 可以利用返回值判断用户的输入
// if(QMessageBox::Save == QMessageBox::question(this, "ques", "提问", QMessageBox::Save | QMessageBox::Cancel, QMessageBox::Cancel))
// {
// qDebug() << "选择的是保存";
// }else{
// qDebug() << "选择的是取消";
// }
// 警告对话框
QMessageBox::warning(this, "warning", "警告");
// 其他标准对话框
// 颜色对话框
// QColor color = QColorDialog::getColor(QColor(255, 0, 0));
// qDebug() << "r=" << color.red() << " g=" << color.green() << " b=" << color.blue();
// 文件对话框(注意要使用\\) 参数1 父亲 参数2 标题 参数3 默认打开路径 参数4 过滤文件格式
// 返回值是选取的路径
// QString str = QFileDialog::getOpenFileName(this, "打开文件", "C:\\Users\\Administrator\\Desktop", "(*.txt)");
// qDebug() << str;
// 字体对话框
bool flag;
QFont font = QFontDialog::getFont(&flag, QFont("华文彩云", 36));
qDebug() << "字体:" << font.family().toUtf8().data() << " 字号:" << font.pointSize() << " 是否加粗:" << font.bold();
});
}
MainWindow::~MainWindow()
{
delete ui;
}
界面布局
- 实现一个登录窗口
- 利用布局的方式对窗口进行美化
- 选取widget进行布局,水平布局、垂直布局、栅格布局
- 给用户名、密码、登录、退出按钮进行布局
- 默认窗口和控件之间有9像素的间隙,可以调整layoutleftMargin
- 利用弹簧进行布局
- 垂直策略设置为fixed
控件
按钮组
- QPushButton 常用按钮
- QtoolButton 工具按钮 用于显示图片,如果想提示文字,修改风格:toolButtonStyle,凸起风格:autoRaise
- radioButton 单选按钮,设置默认 ui->rBtnMan->setChecked(this)
- checkBox 多选按钮,监听状态,2选中,1半选,0未选中
QListWidget 列表容器
- QListWidgetitem * item 一行内容
- ui->listWidget->additem(item)
- 设置居中方式 item->setTextAlignment(Qt::AlignHCenter)
- 可以利用additems一次性添加整个诗内容
示例代码
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QCheckBox>
#include <QListWidget>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 设置单选按钮 男默认选中
ui->rBtnMan->setChecked(true);
// 选中女后 打印信息
connect(ui->rBtnWoman, &QRadioButton::clicked, [=](){
qDebug() << "选中了女了!";
});
// 多选按钮 2是选中,0是未选中
connect(ui->cBox, &QCheckBox::stateChanged, [=](int state){
qDebug() << state;
});
// 利用listWidfet写诗
// QListWidgetItem * item = new QListWidgetItem("锄禾日当午");
// // 将一行诗放入到listWidget中
// ui->listWidget->addItem(item);
// item->setTextAlignment(Qt::AlignHCenter);
// QStringList QList<QString>
QStringList list;
list << "锄禾日当午" << "汗滴禾下土" << "谁知盘中餐" << "粒粒皆辛苦";
ui->listWidget->addItems(list);
}
Widget::~Widget()
{
delete ui;
}
树控件
- 设置头
- 设置根节点
- 添加根节点
- 追加子节点
示例代码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// treeWidget树控件使用
// 设置水平头
ui->treeWidget->setHeaderLabels(QStringList() << "英雄" << "英雄介绍");
QTreeWidgetItem * item = new QTreeWidgetItem(QStringList() << "力量");
// 加载顶层节点
ui->treeWidget->addTopLevelItem(item);
QTreeWidgetItem * item1 = new QTreeWidgetItem(QStringList() << "敏捷");
QTreeWidgetItem * item2 = new QTreeWidgetItem(QStringList() << "智力");
ui->treeWidget->addTopLevelItem(item1);
ui->treeWidget->addTopLevelItem(item2);
// 追加子节点
QStringList heroL1;
heroL1 << "刚被猪" << "前排坦克,能在吸收伤害的同时造成可观的范围输出";
QTreeWidgetItem * l1 = new QTreeWidgetItem(heroL1);
item->addChild(l1);
}
Widget::~Widget()
{
delete ui;
}
QTableWidget 表格控件
- 设置列数
- 设置水平表头
- 设置行数
- 设置正文
示例代码
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// TableWidget控件
// 设置列数
ui->tableWidget->setColumnCount(3);
// 设置水平表头
ui->tableWidget->setHorizontalHeaderLabels(QStringList() << "姓名" << "性别" << "年龄");
// 设置行数
ui->tableWidget->setRowCount(5);
// 设置正文
ui->tableWidget->setItem(0, 0, new QTableWidgetItem("亚瑟"));
QStringList nameList;
nameList << "亚瑟" << "赵云" << "张飞" << "关羽" << "花木兰";
QList<QString> sexList;
sexList << "男" << "男" << "男" << "男" << "女";
for(int i = 0; i < 5; ++i){
int col = 0;
ui->tableWidget->setItem(i, col++, new QTableWidgetItem(nameList[i]));
ui->tableWidget->setItem(i, col++, new QTableWidgetItem(sexList.at(i)));
// int 转 QString
ui->tableWidget->setItem(i, col++, new QTableWidgetItem(QString::number(i+18)));
}
}
Widget::~Widget()
{
delete ui;
}
其他控件介绍
- stackedWidget 控件
- 下拉框
- QLabel 显示图片
- QLabel 显示动图 gif图片
示例代码
#include "widget.h"
#include "ui_widget.h"
#include <QPixmap>
#include <QMovie>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 栈控件使用
// 设置默认定位到scrollArea
ui->stackedWidget->setCurrentIndex(0);
// scrollArea按钮
connect(ui->btn_scrollArea, &QPushButton::clicked, [=](){
ui->stackedWidget->setCurrentIndex(0);
});
// toolBox按钮
connect(ui->btn_toolBox, &QPushButton::clicked, [=](){
ui->stackedWidget->setCurrentIndex(1);
});
// 下拉框
ui->comboBox->addItem("奔驰");
ui->comboBox->addItem("宝马");
ui->comboBox->addItem("拖拉机");
// 点击按钮选中拖拉机选项
connect(ui->btn_select, &QPushButton::clicked, [=](){
//ui->comboBox->setCurrentIndex(2);
ui->comboBox->setCurrentText("拖拉机");
});
// 利用QLabel显示图片
ui->label->setPixmap(QPixmap(":/image/770761.jpg"));
// 利用QLabel显示gif动态图片
QMovie * movie = new QMovie(":/");
ui->lbl_movie->setMovie(movie);
// 播放动图
movie->start();
}
Widget::~Widget()
{
delete ui;
}
自定义控件封装
- 添加一个新文件 Qt设计师界面类
- ui中设计 QSpinBox 和 QSlider 两个控件
- Widget 中使用自定义控件,拖曳一个Widget,点击提升为,点击添加,点击提升
- 实现功能,改变数字,滑动条跟着移动,信号槽监听
- 提供 getNum() 和 setNum() 接口
示例代码
Widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
Widget.cpp 文件
#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 点击获取 获取到控件当前的值
// 这里的widget就是smallwidget
connect(ui->btn_get, &QPushButton::clicked, [=](){
qDebug() << ui->widget->getNum();
});
// 设置到一半
connect(ui->btn_set, &QPushButton::clicked, [=](){
ui->widget->setNum(50);
});
}
Widget::~Widget()
{
delete ui;
}
smallWidget.h 文件
#ifndef SMALLWIDGET_H
#define SMALLWIDGET_H
#include <QWidget>
namespace Ui {
class SmallWidget;
}
class SmallWidget : public QWidget
{
Q_OBJECT
public:
explicit SmallWidget(QWidget *parent = nullptr);
~SmallWidget();
// 设置数字
void setNum(int num);
// 获取数字
int getNum();
private:
Ui::SmallWidget *ui;
};
#endif // SMALLWIDGET_H
smallWidget.cpp 文件
#include "smallwidget.h"
#include "ui_smallwidget.h"
SmallWidget::SmallWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::SmallWidget)
{
ui->setupUi(this);
// QSpinBox移动 QSlider跟着移动
void(QSpinBox:: * spSignal)(int) = &QSpinBox::valueChanged;
connect(ui->spinBox, spSignal, ui->horizontalSlider, &QSlider::setValue);
// QSlider滑动, QSpinbox数字跟着改变
connect(ui->horizontalSlider, &QSlider::valueChanged, ui->spinBox, &QSpinBox::setValue);
}
// 设置数字
void SmallWidget::setNum(int num)
{
ui->spinBox->setValue(num);
}
// 获取数字
int SmallWidget::getNum()
{
return ui->spinBox->value();
}
SmallWidget::~SmallWidget()
{
delete ui;
}
main 文件
#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
Widget w;
w.show();
return a.exec();
}
鼠标事件
- 鼠标进入事件 enterEvent
- 鼠标离开事件 leaveEvent
- 鼠标按下事件 mousePressEvent
- 鼠标释放事件 mouseReleaseEvent
- 鼠标移动事件 mouseMoveEvent
- ev->x() x坐标 ex->y() y坐标
- ex->button() 可以判断所有按键 Qt::LeftButton
- ev->buttons()判断组合按键 判断 move 时候的左右键
示例代码
myLabel.h 文件
#ifndef MYLABEL_H
#define MYLABEL_H
#include <QLabel>
class myLabel : public QLabel
{
Q_OBJECT
public:
explicit myLabel(QWidget *parent = nullptr);
// 鼠标进入事件
void enterEvent(QEvent *event) override;
// 鼠标离开事件
void leaveEvent(QEvent *) override;
// 鼠标移动事件
void mouseMoveEvent(QMouseEvent *ev) override;
// 鼠标按下事件
void mousePressEvent(QMouseEvent *ev) override;
// 鼠标释放事件
void mouseReleaseEvent(QMouseEvent *ev) override;
signals:
};
#endif // MYLABEL_H
myLabel.cpp 文件
#include "mylabel.h"
#include <QDebug>
#include <QMouseEvent>
myLabel::myLabel(QWidget *parent) : QLabel(parent)
{
// 设置鼠标追踪状态
setMouseTracking(true);
}
// 鼠标进入事件
void myLabel::enterEvent(QEvent *event)
{
//qDebug() << "鼠标进入";
}
// 鼠标离开事件
void myLabel::leaveEvent(QEvent *)
{
//qDebug() << "鼠标离开";
}
// 鼠标移动事件
void myLabel::mouseMoveEvent(QMouseEvent *ev)
{
// if(ev->buttons() & Qt::LeftButton)
// {
QString str = QString("鼠标移动 x = %1 y = %2 globalX = %3 golbalY = %4 ").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << str;
// }
}
// 鼠标按下事件
void myLabel::mousePressEvent(QMouseEvent *ev)
{
// 当鼠标左键按下 提示信息
if(ev->button() == Qt::LeftButton)
{
QString str = QString("鼠标按下 x = %1 y = %2 globalX = %3 golbalY = %4 ").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << str;
}
}
// 鼠标释放事件
void myLabel::mouseReleaseEvent(QMouseEvent *ev)
{
if(ev->button() == Qt::LeftButton)
{
QString str = QString("鼠标释放 x = %1 y = %2 globalX = %3 golbalY = %4 ").arg(ev->x()).arg(ev->y()).arg(ev->globalX()).arg(ev->globalY());
qDebug() << str;
}
}
定时器1
- 利用事件 void timerEvent( QTimerEvent * ev)
- 启动定时器 start(1000) 毫秒单位
示例代码
widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
// 重写定时器事件
void timerEvent(QTimerEvent *);
private:
Ui::Widget *ui;
int id1; // 定时器1的唯一标识
int id2; // 定时器2的唯一标识
};
#endif // WIDGET_H
widget.cpp 文件
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 启动定时器
id1 = startTimer(1000); // 参数1 间隔 单位是毫秒
id2 = startTimer(2000);
// 定时器的第二种方式
QTimer * timer = new QTimer(this);
// 启动定时器
timer->start(500);
connect(timer, &QTimer::timeout, [=](){
static int num3 = 1;
ui->label_4->setText(QString::number(num3++));
});
// 点击暂停按钮 停止定时器
connect(ui->btn, &QPushButton::clicked, [=](){
timer->stop();
});
// 给 label1 安装事件过滤器
// 步骤1 安装事件过滤器
ui->label->installEventFilter(this);
// 步骤2 重写eventfilter事件
}
Widget::~Widget()
{
delete ui;
}
void Widget::timerEvent(QTimerEvent * ev)
{
if(ev->timerId() == id1)
{
// label2每隔1秒+1
static int num = 1;
ui->label_2->setText(QString::number(num++));
}
if(ev->timerId() == id2)
{
// label3每隔2秒+1
static int num2 = 1;
ui->label_3->setText(QString::number(num2++));
}
}
定时器2
- 利用定时器类 QTimer
- 创建定时器对象 QTimer * timer = new QTimer(this)
- 启动定时器 timer->start(毫秒)
- 每个一定毫秒,发送信号, timeout,进行监听
- 暂停 timer->stop()
event事件
- 用途:用于事件分发
- 也可以做拦截操作 不建议
- bool event(QEvent * e)
- 返回值 如果是 true 代表用户处理这个事件,不向下分发了
- e->type() == 鼠标按下
事件过滤器
- 在程序将事件分发到事件分发器前,可以利用过滤器做拦截
- 步骤:1. 给控件安装事件过滤器 2. 重写eventFilter函数(obj, ev)
QPainter 绘图
- 绘图事件 void paintEvent()
- 声明一个画家对象 QPainter painter(this) this 指定绘图设备
- 画线、画圆、画矩形、画文字
- 设置画笔 QPen 设置画笔宽度、风格
- 设置画刷 QBrush 设置画刷风格
示例代码
Widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
Q_OBJECT
public:
Widget(QWidget *parent = nullptr);
~Widget();
// 绘图事件
void paintEvent(QPaintEvent *event) override;
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
Widget.cpp 文件
#include "widget.h"
#include "ui_widget.h"
#include <QPainter> // 画家类
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 点击移动按钮, 移动图片
connect(ui->pushButton, &QPushButton::clicked, [=](){
posX += 20;
// 如果要手动调用绘图事件,用update更新
update();
});
}
Widget::~Widget()
{
delete ui;
}
// 绘图事件
void Widget::paintEvent(QPaintEvent *)
{
// 实例化画家对象 this指定的是绘图的设备
QPainter painter(this);
// 设置画笔
QPen pen(QColor(255, 0, 0));
// 设置画笔的宽度
pen.setWidth(3);
pen.setStyle(Qt::DotLine);
// 让画家 使用这个笔
painter.setPen(pen);
// 设置画刷
QBrush brush(Qt::green);
// 设置画刷风格
brush.setStyle(Qt::Dense7Pattern);
// 让画家使用画刷
painter.setBrush(brush);
// 画线
painter.drawLine(QPoint(0, 0), QPoint(100, 100));
// 画圆
painter.drawEllipse(QPoint(100, 100), 50, 50);
// 画矩形
painter.drawRect(QRect(20, 20, 50, 50));
// 画文字
painter.drawText(QRect(10, 200, 150, 50), "好好学习, 天天向上");
// 高级设置
QPainter painter(this);
// painter.drawEllipse(QPoint(100, 50), 50, 50);
// // 设置抗锯齿能力 效率较低
// painter.setRenderHint(QPainter::Antialiasing);
// painter.drawEllipse(QPoint(200, 50), 50, 50);
painter.drawRect(QRect(20, 20, 50, 50));
painter.translate(100, 0);
// 保存画家状态
painter.save();
painter.drawRect(QRect(20, 20, 50, 50));
painter.translate(100, 0);
// 还原画家状态
painter.restore();
painter.drawRect(QRect(20, 20, 50, 50));
// 利用画家来画资源图片
QPainter painter(this);
// 如果超出了屏幕 从0开始
if(posX > this->width()){
posX = 0;
}
painter.drawPixmap(posX, 0, QPixmap(":/image/770761.jpg"));
}
QPainter 高级设置
- 抗锯齿 效率低 painter.setRenderHint(QPainter::Antialiasing);
- 画家进行移动 painter translate(100, 0);
- 状态保存 painter.save()
- 状态还原 painter.restore()
- 如果想手动调用绘图事件,利用update
- 利用画家画图片, painter.drawPixmap(posX, 0, QPixmap(":/image/770761.jpg"));
QPainter 绘图设备
- QPixmap QImage QBitmap(黑白色) QPicture QWidget
- QPixmap 对不同平台做了显示的优化
- QImage 可以对像素进行访问
- QPicture 记录和重现绘图指令 可以保存任意后缀名
示例代码
widget.cpp 文件
#include "widget.h"
#include "ui_widget.h"
#include <QPainter>
#include <QPixmap>
#include <QImage>
#include <QRgb>
#include <QPicture>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// Pixmap 绘图设备 专门为平台做了显示的优化
// QPixmap pix(300, 300);
// // 背景填充
// pix.fill(Qt::white);
// QPainter painter(&pix);
// painter.setPen(QPen(Qt::green));
// painter.drawEllipse(QPoint(150, 150), 100, 100);
// // 保存
// pix.save("D:\\pix.png");
// QImage 绘图设备 可以对每个像素点进行访问
// QImage img(300, 300, QImage::Format_RGB32);
// // 底色填充
// img.fill(Qt::white);
// QPainter painter(&img);
// painter.setPen(QPen(Qt::green));
// painter.drawEllipse(QPoint(150, 150), 100, 100);
// img.save("D:\\img.png");
// Qpicture 绘图设备 可以记录和重现绘图指令
QPicture pic;
QPainter painter;
painter.begin(&pic); // 开始pic上画画
painter.setPen(QPen(Qt::cyan));
painter.drawEllipse(QPoint(150, 150), 100, 100);
painter.end(); // 结束画画
pic.save("D:\\pic.zt");
}
// 绘图事件
void Widget::paintEvent(QPaintEvent *event)
{
// // 利用QImage 对像素进行修改
// QPainter painter(this);
// QImage img;
// img.load(":/image/770761.jpg");
// // 修改像素点
// for(int i = 50; i< 100; ++i){
// for(int j = 50; j<100; ++j){
// QRgb value = qRgb(255, 0, 0);
// img.setPixel(i, j, value);
// }
// }
// painter.drawImage(0, 0, img);
// 重现QPicture的绘图指令
QPainter painter(this);
QPicture pic;
pic.load("D:\\pic.zt");
painter.drawPicture(0, 0, pic);
}
Widget::~Widget()
{
delete ui;
}
QFile
- 对文件进行读写操作
- QFile file( path 文件路径)
- 读 file.open(打开方式) QIODevice::ReadOnly
- 默认支持编码格式utf-8,也可以利用编码格式类指定编码格式
示例代码
#include "widget.h"
#include "ui_widget.h"
#include <QFileDialog>
#include <QTextCodec>
Widget::Widget(QWidget *parent)
: QWidget(parent)
, ui(new Ui::Widget)
{
ui->setupUi(this);
// 点击选取文件按钮,弹出文件对话框
connect(ui->pushButton, &QPushButton::clicked, [=](){
QString path = QFileDialog::getOpenFileName(this, "打开文件", "D:\\");
// 将路径放入到LineEdit中
ui->lineEdit->setText(path);
// 编码格式类
//QTextCodec * codec = QTextCodec::codecForName("gbk");
// 读取内容 放入到textEdit中
// QFile默认支持的格式是utf-8
QFile file(path);
file.open(QIODevice::ReadOnly);
//QByteArray array = file.readAll();
QByteArray array;
while(!file.atEnd()){
array += file.readLine(); // 按行读
}
ui->textEdit->setText(array);
//ui->textEdit->setText(codec->toUnicode(array));
// 对文件对象进行关闭
file.close();
// 进行写文件
// 用追加的方式进行写
file.open(QIODevice::Append);
file.write("啊啊啊");
file.close();
// QFileInfo 文件信息类
QFileInfo info(path);
qDebug() << "大小:" << info.size() << " 后缀名:" << info.suffix() << " 文件名称:" << info.fileName() << " 文件路径:" << info.filePath();
qDebug() << "创建日期:" << info.created().toString("yyyy/MM/dd hh:mm:ss");
qDebug() << "最后修改日期:" << info.lastModified().toString("yyyy/MM/dd hh:mm:ss");
});
}
Widget::~Widget()
{
delete ui;
}
翻金币项目
1. 项目基本配置
- 设置背景图标
- 设置固定大小
- 设置项目标题
- 设置背景
- 设置背景标题
- 开始菜单 - 退出功能
2. 创建开始按钮
- 封装自定义按钮 MyPushButton
- 构造函数封装
- 测试开始按钮
- 开始制作特效
- zoom1 向下
- zoom2 向上
3. 创建选择关卡场景
- 点击开始按钮后,延时进入到 选择关卡场景
- 配置选择关卡场景(图标、标题、大小)
- 设置背景图片、设置标题、图片
- 设置返回按钮
4. 选择关卡返回按钮特效操作
- 点击后切换另一张图片
- 重写 mousePressEvent
- 重写 mouseReleaseEvent
5. 开始场景与选择关卡场景的切换
- 点击选择关卡场景的返回按钮,发送一个自定义信号
- 在主场景中监听
6. 选择关卡中的按钮创建
- 利用一个 for 循环将所有按钮布置到场景中
- 在按钮上面设置一个 QLabel 显示关卡数
- QLabel 设置大小、显示文字、对齐方式、鼠标穿透
- 给每个按钮设置一个监听点击事件
7. 翻金币场景创建
- 点击选择关卡按钮后,进入到翻金币游戏场景
- 配置翻金币游戏场景 设置标题、图标、大小、设置背景
- 实现返回按钮
- 实现三个场景之间的切换
8. 实现显示关卡的Level标签
9. 创建金币类
- 先将金币的背景图案 放入到playScene中
- 创建MyCoin自定义金币按钮类
- MyCoin::MyCoin[QString btnImg] 构造函数传入默认显示的图片金币
- 在playScene中创建所有的金币
10. 每个关卡的默认显示
- 先引入 dataConfig.h 和 dataConfig.cpp 文件到项目中
- 在 PlayScene 中写了 int GameArray[4][4]的数组 维护每个关卡的金币状态
- 初始化每个关卡的显示
11. 金币翻转特效
- 给每个硬币加属性 posX坐标 posY坐标 bool flag 正反面标志
- 给 MyCoin 加函数 changeFlag改变标志
12. 解决快速点击的效果不好
- 在 MyCoin 中加入了 isAnimation 判断 是否正在做动画条件
- 当按下 MyCoin 判断是否在做动画,如果做动画,直接return,保证金币和银币动态切换的完成效果
13. 反转周围金币
- 点击金币后,延时翻转周围金币
14. 胜利图片特效
- 将胜利图片放入到游戏场景外
- 当游戏胜利时,移动到屏幕*