下载和安装

安装时如果操作系统为 Windows,则应该安装 MinGW 版本

Qt Creator

  • QWidget 类:不带菜单栏的
  • QMainWindow 类:带菜单栏的

界面:代码实现和图形界面分开

代码区有头文件和相应的实现(都在类中)

图形界面有插件和相应的属性设置

有不知道的命令可以在左侧帮助中查

#include "widget.h"

#include <QApplication> // 包含一个应用程序类的文件

int main(int argc, char *argv[])
{
QApplication a(argc, argv); // 应用程序对象,有且仅有一个
Widget w;
w.show(); // 窗口对象默认不会显示,需要手动调用
return a.exec(); // 让代码阻塞到这行
}

信号与槽

插入信号和槽的方法

最直接的:右键对象,转到槽,只需直接在所给的函数中写代码

private slots 中添加函数声明,并连接信号与槽:

谁发出信号,发出什么信号,谁处理信号,怎么处理信号

例如:connnect(ui->cmdLineEdit, SIGNAL(returnPressed()), this, SLOT(on_commitButton_clicked()));

也可以:connect(ui->cancelButton, &QPushButton::clicked, this, &Widget::on_cancelButton_clicked);

后面部分可以写成 lambda 表达式:

connect(ui->browseButton, &QPushButton::clicked, [this](){
QMessageBox::information(this, "信息", "点击浏览");
});

自定义信号

头文件里写:

signals:
void sendToWidget();

发出信号:emit sendToWidget()

信号可以包含参数,槽也可以包含参数,且允许传递无用的信号

  • 一个信号可以连接多个槽,但这些槽执行顺序不确定
  • 一个槽可以与多个信号相连,只要接收到其中一个信号,就会执行该槽

实现计算器

this->setWindowTitle("计算器");this->setFixedSize(200, 280); // 固定窗口大小

this->setWindowTitle("计算器"); // 设置窗口标题

QFont f("仿宋", 14);
ui->mainLineEdit->setFont(f); // 设置字体

QIcon icon("E:\\code\\Qt\\calculator\\tt.jpg");
ui->deleteButton->setIcon(icon); // 设置图标

ui->equalButton->setStyleSheet("background:blue"); // 设置按钮背景色

计时器

QObject

使用放在基类 QObject 中的计时器

定义函数:virtual void timerEvent(QTimerEvent *event)

开始计时:myTimerId = this->startTimer(TIMEOUT)

void Widget::timerEvent(QTimerEvent *event) {
if (event->timerId() != myTimerId) // 判断该事件是否是由自己刚才设定的那个计时器触发的
return;

QString path("E:\\Pictures\\正经的\\琉璃神社壁纸包 2022年6月号\\");
path += QString::number(picId) + ".jpg";

QImage img(path);
ui->label->setPixmap(QPixmap::fromImage(img)); // 使用 QImage 保存图片,QPixmap 显示图片

picId++;
if (picId > 42)
picId = 10;
}

QTimer

定义:QTimer* timer

连接信号与槽:connect(timer, &QTimer::timeout, this, &Widget::timeoutSlot)

时间到了执行一次:QTimer::singleShot(TIMEOUT, this, SLOT(timeoutSlot()));

文件操作

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);

connect(ui->newAction, &QAction::triggered, this, &MainWindow::newActionSlot); // 将菜单栏选项和事件连接起来
connect(ui->openAction, &QAction::triggered, this, &MainWindow::openActionSlot);
connect(ui->saveAction, &QAction::triggered, this, &MainWindow::saveActionSlot);
}

MainWindow::~MainWindow()
{
delete ui;
}

void MainWindow::newActionSlot() {
ui->textEdit->clear();
this->setWindowTitle("新建文本文档.txt");
}

void MainWindow::openActionSlot() {
QString fileName = QFileDialog::getOpenFileName(this, "选择一个文件", QCoreApplication::applicationFilePath(), "*.cpp"); // 弹出选择路径的窗口
if (fileName.isEmpty())
QMessageBox::warning(this, "警告", "请选择一个文件");
else {
QFile file(fileName); // 创建文件对象
file.open(QIODevice::ReadOnly); // 以只读方式打开文件
ui->textEdit->setText(QString(file.readAll())); // 将读取的内容转为字符串
file.close();
}
}

void MainWindow::saveActionSlot() {
QString fileName = QFileDialog::getSaveFileName(this, "请选择一个文件", CoreApplication::applicationFilePath()); // 当前路径
if (fileName.isEmpty())
QMessageBox::warning(this, "警告", "请选择一个文件");
else {
QFile file(fileName);
file.open(QIODevice::WriteOnly);
file.write(ui->textEdit->toPlainText().toLocal8Bit()); // 将保存内容转为字符串
file.close();
}
}

文件的打开与文件信息的获取

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

QFile file("in.txt");
if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
qDebug() << "Open file failed.";
return -1;
} else {
while (!file.atEnd()) {
qDebug() << file.readLine();
}
}

QFileInfo info(file);
qDebug() << info.isDir();

return app.exec();
}

QFileInfo 的一些函数:

函数名 用处
isDir() 检查该文件是否是目录
isExecutable() 检查该文件是否是可执行文件
baseName() 获取文件名(
completeBaseName() 获取完整的文件名
suffix() 获取文件后缀名
completeSuffix() 获取完整的文件后缀

二进制文件读写

使用 QDataStream

// 写
QFile file("file.dat");
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out << QString("the answer is");
out << (qint32)42;
file.close(); // 为性能起见,数据只有在文件关闭时才会真正写入

// 读
QFile file("file.dat");
file.open(QIODevice::ReadOnly);
QDataStream in(&file);
QString str;
qint32 a;
in >> str >> a;

文本文件读写

使用 QTextStream

读写方法类似

鼠标和键盘事件

所需头文件:

  • #include <QKeyEvent>
  • #include <QMouseEvent>
void MainWindow::keyPressEvent(QKeyEvent *k) { // 键盘事件
if (k->modifiers() == Qt::ControlModifier && k->key() == Qt::Key_S) // Qt:: 里面有一些预定义的宏
saveActionSlot();
}

void MainWindow::mousePressEvent(QMouseEvent *m) { // 鼠标事件
QPoint pt = m->pos(); // 鼠标指针对象
qDebug() << pt;
if (m->button() == Qt::LeftButton) {
qDebug() << "左键被按下";
}
else if (m->button() == Qt::RightButton) {
qDebug() << "右键被按下";
}
}

启动新窗口

类似于 main.cpp 中所写的

因为 show 并不会阻塞函数,所以这个函数会继续执行,所以必须在堆空间而不是栈空间创建对象

// Chat 为新增的 Widget 类
Chat *c = new Chat(socket);
// 不能写成 Chat c(socket);
c->show();

多线程

新建一个继承自 QThread 的类 myThread,该类中须实现线程处理函数 run()

调用:

myThread *t = new myThread; // 创建线程对象
t->start(); // 启动线程

绘图

坐标原点在左上角,向右为 x 轴正方向,向下为 y 轴正方向

需要 <QPainter> 头文件

事件为:void paintEvent(QPaintEvent *)

调用:

void PaintedWidget::paintEvent(QPaintEvent *)
{
QPainter painter(this); // 在当前绘图设备(PaintedWidget)上绘图
painter.drawLine(80, 100, 650, 500); // 画线
painter.setPen(Qt::red); // 调整笔的颜色
painter.drawRect(10, 10, 100, 400); // 画左上角坐标为(10, 10),水平、竖直边长分别为 100, 400
painter.setPen(QPen(Qt::green, 5)); // 宽度为5
painter.setBrush(Qt::blue);
painter.drawEllipse(50, 150, 400, 200);
}

若想要再次手动调用该事件,使用 `update()