文章目录
信号与槽函数
信号与槽( Signal & Slot)是 Qt 编程的基础,也是 Qt 的一大创新。因 为有了信号与槽的编程机制,在 Qt 中处理界面各个组件的交互操作时变得更加 直观和简单。
信号(Signal)就是在特定情况下被发射的事件,例如 PushButton 最常见 的信号就是鼠标单击时发射的clicked() 信号,一个 ComboBox 最常见的信号 是选择的列表项变化时发射的 CurrentIndexChanged() 信号。
一、实验目的
1.学习 Qt 信号与槽机制的定义。
2.学习如何在项目里定义我们的信号与槽的创建和使用方法。
二、实验内容
- 使用 UI 界面添加一个 PushButton 并创建槽函数。
- 使用纯代码添加 PushButton 并创建槽函数。
三、实验代码
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
/* 引入 QPushButton */
#include <QPushButton>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
signals:
/* 声明一个信号,只需声明,无需定义 */
void pushButtonTextChanged();
private slots:
void on_pushButton_clicked();
/* 声明一个槽函数 */
void changeButtonText();
/* 声明按钮点击的槽函数 */
void pushButtonClicked();
private:
Ui::MainWindow *ui;
/* 声明一个对象 pushButton */
QPushButton *pushButton;
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/* 设置窗体的宽为 800,高为 480 */
this->resize(800,480);
/* 实例化 pushButton 对象 */
pushButton = new QPushButton(this);
/* 调用 setText()方法设定按钮的文本 */
pushButton->setText("我是一个按钮");
/* 信号与槽连接 */
connect(pushButton, SIGNAL(clicked()), this, SLOT(pushButtonClicked()));
connect(this, SIGNAL(pushButtonTextChanged()), this, SLOT(changeButtonText()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
this->close();
}
/* 实现按钮点击槽函数 */
void MainWindow::pushButtonClicked()
{
/* 使用 emit 发送信号 */
emit pushButtonTextChanged();
}
/* 实现按钮文本改变的槽函数 */
void MainWindow::changeButtonText()
{
/* 在槽函数里改变按钮的文本 */
pushButton->setText("被点击了!");
}
四、运行结果
初始界面:
点击按钮后文字发生改变:
控件
QPushButton
1.QPushButton(按钮):
作用: 创建可点击的按钮,用于触发特定的操作或事件。
使用方法: 创建一个 QPushButton 对象,并设置按钮的文本、图标等属性。
通过连接按钮的信号(例如 clicked())到相应的槽函数,可以在按钮点击时执 行特定的代码。
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QPushButton>
/* 引入 QToolButton 类 */
#include <QToolButton>
/* 引入 QToolBar 类 */
#include <QToolBar>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
QPushButton pushButton1;
QPushButton pushButton2;
/* 声明一个 QToolButton 对象 */
QToolButton *toolButton;
/* 声明一个 QToolBar 对象 */
QToolBar *toolBar;
private slots:
/* 声明对象 pushButton1 的槽函数 */
void pushButton1_Clicked();
/* 声明对象 pushButton2 的槽函数 */
void pushButton2_Clicked();
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 设置宽高为 800×480,位置在 0, 0。(0, 0)代表原点,Qt 默认最左上角的点为原
点 */
this->setGeometry(0, 0, 800, 480);
/* 实例化两个按钮对象,并设置其显示文本为窗口皮肤 1 和窗口皮肤 2 */
//pushButton1 = new QPushButton("窗口皮肤 1", this);
//pushButton2 = new QPushButton("窗口皮肤 2", this);
//实例化按钮对象也可以使用栈直接实例化,因为后面信号槽连接需要传入&pushButton1
//pushButton1 = QPushButton("窗口皮肤 1", this);
//pushButton2 = QPushButton("窗口皮肤 2", this);
//需要手动设置父对象才能在窗口中显示
pushButton1.setParent(this);
pushButton2.setParent(this);
pushButton1.setText("窗口皮肤 1");
pushButton2.setText("窗口皮肤 2");
/* 设定两个 QPushButton 对象的位置 指针使用->,其他用. */
pushButton1.setGeometry(300,200,80,40);
pushButton2.setGeometry(400,200,80,40);
/* 信号槽连接,如果用栈实例化的pushbutton需要用&,堆实例化则不需要 */
connect(&pushButton1, SIGNAL(clicked()), this,SLOT(pushButton1_Clicked()));
connect(&pushButton2, SIGNAL(clicked()), this,SLOT(pushButton2_Clicked()));
}
MainWindow::~MainWindow()
{
}
/* 槽函数的实现 */
void MainWindow::pushButton1_Clicked()
{
/* 设置主窗口的样式 1 */
this->setStyleSheet("QMainWindow { background-color: rgba(255, 245, 238, 100%); }");
}
/* 槽函数的实现 */
void MainWindow::pushButton2_Clicked()
{
/* 设置主窗口的样式 2 */
this->setStyleSheet("QMainWindow { background-color: rgba(238, 122, 233, 100%); }");
}
运行结果
初始界面:
点击“窗口皮肤 1”后:
点击“窗口皮肤 2”后:
QComboBox
2.QComboBox(下拉框):
作用: 创建一个下拉框,用户可以从预定义的选项中选择。
使用方法: 创建一个 QComboBox 对象,然后使用 addItem()方法添加选项。
用户可以通过下拉框选择其中一个选项。通常,可以连接 activated()信号到槽
函数,以便在用户选择某个选项时执行相应的操作。
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H3.
#include <QMainWindow>
/* 引入 QComboBox */
#include <QComboBox>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
/* 声明一个 QComboBox 对象 */
QComboBox *comboBox;
private slots:
/* 声明 QComboBox 对象的槽函数 */
void comboBoxIndexChanged(int);
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
/* 引入 QDebug */
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
/* 设置主窗体的显示位置与大小 */
this->setGeometry(0, 0, 800, 480);14.
/* 实例化对象 */
comboBox = new QComboBox(this);
/* 设置 comboBox 的显示位置与大小 */
comboBox->setGeometry(300, 200, 150, 30);
/* 添加项,我们添加三个省份,作为 comboBox 的三个选项 */
comboBox->addItem("广东(默认)");
comboBox->addItem("湖南");
comboBox->addItem("四川");
/* 信号槽连接 */
connect(comboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(co
mboBoxIndexChanged(int)));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::comboBoxIndexChanged(int index)
{
/* 打印出选择的省份 */
qDebug()<<"您选择的省份是"<< comboBox->itemText(index)<<endl;
}
运行结果
初始界面:
选择四川后:
控制台输出:
QLineEdit和QLabel
3.QLineEdit(文本输入框):
作用: 创建一个文本输入框,用于接收用户的文本输入。
使用方法: 创建一个 QLineEdit 对象,用户可以在该文本框中输入文本。
可以通过 text()方法获取文本框中的文本,或者通过 textChanged()信号连接到槽函数,以在文本发生变化时执行特定的操作。
4.QLabel(标签):
作用: 创建一个用于显示文本或图像的标签。
使用方法: 创建一个 QLabel 对象,并设置标签的文本、图像等属性。可以通过 setText()方法设置文本内容,或者通过 setPixmap()方法设置图像。标签通常用于显示静态信息,而不直接响应用户输入。
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QLineEdit>
#include <QPushButton>
#include <QLabel>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
private:
Ui::MainWindow *ui;
/* 声明一个 QLineEdit 对象 */
QLineEdit *lineEdit;
/* 声明一个 QPushButton 对象 */
QPushButton *pushButton;
/* 声明一个 QLabel 对象 */31. QLabel *label;
private slots:
/* 声明一个槽函数,响应 pushButton 的 clicked 事件 */
void pushButtonClicked();
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setGeometry(0, 0, 800, 480);
lineEdit = new QLineEdit(this);
lineEdit->setGeometry(280, 200, 200, 20);
pushButton = new QPushButton(this);
pushButton->setGeometry(500, 200, 50, 20);
pushButton->setText("确认");
label = new QLabel(this);
label->setGeometry(280, 250, 400, 20);
label->setText("您输入的内容是:");
/* 信号槽连接 */
connect(pushButton,SIGNAL(clicked()), this, SLOT(pushButtonClicked()));
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::pushButtonClicked()33. {
/* 字符串变量 str */
QString str;
str = "您输入的内容是:";
str += lineEdit->text();
/* 设置 label 里的文本显示内容 */
label->setText(str);
/* 在点击了确认键之后清空 lineEdit 单行输入框 */
lineEdit->clear();
}
运行结果
初始界面:
输入test:
标签显示:
布局
QHBoxLayout 和 QVBoxLayout
作用: QHBoxLayout(水平布局)和 QVBoxLayout(垂直布局)用于在水平或垂直方向上排列控件。
使用方法: 创建相应的布局对象,使用 addWidget()方法添加控件,最后将布局对象设置为父窗口或容器的布局。
用法示例
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
/* 声明按钮对象数组 ,这是一个指针数组*/
QPushButton *pushButton[6];
/* 定义两个 widget,用于容纳排布按钮 */
QWidget *hWidget;
QWidget *vWidget;
/* QHBoxLayout 与 QVBoxLayout 对象 */
QHBoxLayout *hLayout;
QVBoxLayout *vLayout;
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
#include <QList>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 设置主窗口的位置与大小 */
this->setGeometry(0, 0, 800, 480);
/* 实例化与设置位置大小 */
hWidget = new QWidget(this);
hWidget->setGeometry(0, 0, 800, 240);
vWidget = new QWidget(this);
vWidget->setGeometry(0, 240, 800, 240);
hLayout = new QHBoxLayout();
vLayout = new QVBoxLayout();
/* QList<T>是 Qt 的一种泛型容器类。
* 它以链表方式存储一组值,
* 并能对这组数据进行快速索引
*/
QList <QString>list;
/* 将字符串值插入 list */
list<<"one"<<"two"<<"three"<<"four"<<"five"<<"six";
/* 用一个循环实例化 6 个按钮 */
for(int i = 0; i < 6; i++){
pushButton[i] = new QPushButton();
pushButton[i]->setText(list[i]);
if(i < 3) {
/* 将按钮添加至 hLayout 中 */
hLayout->addWidget(pushButton[i]);
} else {
/* 将按钮添加至 vLayout 中 */
vLayout->addWidget(pushButton[i]);
}
}
/* 设置间隔为 50 */
hLayout->setSpacing(50);
/* hWidget 与 vWidget 的布局设置为 hLayout/vLayout */
hWidget->setLayout(hLayout);
vWidget->setLayout(vLayout);
}
MainWindow::~MainWindow()
{
}
控件效果
QGridLayout网格布局
控件简介
QGridLayout 类提供了布局管理器里的一种以网格(二维)的方式管理界面组件,以按钮组件为例,它们所对应网格的坐标下表,与二维数组类似。QGridLayout继承QLayout。QGridLayout获取可用的空间(通过其父布局或parentWidget())),将其分为行和列,并将其管理的每个小部件放入正确的单元格中。由于网格布局管理器中的组件也是会随着窗口拉伸而发生变化的,所以也是需要设置组件之间的比例系数的,与QBoxLayout 不同的是网格布局管理器还需要分别设置行和列的比例系数。
作用:QGridLayout 用于在表格中排列控件,每个控件占用一个表格单元格。
使用方法: 创建 QGridLayout 对象,使用 addWidget()方法设置控件的行和列索引,将布局对象设置为父窗口或容器的布局。
用法示例
mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QGridLayout>
#include <QPushButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
/* 声明 widget 窗口部件,用于容纳下面 4 个 pushButton 按钮 */
QWidget *gWidget;
/* 声明 QGridLayout 对象 */
QGridLayout *gridLayout;
/* 声明 pushButton 按钮数组 */
QPushButton *pushButton[4];
};
#endif // MAINWINDOW_H
mainwindow.cpp
注意:在没有ui的情况下需要先实例化一个QWidget(this)作为容器承载gridlayout
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 设置位置与大小 */
this->setGeometry(0, 0, 800, 480);
/* 实例化 */
gWidget = new QWidget(this);
/* 设置 gWidget 居中央 */
this->setCentralWidget(gWidget);
gridLayout = new QGridLayout();
/* QList 链表,字符串类型 */
QList <QString> list;
list<<"按钮 1"<<"按钮 2"<<"按钮 3"<<"按钮 4";
for (int i = 0; i < 4; i++){
pushButton[i] = new QPushButton();
pushButton[i]->setText(list[i]);
/* 设置最小宽度与高度 */
pushButton[i]->setMinimumSize(100, 30);
/* 自动调整按钮的大小 */
pushButton[i]->setSizePolicy(
QSizePolicy::Expanding,
QSizePolicy::Expanding
);
switch (i) {
case 0:
/* 将 pushButton[0]添加至网格的坐标(0,0),下同 */
gridLayout->addWidget(pushButton[i], 0, 0);
break;
case 1:
gridLayout->addWidget(pushButton[i], 0, 1);
break;
case 2:
gridLayout->addWidget(pushButton[i], 1, 0);
break;
case 3:
gridLayout->addWidget(pushButton[i], 1, 1);
break;
default:
break;
}
}
/* 设置第 0 行与第 1 行的行比例系数 */
gridLayout->setRowStretch(0, 2);
gridLayout->setRowStretch(1, 3);
/* 设置第 0 列与第 1 列的列比例系数 */
gridLayout->setColumnStretch(0, 1);
gridLayout->setColumnStretch(1, 3);
/* 将 gridLayout 设置到 gWidget */
gWidget->setLayout(gridLayout);
}
MainWindow::~MainWindow()
{
}
控件效果
QStackedLayout布局
作用:QStackedLayout 用于将一组控件叠放在一起,只显示其中一个控件。
使用方法: 创建 QStackedLayout 对象,使用 addWidget()方法添加多个控件,通过 setCurrentIndex()方法在这些控件之间切换,最后将布局对象设置父窗口或容器的布局。
“mainwindow.h”代码:
#ifndef MAINWINDOWG_H
#define MAINWINDOWG_H
#include <QMainWindow>
#include <QStackedWidget>
#include <QHBoxLayout>
#include <QListWidget>
#include <QLabel>
class MainWindowg : public QMainWindow
{
Q_OBJECT
public:
MainWindowg(QWidget *parent = 0);
~MainWindowg();
private:
QWidget *widget;
QHBoxLayout *hBoxLayout;
QListWidget *listWidget;
QStackedWidget *stackedWidget;
QLabel *label[3];
};
#endif // MAINWINDOWG_H
“mainwindow.cpp”代码:
#include "mainwindowg.h"
MainWindowg::MainWindowg(QWidget *parent)
: QMainWindow(parent)
{
this->setGeometry(0, 0, 800, 480);
widget = new QWidget(this);
/* 设置居中 */
this->setCentralWidget(widget);
/* 垂直布局实例化 */
hBoxLayout = new QHBoxLayout();
/* 堆栈部件实例化 */
stackedWidget = new QStackedWidget();
/* 列表实例化 */
listWidget = new QListWidget();
QList <QString>strListWidgetList;
strListWidgetList<<"窗口一"<<"窗口二"<<"窗口三";
listWidget->insertItems(3,strListWidgetList);
QList <QString>strLabelList;
strLabelList<<"标签一"<<"标签二"<<"标签三";
for (int i =0;i<3;i++){
label[i]=new QLabel;
label[i]->setText(strLabelList[i]);
/* 标签对齐方式(居中) */
label[i]->setAlignment(Qt::AlignCenter);
stackedWidget->addWidget(label[i]);
}
/* 设置列表的最大宽度 */
listWidget->setMaximumWidth(200);
/* 添加到水平布局 */
hBoxLayout->addWidget(listWidget);
hBoxLayout->addWidget(stackedWidget);
/* 将 widget 的布局设置成 hboxLayout */
widget->setLayout(hBoxLayout);
/* 利用 listWidget 的信号函数 currentRowChanged()与
57 * 槽函数 setCurrentIndex(),进行信号与槽连接
58 */
connect(listWidget, SIGNAL(currentRowChanged(int)),
stackedWidget, SLOT(setCurrentIndex(int)));
}
MainWindowg::~MainWindowg()
{
}
控件效果
文件操作和多线程
QFile
QFile 类提供了用于文件的输入和输出的功能。它允许你读取和写入文 件,以及执行一些文件操作,如重命名、删除等。
使用 QFile 类读写文本。
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QTextEdit>
#include <QFile>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QPushButton>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
/* 用于读取文件后显示 */
QTextEdit *textEdit;
/* QFile 类型对象 */
QFile file;
/* 水平布局 */
QHBoxLayout *hBoxLayout;
/* 垂直布局 */
QVBoxLayout *vBoxLayout;
/* 水平布局 Widget */
QWidget *hWidget;
/* 垂直布局 Widget */
QWidget *vWidget;
/* 打开文件按钮 */
QPushButton *openPushButton;
/* 关闭文件按钮 */
QPushButton *closePushButton;
private slots:
bool openFile();
void closeFile();
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
#include <QFileDialog>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->setGeometry(0, 0, 800, 480);
/* 布局设置 */
textEdit = new QTextEdit();
vBoxLayout = new QVBoxLayout();
hBoxLayout = new QHBoxLayout();
vWidget = new QWidget();
hWidget = new QWidget();
openPushButton = new QPushButton();
closePushButton = new QPushButton();
/* 设置两个按钮的大小 */
openPushButton->setMinimumHeight(50);
openPushButton->setMaximumWidth(120);
closePushButton->setMinimumHeight(50);
closePushButton->setMaximumWidth(120);
/* 设置两个按钮的文本 */
openPushButton->setText("打开文件");
closePushButton->setText("关闭并保存");
/* 设置关闭按钮为不可用属性,需要打开文件才设置为可用属性 */
closePushButton->setEnabled(false);
/* 水平布局 */
hBoxLayout->addWidget(openPushButton);
hBoxLayout->addWidget(closePushButton);
hWidget->setLayout(hBoxLayout);
/* 垂直布局 */
vBoxLayout->addWidget(textEdit);
vBoxLayout->addWidget(hWidget);
vWidget->setLayout(vBoxLayout);
/* 居中 */
setCentralWidget(vWidget);
/* 信号槽连接 */
connect(openPushButton, SIGNAL(clicked()),
this, SLOT(openFile()));
connect(closePushButton, SIGNAL(clicked()),
this, SLOT(closeFile()));
}
MainWindow::~MainWindow()
{
}
bool MainWindow::openFile()
{
/* 获取文件的路径 */
QString fileName = QFileDialog::getOpenFileName(this);
/* 指向文件 */
file.setFileName(fileName);
/* 判断文件是否存在 */
if (!file.exists())
return false;
/* 以读写的方式打开 */
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
/* 使用文本流读取文件 */
QTextStream stream(&file);
/* 读取文本到 textEdit */
textEdit->setPlainText(stream.readAll());
/* 设置打开按钮不可用,需要关闭再打开 */
openPushButton->setEnabled(false);
/* 设置关闭按钮为可用属性 */
closePushButton->setEnabled(true);
/* 关闭文件 */
file.close();
return true;
}
void MainWindow::closeFile()
{
/* 检测打开按钮是否可用,不可用时,说明已经打开了文件 */
if (!openPushButton->isEnabled()) {
/* 获取 textEdit 的文本内容 */
QString str = textEdit->toPlainText();
/* 以只读的方式打开 */
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
return;
/* 转换为字节数组 */
QByteArray strBytes = str.toUtf8();
/* 写入文件 */
file.write(strBytes, strBytes.length());
/* 清空 textEdit 的显示内容 */
textEdit->clear();
/* 关闭文件 */
file.close();
/* 重新设置打开和关闭按钮的属性 */
openPushButton->setEnabled(true);
closePushButton->setEnabled(false);
}
}
控件效果
初始界面:
选择mainwindows.cpp文件:
成功打开后:
QThread
QThread 类提供了多线程的支持,允许在单独的线程中执行耗时的操作, 而不会阻塞主线程。
使用 QThread 类实现多线程。
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <QPushButton>
/* 使用下面声明的 WorkerThread 线程类 */
class WorkerThread;
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
/* 在 MainWindow 类里声明对象 */
WorkerThread *workerThread;
/* 声明一个按钮,使用此按钮点击后开启线程 */
QPushButton *pushButton;
private slots:
/* 槽函数,用于接收线程发送的信号 */
void handleResults(const QString &result);
/* 点击按钮开启线程 */
void pushButtonClicked();
};
/* 新建一个 WorkerThread 类继承于 QThread */
class WorkerThread : public QThread
{
/* 用到信号槽即需要此宏定义 */
Q_OBJECT
public:
WorkerThread(QWidget *parent = nullptr) {
Q_UNUSED(parent);
}
/* 重写 run 方法,继承 QThread 的类,只有 run 方法是在新的线程里 */
void run() override {
QString result = "线程开启成功";
/* 这里写上比较耗时的操作 */
// ...
// 延时 2s,把延时 2s 当作耗时操作
sleep(2);
/* 发送结果准备好的信号 */
emit resultReady(result);
}
signals:
/* 声明一个信号,译结果准确好的信号 */
void resultReady(const QString &s);
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
/* 设置位置与大小 */
this->setGeometry(0, 0, 800, 480);
/* 对象实例化 */
pushButton = new QPushButton(this);
workerThread = new WorkerThread(this);
/* 按钮设置大小与文本 */
pushButton->resize(100, 40);
pushButton->setText("开启线程");
/* 信号槽连接 */
connect(workerThread, SIGNAL(resultReady(QString)),
this, SLOT(handleResults(QString)));
connect(pushButton, SIGNAL(clicked()),
this, SLOT(pushButtonClicked()));
}
MainWindow::~MainWindow()
{
/* 进程退出,注意本例 run()方法没写循环,此方法需要有循环才生效 */
workerThread->quit();
/* 阻塞等待 2000ms 检查一次进程是否已经退出 */
if (workerThread->wait(2000)) {
qDebug()<<"线程已经结束!"<<endl;
}
}
void MainWindow::handleResults(const QString &result)
{
/* 打印出线程发送过来的结果 */
qDebug()<<result<<endl;
}
void MainWindow::pushButtonClicked()
{
/* 检查线程是否在运行,如果没有则开始运行 */
if (!workerThread->isRunning())
workerThread->start();
}
控件效果
初始界面:
点击开启线程的按钮,控制台输出:
opencv
通过在 Qt 中结合 OpenCV 库完成了图像处理的任务。主要步骤包括:
UI 控件添加:在界面上添加了对比度和亮度的滑动条等控件,方便用户调整图像处理参数。
图片处理:使用 OpenCV 库读取图片数据,并将其转换为适合在 Qt 中显示的格式(RGB888)。实现了图像的对比度和亮度的调整功能。
界面显示:通过 Qt 的界面控件,在程序中实时显示经过处理的图像。
-
使用 UI 界面添加需要的控件。
-
使用代码完成 OpenCV 功能。
“mainwindow.h”代码:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include "opencv2/opencv.hpp"
using namespace cv;
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = 0);
~MainWindow();
void initMainWindow();
void imgProc(float contrast, int brightness);
void imgShow();
private slots:
void on_contrastVerticalSlider_sliderMoved(int position);
void on_contrastVerticalSlider_valueChanged(int value);
void on_brightnessVerticalSlider_sliderMoved(int position);
void on_brightnessVerticalSlider_valueChanged(int value);
private:
Ui::MainWindow *ui;
//全局变量
Mat myImg;
QImage myQImg;
};
#endif // MAINWINDOW_H
“mainwindow.cpp”代码:
#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
initMainWindow();
}
void MainWindow::initMainWindow () {
//QString imgPath = "D:\\Qt\\imgproc\\girl~iver.jpg"; //路径中不能含中文字符
QString imgPath = "/home/hugo/img_pro/3.png";//本地路径(图片直接存放在项目目录下)
Mat imgData = imread(imgPath.toLatin1().data()); //读取图片数据
cvtColor(imgData, imgData, COLOR_BGR2RGB); //图片格式转换
myImg = imgData;
myQImg=QImage((const unsigned char*) (imgData.data), imgData.cols, imgData.rows, QImage::Format_RGB888);
imgShow(); //(b)
}
void MainWindow::imgShow () {
ui->viewLabel->setPixmap(QPixmap::fromImage(myQImg.scaled(ui->viewLabel->size(),Qt::KeepAspectRatio))); //在 Qt 界面上显示图片
}
void MainWindow::imgProc(float contrast, int brightness) {
Mat imgSrc = myImg;
Mat imgDst = Mat::zeros (imgSrc.cols,imgSrc.rows,imgSrc.type());
imgSrc.convertTo(imgDst,-1,contrast,brightness);
myQImg = QImage((const unsigned char*) (imgDst.data), imgDst.cols, imgDst.rows, QImage::Format_RGB888);
imgShow();
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_contrastVerticalSlider_sliderMoved(int position)
{
imgProc(position / 33.3, 0);
}
void MainWindow::on_contrastVerticalSlider_valueChanged(int value)
{
imgProc(value / 33.3, 0);
}
void MainWindow::on_brightnessVerticalSlider_sliderMoved(int position)
{
imgProc(1.0, position);
}
void MainWindow::on_brightnessVerticalSlider_valueChanged(int value)
{
imgProc(1.0, value);
}
运行结果
初始界面:
调节对比度:
同时调亮度: