by苏老师(这里二次总结)
常用的窗口类有3个
在创建Qt窗口的时候, 需要让自己的窗口类继承上述三个窗口类的其中一个
所有窗口类的基类
Qt中的控件(按钮, 输入框, 单选框…)也属于窗口, 基类都是QWidget
可以内嵌到其他窗口中: 没有边框
可以不内嵌单独显示: 独立的窗口, 有边框
新的会传递给信号的捕捉者(icon、title)
尺寸:
// 获取当前窗口的位置信息
void MainWindow::on_positionBtn_clicked()
{
QRect rect = this->frameGeometry();
qDebug() << "左上角: " << rect.topLeft()
<< "右上角: " << rect.topRight()
<< "左下角: " << rect.bottomLeft()
<< "右下角: " << rect.bottomRight()
<< "宽度: " << rect.width()
<< "高度: " << rect.height();
}
// 重新设置当前窗口的位置以及宽度, 高度
void MainWindow::on_geometryBtn_clicked()
{
int x = 100 + rand() % 500;
int y = 100 + rand() % 500;
int width = this->width() + 10;
int height = this->height() + 10;
setGeometry(x, y, width, height);
}
// 通过 move() 方法移动窗口
void MainWindow::on_moveBtn_clicked()
{
QRect rect = this->frameGeometry();
move(rect.topLeft() + QPoint(10, 20));
}
//------------- 窗口图标 -------------
// 得到当前窗口的图标
QIcon windowIcon() const;
// 构造图标对象, 参数为图片的路径
QIcon::QIcon(const QString &fileName);
// 设置当前窗口的图标
void setWindowIcon(const QIcon &icon);
//------------- 窗口标题 -------------
// 得到当前窗口的标题
QString windowTitle() const;
// 设置当前窗口的标题
void setWindowTitle(const QString &);
https://subingwen.cn/qt/qt-base-window/
对话框类, 后边的章节会具体介绍这个窗口
不能内嵌到其他窗口中
关于对话框窗口类的操作
// 对话框窗口中三个普通按钮按下之后对应的槽函数
void MyDialog::on_acceptBtn_clicked()
{
//解除阻塞,隐藏窗口
this->accept(); // exec()函数返回值为QDialog::Accepted
}
void MyDialog::on_rejectBtn_clicked()
{
//解除阻塞,隐藏窗口
this->reject(); // exec()函数返回值为QDialog::Rejected
}
void MyDialog::on_donBtn_clicked()
{
// exec()函数返回值为 done() 的参数, 并根据参数发射出对应的信号
//关闭窗口解除阻塞(可以自己指定参数)
this->done(666);
}
根据用户针对对话框窗口的按钮操作, 进行相应的逻辑处理。
这里每次点击“显示模态对话框”主窗口槽函数都会在栈区创建一个新的对话框,然后调用exec阻塞并显示,点击accept,reject,done后,阻塞结束并返回一个值,主窗口槽函数执行结束,dlg被回收
设置信号槽连接:
// 创建对话框对象
MyDialog dlg;
int ret = dlg.exec();
if(ret == QDialog::Accepted)
{
qDebug() << "accept button clicked...";
// 显示主窗口
MainWindow* w = new MainWindow;
w->show();
}
else if(ret == QDialog::Rejected)
{
qDebug() << "reject button clicked...";
// 不显示主窗口
......
......
}
else
{
// ret == 666
qDebug() << "done button clicked...";
// 根据需求进行逻辑处理
......
......
}
显示一些简单的提示框, 用于展示警告、错误、问题等信息
void MainWindow::on_msgbox_clicked()
{
QMessageBox::about(this, "about", "这是一个简单的消息提示框!!!");
QMessageBox::critical(this, "critical", "这是一个错误对话框-critical...");
int ret = QMessageBox::question(this, "question",
"你要保存修改的文件内容吗???",
QMessageBox::Save|QMessageBox::Cancel,
QMessageBox::Cancel);
if(ret == QMessageBox::Save)
{
QMessageBox::information(this, "information", "恭喜你保存成功了, o(* ̄︶ ̄*)o!!!");
}
else if(ret == QMessageBox::Cancel)
{
QMessageBox::warning(this, "warning", "你放弃了保存, ┭┮﹏┭┮ !!!");
}
}
QFileDialog 对话框类是 QDialog 类的子类, 通过这个类可以选择要打开/保存的文件或者目录
//打开一个已存在的本地目录
void MainWindow::on_filedlg_clicked()
{
QString dirName = QFileDialog::getExistingDirectory(this, "打开目录", "e:\\temp");
QMessageBox::information(this, "打开目录", "您选择的目录是: " + dirName);
}
//打开一个本地文件
void MainWindow::on_filedlg_clicked()
{
QString arg("Text files (*.txt)");
QString fileName = QFileDialog::getOpenFileName(
this, "Open File", "e:\\temp",
"Images (*.png *.jpg);;Text files (*.txt)", &arg);
QMessageBox::information(this, "打开文件", "您选择的文件是: " + fileName);
}
//打开多个本地文件
void MainWindow::on_filedlg_clicked()
{
QStringList fileNames = QFileDialog::getOpenFileNames(
this, "Open File", "e:\\temp",
"Images (*.png *.jpg);;Text files (*.txt)");
QString names;
for(int i=0; i<fileNames.size(); ++i)
{
names += fileNames.at(i) + " ";
}
QMessageBox::information(this, "打开文件(s)", "您选择的文件是: " + names);
}
关于字体的属性信息, 在QT框架中被封装到了一个叫QFont的类中
// 构造函数
QFont::QFont();
/*
参数:
- family: 本地字库中的字体名, 通过 office 等文件软件可以查看
- pointSize: 字体的字号
- weight: 字体的粗细, 有效范围为 0 ~ 99
- italic: 字体是否倾斜显示, 默认不倾斜
*/
QFont::QFont(const QString &family, int pointSize = -1, int weight = -1, bool italic = false);
// 设置字体
void QFont::setFamily(const QString &family);
// 根据字号设置字体大小
void QFont::setPointSize(int pointSize);
// 根据像素设置字体大小
void QFont::setPixelSize(int pixelSize);
// 设置字体的粗细程度, 有效范围: 0 ~ 99
void QFont::setWeight(int weight);
// 设置字体是否加粗显示
void QFont::setBold(bool enable);
// 设置字体是否要倾斜显示
void QFont::setItalic(bool enable);
// 获取字体相关属性(一般规律: 去掉设置函数的 set 就是获取相关属性对应的函数名)
QString QFont::family() const;
bool QFont::italic() const;
int QFont::pixelSize() const;
int QFont::pointSize() const;
bool QFont::bold() const;
int QFont::weight() const;
void MainWindow::on_fontdlg_clicked()
{
#if 1
// 方式1
bool ok;
QFont ft = QFontDialog::getFont(
&ok, QFont("微软雅黑", 12, QFont::Bold), this, "选择字体");
qDebug() << "ok value is: " << ok;
#else
// 方式2
QFont ft = QFontDialog::getFont(NULL);
#endif
// 将选择的字体设置给当前窗口对象
this->setFont(ft);
}
关于颜色的属性信息, 在QT框架中被封装到了一个叫QColor的类中。各种颜色都是基于红, 绿, 蓝这三种颜色调配而成的, 并且颜色还可以进行透明度设置, 默认是不透明的。
// 构造函数
QColor::QColor(Qt::GlobalColor color);
QColor::QColor(int r, int g, int b, int a = ...);
QColor::QColor();
// 参数设置 red, green, blue, alpha, 取值范围都是 0-255
void QColor::setRed(int red); // 红色
void QColor::setGreen(int green); // 绿色
void QColor::setBlue(int blue); // 蓝色
void QColor::setAlpha(int alpha); // 透明度, 默认不透明(255)
void QColor::setRgb(int r, int g, int b, int a = 255);
int QColor::red() const;
int QColor::green() const;
int QColor::blue() const;
int QColor::alpha() const;
void QColor::getRgb(int *r, int *g, int *b, int *a = nullptr) const;
====================================================
1. 在窗口上放一个标签控件
2. 通过颜色对话框选择一个颜色, 将选中的颜色显示到标签控件上
3. 将选中的颜色的 RGBA 值分别显示出来
void MainWindow::on_colordlg_clicked()
{
QColor color = QColorDialog::getColor();
QBrush brush(color);
QRect rect(0, 0, ui->color->width(), ui->color->height());
QPixmap pix(rect.width(), rect.height());
QPainter p(&pix);
p.fillRect(rect, brush);
ui->color->setPixmap(pix);
QString text = QString("red: %1, green: %2, blue: %3, 透明度: %4")
.arg(color.red()).arg(color.green()).arg(color.blue()).arg(color.alpha());
ui->colorlabel->setText(text);
}
QInputDialog类是QDialog的子类, 通过这个类我们可以得到一个输入对话框窗口, 根据实际需求我们可以在这个输入窗口中输入整形, 浮点型, 字符串类型的数据, 并且还可以显示下拉菜单供使用者选择。
和前边介绍的对话框类一样, 我们只需要调用这个类的静态成员函数就可以得到想要的窗口了。
void MainWindow::on_inputdlg_clicked()
{
int ret = QInputDialog::getInt(this, "年龄", "您的当前年龄: ", 10, 1, 100, 2);
QMessageBox::information(this, "年龄", "您的当前年龄: " + QString::number(ret));
}
QProgressDialog类是QDialog的子类, 通过这个类我们可以得到一个带进度条的对话框窗口, 这种类型的对话框窗口一般常用于文件拷贝、数据传输等实时交互的场景中。
void MainWindow::on_progressdlg_clicked()
{
// 1. 创建进度条对话框窗口对象
QProgressDialog *progress = new QProgressDialog(
"正在拷贝数据...", "取消拷贝", 0, 100, this);
// 2. 初始化并显示进度条窗口
progress->setWindowTitle("请稍后");
progress->setWindowModality(Qt::WindowModal);
progress->show();
// 3. 更新进度条
static int value = 0;
QTimer *timer = new QTimer;
connect(timer, &QTimer::timeout, this, [=]()
{
progress->setValue(value);
value++;
// 当value > 最大值的时候
if(value > progress->maximum())
{
timer->stop();
value = 0;
delete progress;
delete timer;
}
});
connect(progress, &QProgressDialog::canceled, this, [=]()
{
timer->stop();
value = 0;
delete progress;
delete timer;
});
timer->start(50);
}
关于顶级菜单可以直接在UI窗口中双击, 直接输入文本信息即可, 对应子菜单项也可以通过先双击在输入的方式完成添加, 但是这种方式不支持中文的输入.
// 给菜单栏添加菜单
QAction *QMenuBar::addMenu(QMenu *menu);
QMenu *QMenuBar::addMenu(const QString &title);
QMenu *QMenuBar::addMenu(const QIcon &icon, const QString &title);
// 给菜单对象添加菜单项(QAction)
QAction *QMenu::addAction(const QString &text);
QAction *QMenu::addAction(const QIcon &icon, const QString &text);
// 添加分割线
QAction *QMenu::addSeparator();
// save_action 是某个菜单项对象名, 点击这个菜单项会弹出一个对话框
connect(ui->save_action, &QAction::triggered, this, [=]()
{
QMessageBox::information(this, "Triggered", "我是菜单项, 你不要调戏我...");
});
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 添加第二个工具栏
QToolBar* toolbar = new QToolBar("toolbar");
this->addToolBar(Qt::LeftToolBarArea, toolbar);
// 给工具栏添加按钮和单行输入框
ui->toolBar->addWidget(new QPushButton("搜索"));
QLineEdit* edit = new QLineEdit;
edit->setMaximumWidth(200);
edit->setFixedWidth(100);
ui->toolBar->addWidget(edit);
// 添加QAction类型的菜单项
ui->toolBar->addAction(QIcon(":/er-dog"), "二狗子");
}
需要在状态栏中添加某些控件, 显示某些属性, 使用最多的就是添加标签 QLabel
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 状态栏添加子控件
// 按钮
QPushButton* button = new QPushButton("按钮");
ui->statusBar->addWidget(button);
// 标签
QLabel* label = new QLabel("hello,world");
ui->statusBar->addWidget(label);
}
停靠窗口可以通过鼠标拖动停靠到窗口的上、下、左、右,或者浮动在窗口上方。如果需要这种类型的窗口必须手动添加,如果在非QMainWindow类型的窗口中添加了停靠窗口, 那么这个窗口是不能移动和浮动的。
浮动窗口在工具栏中, 直接将其拖拽到UI界面上即可。
停靠窗口也有一个属性面板, 我们可以在其对应属性面板中直接进行设置和修改相关属性。
Qt中有内存回收机制, 但是不是所有被new出的对象被自动回收, 满足条件才可以回收
需要满足:
// 方式1: 通过构造函数
// parent: 当前窗口的父对象, 找构造函数中的 parent 参数即可
QWidget::QWidget(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags());
QTimer::QTimer(QObject *parent = nullptr);
// 方式2: 通过setParent()方法
// 假设这个控件没有在构造的时候指定符对象, 可以调用QWidget的api指定父窗口对象
void QWidget::setParent(QWidget *parent);
void QObject::setParent(QObject *parent);
通过构造函数使用,可以一次性插入多条数据(调用qDebug函数)
如果想将数据输出到控制台,需要修改项目文件,重新构建后执行
也可以在debug目录双击,方便外面程序程序调试
c语言中 char*的升级版本。我们在使用这种类型的时候可通过这个类的构造函数申请一块动态内存,用于存储我们需要处理的字符串数据
//一、构造函数
// 构造空对象, 里边没有数据
QByteArray::QByteArray();
// 将data中的size个字符进行构造, 得到一个字节数组对象
// 如果 size==-1 函数内部自动计算字符串长度, 计算方式为: strlen(data)
QByteArray::QByteArray(const char *data, int size = -1);
// 构造一个长度为size个字节, 并且每个字节值都为ch的字节数组
QByteArray::QByteArray(int size, char ch);
尾部、头部增加,插入任意位置,删除(位置,个数;n个;从位置截断;清空),替换
//二、数据操作
// 在尾部追加数据
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::append(const QByteArray &ba);//QT风格
void QByteArray::push_back(const QByteArray &other);//STL风格
// 头部添加数据
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::prepend(const QByteArray &ba);
void QByteArray::push_front(const QByteArray &other);
// 插入数据, 将ba插入到数组第 i 个字节的位置(从0开始)
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::insert(int i, const QByteArray &ba);
// 删除数据
// 从大字符串中删除len个字符, 从第pos个字符的位置开始删除
QByteArray &QByteArray::remove(int pos, int len);
// 从字符数组的尾部删除 n 个字节
void QByteArray::chop(int n);
// 从字节数组的 pos 位置将数组截断 (前边部分留下, 后边部分被删除)
void QByteArray::truncate(int pos);
// 将对象中的数据清空, 使其为null
void QByteArray::clear();
// 字符串替换
// 将字节数组中的 子字符串 before 替换为 after
QByteArray &QByteArray::replace(const QByteArray &before, const QByteArray &after);
是否包含;以…开始(起始位置);以…结尾
// 判断字节数组中是否包含子字符串 ba, 包含返回true, 否则返回false
bool QByteArray::contains(const QByteArray &ba) const; //QT
bool QByteArray::contains(const char *ba) const; //C++
// 判断字节数组中是否包含子字符 ch, 包含返回true, 否则返回false
bool QByteArray::contains(char ch) const;
// 判断字节数组是否以字符串 ba 开始, 是返回true, 不是返回false
bool QByteArray::startsWith(const QByteArray &ba) const;
bool QByteArray::startsWith(const char *ba) const;
// 判断字节数组是否以字符 ch 开始, 是返回true, 不是返回false
bool QByteArray::startsWith(char ch) const;
// 判断字节数组是否以字符串 ba 结尾, 是返回true, 不是返回false
bool QByteArray::endsWith(const QByteArray &ba) const;
bool QByteArray::endsWith(const char *ba) const;
// 判断字节数组是否以字符 ch 结尾, 是返回true, 不是返回false
bool QByteArray::endsWith(char ch) const;
迭代器;数组
// 使用迭代器
iterator QByteArray::begin();
iterator QByteArray::end();
// 使用数组的方式进行遍历
// i的取值范围 0 <= i < size()
char QByteArray::at(int i) const;
char QByteArray::operator[](int i) const;
字符的个数;count有参数(出现次数)
// 返回字节数组对象中字符的个数
int QByteArray::length() const;
int QByteArray::size() const;
int QByteArray::count() const;
// 返回字节数组对象中 子字符串ba 出现的次数
int QByteArray::count(const QByteArray &ba) const;
int QByteArray::count(const char *ba) const;
// 返回字节数组对象中 字符串ch 出现的次数
int QByteArray::count(char ch) const;
data();setNum;静态方法
// 将QByteArray类型的字符串 转换为 char* 类型
char *QByteArray::data();
const char *QByteArray::data() const;
// int, short, long, float, double -> QByteArray
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QByteArray &QByteArray::setNum(int n, int base = 10);//传进来的数是10进制的
QByteArray &QByteArray::setNum(short n, int base = 10);
QByteArray &QByteArray::setNum(qlonglong n, int base = 10);
QByteArray &QByteArray::setNum(float n, char f = 'g', int prec = 6);//使用科学计数法g,prec精度
QByteArray &QByteArray::setNum(double n, char f = 'g', int prec = 6);
[static] QByteArray QByteArray::number(int n, int base = 10);
[static] QByteArray QByteArray::number(qlonglong n, int base = 10);
[static] QByteArray QByteArray::number(double n, char f = 'g', int prec = 6);
// QByteArray -> int, short, long, float, double
int QByteArray::toInt(bool *ok = Q_NULLPTR, int base = 10) const;//ok判断转换是否成功,看是T还是F,没有必要指定;base多少进制转换
short QByteArray::toShort(bool *ok = Q_NULLPTR, int base = 10) const;
long QByteArray::toLong(bool *ok = Q_NULLPTR, int base = 10) const;
float QByteArray::toFloat(bool *ok = Q_NULLPTR) const;
double QByteArray::toDouble(bool *ok = Q_NULLPTR) const;
// std::string -> QByteArray
[static] QByteArray QByteArray::fromStdString(const std::string &str);
// QByteArray -> std::string
std::string QByteArray::toStdString() const;
// 所有字符转换为大写
QByteArray QByteArray::toUpper() const;
// 所有字符转换为小写
QByteArray QByteArray::toLower() const;
QString也是封装了字符串, 但是内部的编码为utf8, UTF-8属于Unicode字符集, 它固定使用多个字节(window为2字节, linux为3字节)来表示一个字符,这样可以将世界上几乎所有语言的常用字符收录其中。
深度构造,深层次封装(外面还有一层)
// 构造一个空字符串对象
QString::QString();
// 将 char* 字符串 转换为 QString 类型
QString::QString(const char *str);
// 将 QByteArray 转换为 QString 类型
QString::QString(const QByteArray &ba);
// 其他重载的同名构造函数可参考Qt帮助文档, 此处略
增加,删除,替换
// 尾部追加数据
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString &QString::append(const QString &str);
QString &QString::append(const char *str);
QString &QString::append(const QByteArray &ba);
void QString::push_back(const QString &other);
// 头部添加数据
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString &QString::prepend(const QString &str);
QString &QString::prepend(const char *str);
QString &QString::prepend(const QByteArray &ba);
void QString::push_front(const QString &other);
// 插入数据, 将 str 插入到字符串第 position 个字符的位置(从0开始)
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString &QString::insert(int position, const QString &str);
QString &QString::insert(int position, const char *str);
QString &QString::insert(int position, const QByteArray &str);
// 删除数据
// 从大字符串中删除len个字符, 从第pos个字符的位置开始删除
QString &QString::remove(int position, int n);
// 从字符串的尾部删除 n 个字符
void QString::chop(int n);
// 从字节串的 position 位置将字符串截断 (前边部分留下, 后边部分被删除)
void QString::truncate(int position);
// 将对象中的数据清空, 使其为null
void QString::clear();
// 字符串替换
// 将字节数组中的 子字符串 before 替换为 after
// 参数 cs 为是否区分大小写, 默认区分大小写
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString &QString::replace(const QString &before, const QString &after, Qt::CaseSensitivity cs = Qt::CaseSensitive);
包含子字符串;以…开始/结尾
// 参数 cs 为是否区分大小写, 默认区分大小写
// 其他重载的同名函数可参考Qt帮助文档, 此处略
// 判断字符串中是否包含子字符串 str, 包含返回true, 否则返回false
bool QString::contains(const QString &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
// 判断字符串是否以字符串 ba 开始, 是返回true, 不是返回false
bool QString::startsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
// 判断字符串是否以字符串 ba 结尾, 是返回true, 不是返回false
bool QString::endsWith(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
// 使用迭代器
iterator QString::begin();
iterator QString::end();
// 使用数组的方式进行遍历
// i的取值范围 0 <= position < size()
const QChar QString::at(int position) const
const QChar QString::operator[](int position) const;
查看字节数
// 返回字节数组对象中字符的个数 (字符个数和字节个数是不同的概念)
int QString::length() const;
int QString::size() const;
int QString::count() const;
// 返回字节串对象中 子字符串 str 出现的次数
// 参数 cs 为是否区分大小写, 默认区分大小写
int QString::count(const QStringRef &str, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
// 将int, short, long, float, double 转换为 QString 类型
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString &QString::setNum(int n, int base = 10);
QString &QString::setNum(short n, int base = 10);
QString &QString::setNum(long n, int base = 10);
QString &QString::setNum(float n, char format = 'g', int precision = 6);
QString &QString::setNum(double n, char format = 'g', int precision = 6);
[static] QString QString::number(long n, int base = 10);
[static] QString QString::number(int n, int base = 10);
[static] QString QString::number(double n, char format = 'g', int precision = 6);//g科学计数法;精度
// 将 QString 转换为 int, short, long, float, double 类型
int QString::toInt(bool *ok = Q_NULLPTR, int base = 10) const;
short QString::toShort(bool *ok = Q_NULLPTR, int base = 10) const;
long QString::toLong(bool *ok = Q_NULLPTR, int base = 10) const
float QString::toFloat(bool *ok = Q_NULLPTR) const;
double QString::toDouble(bool *ok = Q_NULLPTR) const;
// 将标准C++中的 std::string 类型 转换为 QString 类型
[static] QString QString::fromStdString(const std::string &str);
// 将 QString 转换为 标准C++中的 std::string 类型
std::string QString::toStdString() const;
// QString -> QByteArray
// 转换为本地编码, 跟随操作系统
QByteArray QString::toLocal8Bit() const;
// 转换为 Latin-1 编码的字符串 不支持中文
QByteArray QString::toLatin1() const;
// 转换为 utf8 编码格式的字符串 (常用)
QByteArray QString::toUtf8() const;
// 所有字符转换为大写
QString QString::toUpper() const;
// 所有字符转换为小写
QString QString::toLower() const;
// 其他重载的同名函数可参考Qt帮助文档, 此处略
QString QString::arg(const QString &a,
int fieldWidth = 0,
QChar fillChar = QLatin1Char( ' ' )) const;
QString QString::arg(int a, int fieldWidth = 0,
int base = 10,
QChar fillChar = QLatin1Char( ' ' )) const;
// 示例程序
int i; // 假设该变量表示当前文件的编号
int total; // 假设该变量表示文件的总个数
QString fileName; // 假设该变量表示当前文件的名字
// 使用以上三个变量拼接一个动态字符串
QString status = QString("Processing file %1 of %2: %3")
.arg(i).arg(total).arg(fileName);
类似于之前的联合体
QVariant这个类很神奇,或者说方便。很多时候,需要几种不同的数据类型需要传递,如果用结构体,又不大方便,容器保存的也只是一种数据类型,而QVariant则可以统统搞定。
QVariant 这个类型充当着最常见的数据类型的联合。 QVariant 可以保存很多Qt的数据类型,包括QBrush、QColor、QCursor、QDateTime、QFont、QKeySequence、 QPalette、QPen、QPixmap、QPoint、QRect、QRegion、QSize和QString,并且还有C++基本类型,如 int、float等
// 如果要实现该操作, 可以使用QVariant类提供的 toxxx() 方法, 全部转换可以参考Qt帮助文档
// 在此举列举几个常用函数:
bool QVariant::toBool() const;
QByteArray QVariant::toByteArray() const;
double QVariant::toDouble(bool *ok = Q_NULLPTR) const;
float QVariant::toFloat(bool *ok = Q_NULLPTR) const;
int QVariant::toInt(bool *ok = Q_NULLPTR) const;
QString QVariant::toString() const;
......
type得到类型(实际上用的QMetatype类型)
toXXX类型转换
setValue:实际数值设置(QVariant()构造空对象结合,使用setValue设置)
fromValue:得到
第一步: 在头文件中声明
// *.h
struct MyTest
{
int id;
QString name;
};
// 自定义类型注册
Q_DECLARE_METATYPE(MyTest)
第二步: 在源文件中定义
初始化完成后进行打包
MyTest t;
t.name = "张三丰";
t.num = 666;
// 值的封装
QVariant vt = QVariant::fromValue(t);
// 值的读取
if(vt.canConvert<MyTest>())
{
MyTest t = vt.value<MyTest>();
qDebug() << "name: " << t.name << ", num: " << t.num;
}
以上操作用到的QVariant类的API如下:
// 如果当前QVariant对象可用转换为对应的模板类型 T, 返回true, 否则返回false
bool QVariant::canConvert() const;
// 将当前QVariant对象转换为实际的 T 类型
T QVariant::value() const;
QPoint类封装了我们常用用到的坐标点 (x, y)
QLine是一个直线类, 封装了两个坐标点 (两点确定一条直线)
在QT中QSize类用来形容长度和宽度
在Qt中使用 QRect类来描述一个矩形
// 构造函数
// 构造一个坐标原点, 即(0, 0)
QPoint::QPoint();
// 参数为 x轴坐标, y轴坐标
QPoint::QPoint(int xpos, int ypos);
// 设置x轴坐标
void QPoint::setX(int x);
// 设置y轴坐标
void QPoint::setY(int y);
// 得到x轴坐标的 拷贝
int QPoint::x() const;
// 得到x轴坐标的 引用
int &QPoint::rx();
// 得到y轴坐标
int QPoint::y() const;
// 得到y轴坐标的引用
int &QPoint::ry();
// 直接通过坐标对象进行算术运算: 加减乘除
QPoint &QPoint::operator*=(float factor);
QPoint &QPoint::operator*=(double factor);
QPoint &QPoint::operator*=(int factor);
QPoint &QPoint::operator+=(const QPoint &point);
QPoint &QPoint::operator-=(const QPoint &point);
QPoint &QPoint::operator/=(qreal divisor);
=====================================================QLine
// 构造函数
// 构造一个空对象
QLine::QLine();
// 构造一条直线, 通过两个坐标点(起点终点)
QLine::QLine(const QPoint &p1, const QPoint &p2);
// 从点 (x1, y1) 到 (x2, y2)
QLine::QLine(int x1, int y1, int x2, int y2);
// 给直线对象设置坐标点
void QLine::setPoints(const QPoint &p1, const QPoint &p2);
// 起始点(x1, y1), 终点(x2, y2)
void QLine::setLine(int x1, int y1, int x2, int y2);
// 设置直线的起点坐标
void QLine::setP1(const QPoint &p1);
// 设置直线的终点坐标
void QLine::setP2(const QPoint &p2);
// 返回直线的起始点坐标
QPoint QLine::p1() const;
// 返回直线的终点坐标
QPoint QLine::p2() const;
// 返回值直线的中心点坐标, (p1() + p2()) / 2
QPoint QLine::center() const;
// 返回值直线起点的 x 坐标
int QLine::x1() const;
// 返回值直线终点的 x 坐标
int QLine::x2() const;
// 返回值直线起点的 y 坐标
int QLine::y1() const;
// 返回值直线终点的 y 坐标
int QLine::y2() const;
// 用给定的坐标点 平移 这条直线(无返回值)
void QLine::translate(const QPoint &offset);//平移过程中的偏移量
void QLine::translate(int dx, int dy);
// 用给定的坐标点平移这条直线, 返回平移之后的坐标点(得到新的直线的位置)
QLine QLine::translated(const QPoint &offset) const;
QLine QLine::translated(int dx, int dy) const;
// 直线对象进行比较
bool QLine::operator!=(const QLine &line) const;
bool QLine::operator==(const QLine &line) const;
========================================================QSize
// 构造函数
// 构造空对象, 对象中的宽和高都是无效的
QSize::QSize();
// 使用宽和高构造一个有效对象
QSize::QSize(int width, int height);
// 设置宽度
void QSize::setWidth(int width)
// 设置高度
void QSize::setHeight(int height);
// 得到宽度
int QSize::width() const;
// 得到宽度的 引用
int &QSize::rwidth();
// 得到高度
int QSize::height() const;
// 得到高度的 引用
int &QSize::rheight();
// 交换 高度和宽度 的值
void QSize::transpose();
// 交换高度和宽度的值, 返回交换之后的尺寸信息
QSize QSize::transposed() const;
// 进行算法运算: 加减乘除
QSize &QSize::operator*=(qreal factor);
QSize &QSize::operator+=(const QSize &size);
QSize &QSize::operator-=(const QSize &size);
QSize &QSize::operator/=(qreal divisor);
========================================================QRect
// 构造函数
// 构造一个 空对象(没有矩形信息)
QRect::QRect();
// 基于 左上角坐标 和 右下角坐标 构造一个矩形对象
QRect::QRect(const QPoint &topLeft, const QPoint &bottomRight);
// 基于左上角坐标, 和 宽度, 高度构造一个矩形对象
QRect::QRect(const QPoint &topLeft, const QSize &size);
// 通过 左上角坐标(x, y), 和 矩形尺寸(width, height) 构造一个矩形对象
QRect::QRect(int x, int y, int width, int height);
//得到各个点的坐标
// 设置矩形的尺寸信息, 左上角坐标不变
void QRect::setSize(const QSize &size);
// 设置矩形左上角坐标为(x,y), 大小为(width, height)
void QRect::setRect(int x, int y, int width, int height);
// 设置矩形宽度
void QRect::setWidth(int width);
// 设置矩形高度
void QRect::setHeight(int height);
// 返回值矩形左上角坐标
QPoint QRect::topLeft() const;
// 返回矩形右上角坐标
// 该坐标点值为: QPoint(left() + width() -1, top())
QPoint QRect::topRight() const;
// 返回矩形左下角坐标
// 该坐标点值为: QPoint(left(), top() + height() - 1)
QPoint QRect::bottomLeft() const;
// 返回矩形右下角坐标
// 该坐标点值为: QPoint(left() + width() -1, top() + height() - 1)
QPoint QRect::bottomRight() const;
// 返回矩形中心点坐标
QPoint QRect::center() const;
// 返回矩形上边缘y轴坐标
int QRect::top() const;
int QRect::y() const;
// 返回值矩形下边缘y轴坐标
int QRect::bottom() const;
// 返回矩形左边缘 x轴坐标
int QRect::x() const;
int QRect::left() const;
// 返回矩形右边缘x轴坐标
int QRect::right() const;
// 返回矩形的高度
int QRect::width() const;
// 返回矩形的宽度
int QRect::height() const;
// 返回矩形的尺寸信息
QSize QRect::size() const;
QData 年月日
QTime 时分秒
QDataTime 年月日时分秒
可以封装日期信息也可以通过这个类得到日期相关的信息, 包括:年, 月, 日。
// 构造函数
QDate::QDate();
QDate::QDate(int y, int m, int d);
// 公共成员函数
// 重新设置 日期对象中的日期(之前设置的会被覆盖)
bool QDate::setDate(int year, int month, int day);
// 给日期对象 添加 ndays 天(比如加10天)
QDate QDate::addDays(qint64 ndays) const;
// 给日期对象 添加 nmonths 月
QDate QDate::addMonths(int nmonths) const;
// 给日期对象 添加 nyears 月
QDate QDate::addYears(int nyears) const;
// 得到 日期对象中的年/月/日
int QDate::year() const;
int QDate::month() const;
int QDate::day() const;
void QDate::getDate(int *year, int *month, int *day) const;
// 日期对象格式化
/*
d - The day as a number without a leading zero (1 to 31)
dd(两位日期) - The day as a number with a leading zero (01 to 31)
ddd(当前星期几) - The abbreviated localized day name (e.g. 'Mon' to 'Sun'). Uses the system locale to localize the name, i.e. QLocale::system().
dddd(当前星期的全拼) - The long localized day name (e.g. 'Monday' to 'Sunday'). Uses the system locale to localize the name, i.e. QLocale::system().
M - The month as a number without a leading zero (1 to 12)
MM - The month as a number with a leading zero (01 to 12)
MMM(月份对应英文简写) - The abbreviated localized month name (e.g. 'Jan' to 'Dec'). Uses the system locale to localize the name, i.e. QLocale::system().
MMMM(月份对应英文全拼) - The long localized month name (e.g. 'January' to 'December'). Uses the system locale to localize the name, i.e. QLocale::system().
yy - The year as a two digit number (00 to 99)
yyyy - The year as a four digit number. If the year is negative, a minus sign is prepended, making five characters.
*/
//格式化
QString QDate::toString(const QString &format) const;
// 操作符重载 ==> 日期比较
bool QDate::operator!=(const QDate &d) const;
bool QDate::operator<(const QDate &d) const;
bool QDate::operator<=(const QDate &d) const;
bool QDate::operator==(const QDate &d) const;
bool QDate::operator>(const QDate &d) const;
bool QDate::operator>=(const QDate &d) const;
// 静态函数 -> 得到本地的当前日期(跟随操作系统)
[static] QDate QDate::currentDate();
QTime类可以封装时间信息也可以通过这个类得到时间相关的信息, 包括:时, 分, 秒, 毫秒。
两种方式得到当前时间:
// 构造函数
QTime::QTime();
/*
h ==> 取值范围: 0 ~ 23
m and s ==> 取值范围: 0 ~ 59
ms ==> 取值范围: 0 ~ 999
*/
//通过参数指定时间
QTime::QTime(int h, int m, int s = 0, int ms = 0);
// 公共成员函数
// Returns true if the set time is valid; otherwise returns false.
bool QTime::setHMS(int h, int m, int s, int ms = 0);//初始化、数据重置
QTime QTime::addSecs(int s) const;
QTime QTime::addMSecs(int ms) const;
// 示例代码
QTime n(14, 0, 0); // n == 14:00:00
QTime t;
//加时间(负数相当于减)
t = n.addSecs(70); // t == 14:01:10
t = n.addSecs(-70); // t == 13:58:50
t = n.addSecs(10 * 60 * 60 + 5); // t == 00:00:05
t = n.addSecs(-15 * 60 * 60); // t == 23:00:00
// 从时间对象中取出 时/分/秒/毫秒
// Returns the hour part (0 to 23) of the time. Returns -1 if the time is invalid.
int QTime::hour() const;
// Returns the minute part (0 to 59) of the time. Returns -1 if the time is invalid.
int QTime::minute() const;
// Returns the second part (0 to 59) of the time. Returns -1 if the time is invalid.
int QTime::second() const;
// Returns the millisecond part (0 to 999) of the time. Returns -1 if the time is invalid.
int QTime::msec() const;
// 时间格式化
/*
-- 时 --
h ==> The hour without a leading zero (0 to 23 or 1 to 12 if AM/PM display)
hh(显示两位,前面有0) ==> The hour with a leading zero (00 to 23 or 01 to 12 if AM/PM display)
H ==> The hour without a leading zero (0 to 23, even with AM/PM display)
HH ==> The hour with a leading zero (00 to 23, even with AM/PM display)
-- 分 --
m ==> The minute without a leading zero (0 to 59)
mm ==> The minute with a leading zero (00 to 59)
-- 秒 --
s ==> The whole second, without any leading zero (0 to 59)
ss ==> The whole second, with a leading zero where applicable (00 to 59)
-- 毫秒 --
zzz ==> The fractional part of the second, to millisecond precision,
including trailing zeroes where applicable (000 to 999).
-- 上午或者下午
AM or A ==> 使用AM/PM(大写) 描述上下午, 中文系统显示汉字
am or a ==> 使用am/pm(小写) 描述上下午, 中文系统显示汉字
*/
QString QTime::toString(const QString &format) const;
// 阶段性计时
// 过时的API函数
// 开始计时
void QTime::start();
// 计时结束
int QTime::elapsed() const;
// 重新计时
int QTime::restart();
// 推荐使用的API函数
// QElapsedTimer 类
void QElapsedTimer::start();
qint64 QElapsedTimer::restart();
qint64 QElapsedTimer::elapsed() const;
// 操作符重载 ==> 时间比较
bool QTime::operator!=(const QTime &t) const;
bool QTime::operator<(const QTime &t) const;
bool QTime::operator<=(const QTime &t) const;
bool QTime::operator==(const QTime &t) const;
bool QTime::operator>(const QTime &t) const;
bool QTime::operator>=(const QTime &t) const;
// 静态函数 -> 得到当前时间
[static] QTime QTime::currentTime();
QDateTime类可以封装日期和时间信息也可以通过这个类得到日期和时间相关的信息, 包括:年, 月, 日, 时, 分, 秒, 毫秒。其实这个类就是QDate 和 QTime 这两个类的结合体。
// 构造函数
QDateTime::QDateTime();
QDateTime::QDateTime(const QDate &date, const QTime &time, Qt::TimeSpec spec = Qt::LocalTime);//初始化日期,时间
// 公共成员函数
// 设置日期
void QDateTime::setDate(const QDate &date);
// 设置时间
void QDateTime::setTime(const QTime &time);
// 给当前日期对象追加 年/月/日/秒/毫秒, 参数可以是负数
QDateTime QDateTime::addYears(int nyears) const;
QDateTime QDateTime::addMonths(int nmonths) const;
QDateTime QDateTime::addDays(qint64 ndays) const;
QDateTime QDateTime::addSecs(qint64 s) const;
QDateTime QDateTime::addMSecs(qint64 msecs) const;
// 得到对象中的日期
QDate QDateTime::date() const;
// 得到对象中的时间
QTime QDateTime::time() const;
// 日期和时间格式, 格式字符参考QDate 和 QTime 类的 toString() 函数
QString QDateTime::toString(const QString &format) const;
// 操作符重载 ==> 日期时间对象的比较
bool QDateTime::operator!=(const QDateTime &other) const;
bool QDateTime::operator<(const QDateTime &other) const;
bool QDateTime::operator<=(const QDateTime &other) const;
bool QDateTime::operator==(const QDateTime &other) const;
bool QDateTime::operator>(const QDateTime &other) const;
bool QDateTime::operator>=(const QDateTime &other) const;
// 静态函数
// 得到当前时区的日期和时间(本地设置的时区对应的日期和时间)
[static] QDateTime QDateTime::currentDateTime();
窗口程序的处理过程中, 经常要周期性的执行某些操作, 或者制作一些动画效果,看似比较复杂的问题使用定时器就可以完美的解决这些问题, Qt中提供了两种定时器方式一种是使用Qt中的事件处理函数,一种是Qt中的定时器类 QTimer。要使用它,只需创建一个QTimer类对象,然后调用其 start() 函数开启定时器,此后QTimer对象就会周期性的发出 timeout() 信号。
===>固定频率的切换
// 构造函数
// 如果指定了 父对象, 创建的堆内存可以自动析构(到对象树上)
QTimer::QTimer(QObject *parent = nullptr);
// 设置定时器时间间隔为 msec 毫秒
// 默认值是0,一旦窗口系统事件队列中的所有事件都已经被处理完,一个时间间隔为0的QTimer就会触发
void QTimer::setInterval(int msec);//(指定时间间隔),时间间隔到达后发出timeout信号
// 获取定时器的时间间隔, 返回值单位: 毫秒
int QTimer::interval() const;
//启动
// 根据指定的时间间隔启动或者重启定时器, 需要调用 setInterval() 设置时间间隔
[slot] void QTimer::start();
// 启动或重新启动定时器,超时间隔为msec毫秒。
[slot] void QTimer::start(int msec);//时间间隔
// 停止定时器。
[slot] void QTimer::stop();
// 设置 定时器精度(精度高,程序执行效率降低)
/*
参数:
- Qt::PreciseTimer -> 精确的精度, 毫秒级
- Qt::CoarseTimer -> 粗糙的精度, 和1毫秒的误差在5%的范围内, 默认精度
- Qt::VeryCoarseTimer -> 非常粗糙的精度, 精度在1秒左右
*/
//获取和设置
void QTimer::setTimerType(Qt::TimerType atype);
Qt::TimerType QTimer::timerType() const; // 获取当前定时器的精度
// 如果定时器正在运行,返回true; 否则返回false。
bool QTimer::isActive() const;
// 判断定时器是否 只触发一次
bool QTimer::isSingleShot() const;
// 设置定时器是否 只触发一次, 参数为true定时器只触发一次, 为false定时器 重复触发, 默认为false
void QTimer::setSingleShot(bool singleShot);
setInterval(指定时间间隔),时间间隔到达后发出timeout信号
这个类的信号只有一个, 当定时器超时时,该信号就会被发射出来。给这个信号通过conect()关联一个槽函数, 就可以在槽函数中处理超时事件了。
[signal] void QTimer::timeout();
静态函数,直接通过类名调用(不用创建定时器对象)
// 其他同名重载函数可以自己查阅帮助文档
/*
功能: 在msec毫秒后发射一次信号, 并且只发射一次
参数:
- msec: 在msec毫秒后发射信号
- receiver: 接收信号的对象地址
- method: 槽函数地址
*/
//多久后发送, 接收者,
[static] void QTimer::singleShot(
int msec, const QObject *receiver,
PointerToMemberFunction method);
点击开始,启动定时器,timer获取当前时间,并对时间进行显示(timeout)
当timer发出timeout信号,让 this对象接收该信号,通过匿名函数对信号处理(获取当前时间,并对时间进行显示)
当前系统时间,格式化,显示到当前时间控件里面(setText)
// 创建定时器对象
QTimer* timer = new QTimer(this);
// 修改定时器对象的精度(PreciseTimer精度要求特别高)
timer->setTimerType(Qt::PreciseTimer);
// 按钮 loopBtn 的点击事件
// 点击按钮启动或者关闭定时器, 定时器启动, 周期性得到当前时间
connect(ui->loopBtn, &QPushButton::clicked, this, [=]()
{
// 启动定时器
if(timer->isActive())//如果定时器正在工作,关闭
{
timer->stop(); // 关闭定时器
ui->loopBtn->setText("开始");
}
else//如果定时器没有在工作,启动定时器(标题改为关闭)
{
ui->loopBtn->setText("关闭");
timer->start(1000); // 1000ms == 1s(定时周期,多长时间触发一次)
}
});
// !!!! timer获取当前时间,并对时间进行显示(timeout)
connect(timer, &QTimer::timeout, this, [=]()
{
QTime tm = QTime::currentTime();//当前系统时间
// 格式化 当前得到的系统时间
QString tmstr = tm.toString("hh:mm:ss.zzz");
// 设置要显示的时间
ui->curTime->setText(tmstr);
});
// 点击按钮 onceBtn 只发射一次信号
// 点击按钮一次, 发射一个信号, 得到某一个时间点的时间
connect(ui->onceBtn, &QPushButton::clicked, this, [=]()
{
// 获取2s以后的系统时间, 不创建定时器对象, 直接使用类的静态方法
QTimer::singleShot(2000, this, [=](){
QTime tm = QTime::currentTime();
// 格式化当前得到的系统时间
QString tmstr = tm.toString("hh:mm:ss.zzz");
// 设置要显示的时间
ui->onceTime->setText(tmstr);
});
});
信号处理机制。所谓信号槽,实际就是观察者模式(发布-订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发。
信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号,以此对用户的挑选做出反应。
不是谁都可以带我女朋友吃饭==>因此需要将信号和槽连接到一起connect。连接信号和槽的connect()函数原型如下, 其中PointerToMemberFunction是一个指向函数地址的指针
// 信号发出者地址,(函数指针)指向发出函数地址,信号接收者地址,(函数指针)指向槽函数地址,有默认值
QMetaObject::Connection QObject::connect(
const QObject *sender, PointerToMemberFunction signal,
const QObject *receiver, PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection);
参数:
- sender: 发出信号的对象
- signal: 属于sender对象, 信号是一个函数, 这个参数的类型是函数
指针, 信号函数地址
- receiver: 信号接收者
- method: 属于receiver对象, 当检测到sender发出了signal信号,
receiver对象调用method方法,信号发出之后的处理动作
// 参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
//信号发出者,发出信号(写信号的地址),信号接收者(需要处理信号),处理动作
connect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);
connect函数相当于做信号处理动作的注册
调用conenct函数的sender对象的信号并没有产生, 因此receiver对象的method也不会被调用
method槽函数本质是一个回调函数, 调用的时机是信号产生之后, 调用是Qt框架来执行的
connect中的sender和recever两个指针必须被实例化了, 否则conenct不会成功
ps:信号槽是可以被继承的,如果当前类没有signal(如QPushButton),就要去看这个类的父类(QAbstractButton),就可以看见他的信号了
掌握标准信号、槽的查找方式之后以及connect()函数的作用之后, 下面通过一个简单的例子给大家讲解一下他们的使用方式。
功能实现: 点击窗口上的按钮, 关闭窗口
功能分析:
- 按钮: 信号发出者 -> QPushButton 类型
- 窗口: 信号的接收者和处理者 -> QWidget 类型
需要使用的标准信号槽函数
// 单击 按钮发出的信号
[signal] void QAbstractButton::clicked(bool checked = false)
// 关闭 窗口的槽函数
[slot] bool QWidget::close();
对于上边的需求只需要一句代码, 只需要写一句代码就能实现了
// 单击按钮关闭窗口
connect(ui->closewindow, &QPushButton::clicked, this, &MainWindow::close);
connect()操作一般写在窗口的构造函数中, 相当于在事件产生之前在qt框架中先进行注册, 这样在程序运行
过程中假设产生了按钮的点击事件, 框架就会调用信号接收者对象对应的槽函数了, 如果信号不产生, 槽函数也就一直不会被调用。
如果想要在QT类中自定义信号槽, 需要满足一些条件, 并且有些事项也需要注意:
// 在头文件派生类的时候,首先像下面那样引入Q_OBJECT宏:
class MyMainWindow : public QWidget
{
Q_OBJECT//
......
}
自定义信号的要求和注意事项:
// 举例: 信号重载
// Qt中的类想要使用信号槽机制必须要从QObject类派生(直接或间接派生都可以)
class Test : public QObject
{
Q_OBJECT
signals:
void testsignal();
// 参数的作用是数据传递, 谁调用信号函数谁就指定实参
// 实参最终会被传递给槽函数
void testsignal(int a);
};
槽函数就是信号的处理动作,在Qt中槽函数可以作为普通的成员函数来使用。如果标准槽函数提供的功能满足不了需求,可以自己定义槽函数进行某些特殊功能的实现。自定义槽函数和自定义的普通函数写法是一样的。
返回值必须是 void 类型
槽也是函数, 因此也支持重载
槽函数需要指定多少个参数, 需要看连接的信号的参数个数
Qt中槽函数的类型是多样的
===>Qt中的槽函数可以是类的成员函数、全局函数、静态函数、Lambda表达式(匿名函数)
槽函数可以使用关键字进行声明: slots (Qt5中slots可以省略不写)
public slots:
private slots: –> 这样的槽函数不能在类外部被调用
protected slots: –> 这样的槽函数不能在类外部被调用
// 槽函数书写格式举例
// 类中的这三个函数都可以作为槽函数来使用
class Test : public QObject
{
public:
void testSlot();
static void testFunc();
public slots:
void testSlot(int id);
};
3. 添加槽函数
alt+enter写该函数(hungry按钮的槽函数),槽函数与按钮进行关联
=====》按钮是hungry,槽函数为hungrySlot()
#### (4)信号槽拓展
一个信号可以连接多个槽
信号较少可以是按顺序的,但是如果信号比较多的话就不行了
信号可以连接信号
信号接收者可以不处理接收的信号, 而是继续发射新的信号,这相当于传递了数据, 并没有对数据进行处理
当点击按钮后,发送clicked信号(不做处理),m_gril接收信号后继续发新的信号hungry。(前一行通过m_gril实例对象发出自定义信号hungry实现eatSlot)
信号槽可以断开,相当于连接解除(很少做)
disconnect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);
Qt5的连接方式
// 语法:
QMetaObject::Connection QObject::connect(
const QObject *sender, PointerToMemberFunction signal,
const QObject *receiver, PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection);
// 信号和槽函数也就是第2,4个参数传递的是地址, 编译器在编译过程中会对数据的正确性进行检测
connect(const QObject *sender, &QObject::signal,
const QObject *receiver, &QObject::method);
Qt4的连接方式
// Qt4的信号槽连接方式
[static] QMetaObject::Connection QObject::connect(
const QObject *sender, const char *signal,
const QObject *receiver, const char *method,
Qt::ConnectionType type = Qt::AutoConnection);
//需要写入宏里面:信号名,参数列表
connect(const QObject *sender,SIGNAL(信号函数名(参数1, 参数2, ...)),
const QObject *receiver,SLOT(槽函数名(参数1, 参数2, ...)));
而qt5需要:
法1. 用qt4的信号槽连接方式
法2.定义信号的函数指针
信号槽重置qt4更方便,但是不推荐,signal和slot宏替换不会错误检查!!
lambda表达式可以作为槽函数
= 会拷贝,只读,可以使用外部变量(?=效率变低,内存最后被释放)
这里mutable只是修改的拷贝的数据,不会对外部数据进行改变。
#include
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
// 重写事件处理器函数
void closeEvent(QCloseEvent* ev);
void resizeEvent(QResizeEvent* ev);
private:
Ui::MainWindow *ui;
};
================================================
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include
#include
#include
#include
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::closeEvent(QCloseEvent *ev)
{
QMessageBox::Button btn = QMessageBox::question(this, "关闭窗口", "您确定要关闭窗口吗?");
if(btn == QMessageBox::Yes)
{
// 接收并处理这个事件
ev->accept();
}
else
{
// 忽略这个事件,向上传递给父窗口(有默认处理动作)
ev->ignore();
}
}
//窗口大小发送变化时,自动调用
void MainWindow::resizeEvent(QResizeEvent *ev)
{
qDebug() << "oldSize: " << ev->oldSize()
<< "currentSize: " << ev->size();
}
基于Qt提供的事件处理器函数,我们可以非常轻松地按照自己的想法制作出一个按钮,按钮的要求如下:
1. 从视觉上看是一个不规则按钮(按钮实际上都是矩形的)
2. 按钮上需要显示指定的背景图片
3. 按钮在鼠标的不同操作阶段(无操作、鼠标悬停、鼠标按下)能够显示不同的背景图
#ifndef MYBUTTON_H
#define MYBUTTON_H
#include
class MyButton : public QWidget
{
Q_OBJECT
public:
explicit MyButton(QWidget *parent = nullptr);
void setImage(QString normal, QString hover, QString pressed);
protected:
void mousePressEvent(QMouseEvent* ev);
void mouseReleaseEvent(QMouseEvent* ev);
void enterEvent(QEvent* ev);
void leaveEvent(QEvent* ev);
void paintEvent(QPaintEvent* ev);
signals:
void clicked();
private:
QPixmap m_normal;//显示效率更高,QImage是像素级别的修改
QPixmap m_press;
QPixmap m_hover;
QPixmap m_current;
};
#endif // MYBUTTON_H
===========================================================================
#include "mybutton.h"
#include
MyButton::MyButton(QWidget *parent) : QWidget(parent)
{
}
void MyButton::setImage(QString normal, QString hover, QString pressed)
{
// 加载图片
m_normal.load(normal);
m_hover.load(hover);
m_press.load(pressed);
m_current = m_normal;
// 设置按钮和图片大小一致
setFixedSize(m_normal.size());
}
void MyButton::mousePressEvent(QMouseEvent *ev)
{
// 鼠标被按下, 发射这个自定义信号
emit clicked();
m_current = m_press;
update();
}
void MyButton::mouseReleaseEvent(QMouseEvent *ev)
{
m_current = m_normal;
update();
}
void MyButton::enterEvent(QEvent *ev)
{
m_current = m_hover;
update();
}
void MyButton::leaveEvent(QEvent *ev)
{
m_current = m_normal;
update();
}
void MyButton::paintEvent(QPaintEvent *ev)
{
QPainter p(this);
p.drawPixmap(rect(), m_current);
}
bool QWidget::event(QEvent *ev)
{
switch(ev->type())
{
// 鼠标移动
case QEvent::MouseMove:
mouseMoveEvent((QMouseEvent*)event);
break;
// 鼠标按下
case QEvent::MouseButtonPress:
mousePressEvent((QMouseEvent*)event);
break;
// 鼠标释放
case QEvent::MouseButtonRelease:
mouseReleaseEvent((QMouseEvent*)event);
break;
// 鼠标双击
case QEvent::MouseButtonDblClick:
mouseDoubleClickEvent((QMouseEvent*)event);
break;
// 键盘按键被按下事件
case QEvent::KeyPress:
break;
...
...
...
default:
break;
}
}
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
bool eventFilter(QObject *watched, QEvent *event);
private:
Ui::MainWindow *ui;
};
===========================================================
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
ui->textEdit->installEventFilter(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
bool MainWindow::eventFilter(QObject *watched, QEvent *event)
{
// 判断对象和事件
if(watched == ui->textEdit && event->type() == QEvent::KeyPress)
{
QKeyEvent* keyEv = (QKeyEvent*)event;
if(keyEv->key() == Qt::Key_Enter || // 小键盘确认
keyEv->key() == Qt::Key_Return) // 大键盘回车
{
qDebug() << "我是回车, 被按下了...";
return true;
}
}
return false;
}
QTcpServer:服务器类,用于监听客户端连接以及和客户端建立连接。
QTcpSocket:通信的套接字类,客户端、服务器端都需要使用。
这两个套接字通信类都属于网络模块network。
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("TCP - 服务器");
// 创建 QTcpServer 对象
m_server = new QTcpServer(this);
// 检测是否有新的客户端连接
connect(m_server, &QTcpServer::newConnection, this, [=]()
{
m_tcp = m_server->nextPendingConnection();
ui->record->append("成功和客户端建立了新的连接...");
m_status->setPixmap(QPixmap(":/connect.png").scaled(20, 20));
// 检测是否有客户端数据
connect(m_tcp, &QTcpSocket::readyRead, this, [=]()
{
// 接收数据
QString recvMsg = m_tcp->readAll();
ui->record->append("客户端Say: " + recvMsg);
});
// 客户端断开了连接
connect(m_tcp, &QTcpSocket::disconnected, this, [=]()
{
ui->record->append("客户端已经断开了连接...");
m_tcp->deleteLater();
m_status->setPixmap(QPixmap(":/disconnect.png").scaled(20, 20));
});
});
}
MainWindow::~MainWindow()
{
delete ui;
}
// 启动服务器端的服务按钮
void MainWindow::on_startServer_clicked()
{
unsigned short port = ui->port->text().toInt();
// 设置服务器监听
m_server->listen(QHostAddress::Any, port);
ui->startServer->setEnabled(false);
}
// 点击发送数据按钮
void MainWindow::on_sendMsg_clicked()
{
QString sendMsg = ui->msg->toPlainText();
m_tcp->write(sendMsg.toUtf8());
ui->record->append("服务器Say: " + sendMsg);
ui->msg->clear();
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
setWindowTitle("TCP - 客户端");
// 创建通信的套接字对象
m_tcp = new QTcpSocket(this);
// 检测服务器是否回复了数据
connect(m_tcp, &QTcpSocket::readyRead, [=]()
{
// 接收服务器发送的数据
QByteArray recvMsg = m_tcp->readAll();
ui->record->append("服务器Say: " + recvMsg);
});
// 检测是否和服务器是否连接成功了
connect(m_tcp, &QTcpSocket::connected, this, [=]()
{
ui->record->append("恭喜, 连接服务器成功!!!");
m_status->setPixmap(QPixmap(":/connect.png").scaled(20, 20));
});
// 检测服务器是否和客户端断开了连接
connect(m_tcp, &QTcpSocket::disconnected, this, [=]()
{
ui->record->append("服务器已经断开了连接, ...");
ui->connectServer->setEnabled(true);
ui->disconnect->setEnabled(false);
});
}
MainWindow::~MainWindow()
{
delete ui;
}
// 连接服务器按钮按下之后的处理动作
void MainWindow::on_connectServer_clicked()
{
QString ip = ui->ip->text();
unsigned short port = ui->port->text().toInt();
// 连接服务器
m_tcp->connectToHost(QHostAddress(ip), port);
ui->connectServer->setEnabled(false);
ui->disconnect->setEnabled(true);
}
// 发送数据按钮按下之后的处理动作
void MainWindow::on_sendMsg_clicked()
{
QString sendMsg = ui->msg->toPlainText();
m_tcp->write(sendMsg.toUtf8());
ui->record->append("客户端Say: " + sendMsg);
ui->msg->clear();
}
// 断开连接按钮被按下之后的处理动作
void MainWindow::on_disconnect_clicked()
{
m_tcp->close();
ui->connectServer->setEnabled(true);
ui->disconnect->setEnabled(false);
}