一 概述
使用链表数据结构设计一个画圈圈小游戏。
二 整体程序流程
程序启动顺序:
main.cpp创建MainWindow窗口
→ 执行MainWindow构造函数(创建窗口、手写按钮、绑定点击事件)
→ 窗口显示后,鼠标点击空白区域自动生成圆圈存入链表
→ 窗口每次刷新自动执行paintEvent,遍历链表画出所有圆圈
→ 点击按钮调用对应槽函数,修改链表(清空 / 删除最后一个圆),刷新画布
三 源码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QList>
#include <QPoint>
#include <QColor>
#include <QPushButton>
namespace Ui {
class MainWindow;
}
// 圆圈数据结构体,链表存储单元
struct Circle
{
QPoint center;
int radius;
QColor fillColor;
};
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow() override;
protected:
// 绘图、鼠标点击事件重写
void paintEvent(QPaintEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
private slots:
// 按钮点击槽函数
void slotClearAll();
void slotUndoLast();
private:
Ui::MainWindow *ui;
// 按钮控件声明
QPushButton* m_btnClearAll;
QPushButton* m_btnUndoLast;
// Qt双向链表存储所有圆圈
QList<Circle> m_circleList;
};
#endif // MAINWINDOW_H
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPainter>
#include <QMouseEvent>
#include <QRandomGenerator>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
this->setWindowTitle("TEST");
this->resize(900, 650);
// 实例化按钮控件(英文文本)
m_btnClearAll = new QPushButton("Clear All Circles", this);
m_btnUndoLast = new QPushButton("Undo Last Circle", this);
// 按钮绝对坐标布局
m_btnClearAll->setGeometry(20, 20, 160, 35);
m_btnUndoLast->setGeometry(200, 20, 160, 35);
// 信号槽绑定
connect(m_btnClearAll, &QPushButton::clicked, this, &MainWindow::slotClearAll);
connect(m_btnUndoLast, &QPushButton::clicked, this, &MainWindow::slotUndoLast);
}
MainWindow::~MainWindow()
{
delete ui;
}
// 遍历链表,绘制全部圆圈
void MainWindow::paintEvent(QPaintEvent *event)
{
QMainWindow::paintEvent(event);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
const auto& listRef = m_circleList;
for (const Circle& cir : listRef)
{
painter.setBrush(cir.fillColor);
painter.setPen(Qt::black);
painter.drawEllipse
(
cir.center.x() – cir.radius,
cir.center.y() – cir.radius,
cir.radius * 2,
cir.radius * 2
);
}
}
// 鼠标点击新增圆圈,存入链表尾部
void MainWindow::mousePressEvent(QMouseEvent *event)
{
QPoint clickPos = event->pos();
// 避开顶部按钮区域,防止点击按钮时误生成圆
if (clickPos.y() < 70)
return;
int r = QRandomGenerator::global()->bounded(25, 60);
QColor randColor
(
QRandomGenerator::global()->bounded(256),
QRandomGenerator::global()->bounded(256),
QRandomGenerator::global()->bounded(256)
);
Circle newCircle;
newCircle.center = clickPos;
newCircle.radius = r;
newCircle.fillColor = randColor;
m_circleList.append(newCircle);
update();
}
// 清空链表,销毁所有圆圈
void MainWindow::slotClearAll()
{
m_circleList.clear();
update();
}
// 删除链表最后一个圆圈(撤销)
void MainWindow::slotUndoLast()
{
if (!m_circleList.isEmpty())
{
m_circleList.removeLast();
update();
}
}
#include "mainwindow.h"
#include <QApplication>
#include <QLocale>
#include <QTranslator>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "TEST_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
a.installTranslator(&translator);
break;
}
}
MainWindow w;
w.show();
return a.exec();
}
四 完整交互演示流程举例
五 效果演示
点击3次:

点击撤销上一次:

点击销毁所有:


