C++学习之路(十一)C++ 用Qt5实现一个工具箱(增加一个进制转换器功能)- 示例代码拆分讲解

上篇文章,我们用 Qt5 实现了在小工具箱中添加了《时间戳转换功能》功能。为了继续丰富我们的工具箱,今天我们就再增加一个平时经常用到的功能吧,就是「 进制转换 」功能。下面我们就来看看如何来规划开发一个这样的小功能并且添加到我们的工具箱中吧。

老规矩,先看效果

C++学习之路(十一)C++ 用Qt5实现一个工具箱(增加一个进制转换器功能)- 示例代码拆分讲解_第1张图片

本次功能概述

这个程序是一个数字进制转换器,它能够将输入的数字按照不同的进制进行转换,并显示出转换后的结果。

  1. 界面布局:界面上分为两个排列方式不同的部分。第一个部分包含一个输入框和一个下拉选择框,它们水平排列。输入框接受用户输入数字,下拉选择框则用于选择转换后的进制。第二部分包含四个输出框,垂直排列,用于显示转换后的结果。

  2. 槽函数与转换:当用户在输入框中输入数字或者选择不同的进制时,程序会触发convertNumber函数。这个函数根据用户输入和选择的进制进行转换。根据不同的进制选择,程序会采取不同的转换方法,包括二进制、八进制、十进制和十六进制。

  3. 实时更新:输入框的内容一旦发生变化,就会实时计算出对应的四个输出框的结果。这种实时更新让用户能够方便地观察不同进制之间的转换关系。

  4. 清空功能:如果用户清空了输入框的内容,四个输出框也会相应地清空,避免显示错误的转换结果。

这个程序实现了简单的数字进制转换功能,并提供了实时更新和清空功能,使用户能够方便地在不同进制之间进行转换和比较。

核心代码实现

class NumberBaseConverter : public QWidget {
Q_OBJECT
public:
    explicit NumberBaseConverter(QWidget *parent = nullptr) : QWidget(parent) {
        auto *layout = new QVBoxLayout(this);
        // 横向排列的输入框和选择框
        auto *horizontalLayout = new QHBoxLayout();

        // 创建输入框并添加到水平布局
        inputLineEdit = new QLineEdit(this);
        horizontalLayout->addWidget(inputLineEdit);

        // 连接输入框的文本变化信号到槽函数
        connect(inputLineEdit, &QLineEdit::textChanged, this, &NumberBaseConverter::convertNumber);

        // 创建下拉选择框并添加到水平布局
        baseComboBox = new QComboBox(this);
        baseComboBox->addItem("二进制");
        baseComboBox->addItem("八进制");
        baseComboBox->addItem("十进制");
        baseComboBox->addItem("十六进制");
        horizontalLayout->addWidget(baseComboBox);

        // 将水平布局添加到垂直布局
        layout->addLayout(horizontalLayout);

        // 创建四个只读的输出框并添加到垂直布局
        binaryOutput = new QLineEdit(this);
        binaryOutput->setReadOnly(true);
        layout->addWidget(binaryOutput);

        octalOutput = new QLineEdit(this);
        octalOutput->setReadOnly(true);
        layout->addWidget(octalOutput);

        decimalOutput = new QLineEdit(this);
        decimalOutput->setReadOnly(true);
        layout->addWidget(decimalOutput);

        hexOutput = new QLineEdit(this);
        hexOutput->setReadOnly(true);
        layout->addWidget(hexOutput);

        // 连接下拉选择框的选择变化信号到槽函数,并进行初始转换
        connect(baseComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NumberBaseConverter::convertNumber);
        convertNumber(); // 初始转换

        setLayout(layout); // 设置整体布局
    }

private slots:
    void convertNumber() {
        QString inputText = inputLineEdit->text();
        bool ok;
        int base = baseComboBox->currentIndex();

        if (!inputText.isEmpty()) {
            // 根据所选进制进行转换
            if (base == 0) {
                int number = inputText.toInt(&ok, 2); // 二进制转十进制
                if (ok) {
                    binaryOutput->setText(inputText);
                    octalOutput->setText(QString::number(number, 8));
                    decimalOutput->setText(QString::number(number));
                    hexOutput->setText(QString::number(number, 16).toUpper());
                }
            } else if (base == 1) {
                // 八进制转换
                int number = inputText.toInt(&ok, 8);
                if (ok) {
                    binaryOutput->setText(QString::number(number, 2));
                    octalOutput->setText(inputText);
                    decimalOutput->setText(QString::number(number));
                    hexOutput->setText(QString::number(number, 16).toUpper());
                }
            } else if (base == 2) {
                // 十进制转换
                int number = inputText.toInt(&ok, 10);
                if (ok) {
                    binaryOutput->setText(QString::number(number, 2));
                    octalOutput->setText(QString::number(number, 8));
                    decimalOutput->setText(inputText);
                    hexOutput->setText(QString::number(number, 16).toUpper());
                }
            } else if (base == 3) {
                // 十六进制转换
                int number = inputText.toInt(&ok, 16);
                if (ok) {
                    binaryOutput->setText(QString::number(number, 2));
                    octalOutput->setText(QString::number(number, 8));
                    decimalOutput->setText(QString::number(number));
                    hexOutput->setText(inputText.toUpper());
                }
            }
        } else {
            // 如果输入为空,则清空输出
            binaryOutput->clear();
            octalOutput->clear();
            decimalOutput->clear();
            hexOutput->clear();
        }
    }

private:
    QLineEdit *inputLineEdit;
    QComboBox *baseComboBox;
    QLineEdit *binaryOutput;
    QLineEdit *octalOutput;
    QLineEdit *decimalOutput;
    QLineEdit *hexOutput;
};

伸手党福利时间,上完整代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define myApp (dynamic_cast<QApplication *>(QCoreApplication::instance()))

class NumberBaseConverter : public QWidget {
Q_OBJECT
public:
    explicit NumberBaseConverter(QWidget *parent = nullptr) : QWidget(parent) {
        auto *layout = new QVBoxLayout(this);
        // 横向排列的输入框和选择框
        auto *horizontalLayout = new QHBoxLayout();

        // 创建输入框并添加到水平布局
        inputLineEdit = new QLineEdit(this);
        horizontalLayout->addWidget(inputLineEdit);

        // 连接输入框的文本变化信号到槽函数
        connect(inputLineEdit, &QLineEdit::textChanged, this, &NumberBaseConverter::convertNumber);

        // 创建下拉选择框并添加到水平布局
        baseComboBox = new QComboBox(this);
        baseComboBox->addItem("二进制");
        baseComboBox->addItem("八进制");
        baseComboBox->addItem("十进制");
        baseComboBox->addItem("十六进制");
        horizontalLayout->addWidget(baseComboBox);

        // 将水平布局添加到垂直布局
        layout->addLayout(horizontalLayout);

        // 创建四个只读的输出框并添加到垂直布局
        binaryOutput = new QLineEdit(this);
        binaryOutput->setReadOnly(true);
        layout->addWidget(binaryOutput);

        octalOutput = new QLineEdit(this);
        octalOutput->setReadOnly(true);
        layout->addWidget(octalOutput);

        decimalOutput = new QLineEdit(this);
        decimalOutput->setReadOnly(true);
        layout->addWidget(decimalOutput);

        hexOutput = new QLineEdit(this);
        hexOutput->setReadOnly(true);
        layout->addWidget(hexOutput);

        // 连接下拉选择框的选择变化信号到槽函数,并进行初始转换
        connect(baseComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &NumberBaseConverter::convertNumber);
        convertNumber(); // 初始转换

        setLayout(layout); // 设置整体布局
    }

private slots:
    void convertNumber() {
        QString inputText = inputLineEdit->text();
        bool ok;
        int base = baseComboBox->currentIndex();

        if (!inputText.isEmpty()) {
            // 根据所选进制进行转换
            if (base == 0) {
                int number = inputText.toInt(&ok, 2); // 二进制转十进制
                if (ok) {
                    binaryOutput->setText(inputText);
                    octalOutput->setText(QString::number(number, 8));
                    decimalOutput->setText(QString::number(number));
                    hexOutput->setText(QString::number(number, 16).toUpper());
                }
            } else if (base == 1) {
                // 八进制转换
                int number = inputText.toInt(&ok, 8);
                if (ok) {
                    binaryOutput->setText(QString::number(number, 2));
                    octalOutput->setText(inputText);
                    decimalOutput->setText(QString::number(number));
                    hexOutput->setText(QString::number(number, 16).toUpper());
                }
            } else if (base == 2) {
                // 十进制转换
                int number = inputText.toInt(&ok, 10);
                if (ok) {
                    binaryOutput->setText(QString::number(number, 2));
                    octalOutput->setText(QString::number(number, 8));
                    decimalOutput->setText(inputText);
                    hexOutput->setText(QString::number(number, 16).toUpper());
                }
            } else if (base == 3) {
                // 十六进制转换
                int number = inputText.toInt(&ok, 16);
                if (ok) {
                    binaryOutput->setText(QString::number(number, 2));
                    octalOutput->setText(QString::number(number, 8));
                    decimalOutput->setText(QString::number(number));
                    hexOutput->setText(inputText.toUpper());
                }
            }
        } else {
            // 如果输入为空,则清空输出
            binaryOutput->clear();
            octalOutput->clear();
            decimalOutput->clear();
            hexOutput->clear();
        }
    }

private:
    QLineEdit *inputLineEdit;
    QComboBox *baseComboBox;
    QLineEdit *binaryOutput;
    QLineEdit *octalOutput;
    QLineEdit *decimalOutput;
    QLineEdit *hexOutput;
};

class PlaceholderTextEdit : public QWidget {
Q_OBJECT
public:
    explicit PlaceholderTextEdit(const QString &placeholderText, QWidget *parent = nullptr) : QWidget(parent) {
        auto *layout = new QVBoxLayout(this);

        placeholderLabel = new QLabel(placeholderText, this);
        layout->addWidget(placeholderLabel);

        textEdit = new QTextEdit(this);
        layout->addWidget(textEdit);

        connect(textEdit, &QTextEdit::textChanged, this, &PlaceholderTextEdit::checkPlaceholder);
        checkPlaceholder(); // 初始检查

        setLayout(layout);
    }

    QString getText() const {
        return textEdit->toPlainText();
    }

private slots:
    void checkPlaceholder() {
        placeholderLabel->setVisible(textEdit->toPlainText().isEmpty());
    }

private:
    QLabel *placeholderLabel;
    QTextEdit *textEdit;
};

class DateTimeTimestampConverter : public QWidget {
Q_OBJECT
public:
    explicit DateTimeTimestampConverter(QWidget *parent = nullptr) : QWidget(parent) {
        auto *layout = new QVBoxLayout(this);

        inputTextEdit = new PlaceholderTextEdit("在此输入日期时间或时间戳", this);
        layout->addWidget(inputTextEdit);

        convertToTimestampButton = new QPushButton("日期时间转时间戳", this);
        connect(convertToTimestampButton, &QPushButton::clicked, this, &DateTimeTimestampConverter::convertToTimestamp);
        layout->addWidget(convertToTimestampButton);

        convertToDateTimeButton = new QPushButton("时间戳转日期时间", this);
        connect(convertToDateTimeButton, &QPushButton::clicked, this, &DateTimeTimestampConverter::convertToDateTime);
        layout->addWidget(convertToDateTimeButton);

        outputTextEdit = new QTextEdit(this);
        outputTextEdit->setReadOnly(true);
        layout->addWidget(outputTextEdit);

        setLayout(layout);
    }

private slots:
    void convertToTimestamp() {
        QString inputText = inputTextEdit->getText();
        QDateTime dateTime = QDateTime::fromString(inputText, "yyyy-MM-dd HH:mm:ss");

        if (dateTime.isValid()) {
            qint64 timestamp = dateTime.toSecsSinceEpoch();
            outputTextEdit->setText(QString::number(timestamp));
        } else {
            outputTextEdit->setText("无效的日期时间格式!");
        }
    }

    void convertToDateTime() {
        QString inputText = inputTextEdit->getText();
        bool ok;
        qint64 timestamp = inputText.toLongLong(&ok);

        if (ok) {
            QDateTime dateTime;
            dateTime.setSecsSinceEpoch(timestamp);

            outputTextEdit->setText("时间戳 " + inputText + " 对应的日期时间是:" + dateTime.toString("yyyy-MM-dd HH:mm:ss"));
        } else {
            outputTextEdit->setText("无效的时间戳格式!");
        }
    }

private:
    QPushButton *convertToTimestampButton;
    QPushButton *convertToDateTimeButton;
    QTextEdit *outputTextEdit;
    PlaceholderTextEdit *inputTextEdit;
};

class JsonFormatter : public QWidget {
Q_OBJECT
public:
    explicit JsonFormatter(QWidget *parent = nullptr) : QWidget(parent) {
        auto *layout = new QVBoxLayout(this);

        inputTextEdit = new QTextEdit(this);
        layout->addWidget(inputTextEdit);

        formatButton = new QPushButton("格式化", this);
        connect(formatButton, &QPushButton::clicked, this, &JsonFormatter::formatJson);
        layout->addWidget(formatButton);

        outputTextEdit = new QTextEdit(this);
        outputTextEdit->setReadOnly(true);
        layout->addWidget(outputTextEdit);

        setLayout(layout);
    }

private slots:
    void formatJson() {
        QString inputText = inputTextEdit->toPlainText();
        QJsonParseError error{};
        QJsonDocument jsonDoc = QJsonDocument::fromJson(inputText.toUtf8(), &error);

        if (error.error != QJsonParseError::NoError) {
            outputTextEdit->setText("JSON 解析错误:" + error.errorString());
            return;
        }

        QJsonObject jsonObj = jsonDoc.object();
        QJsonDocument formattedJson(jsonObj);

        outputTextEdit->setText(formattedJson.toJson());
    }

private:
    QTextEdit *inputTextEdit;
    QPushButton *formatButton;
    QTextEdit *outputTextEdit;
};

class ClipboardManager : public QWidget {
Q_OBJECT
public:
    explicit ClipboardManager(QWidget *parent = nullptr) : QWidget(parent) {
        auto *layout = new QVBoxLayout(this);

        listWidget = new QListWidget(this);
        updateList(); // 初始更新列表

        auto *clearButton = new QPushButton("清空记录", this);
        connect(clearButton, &QPushButton::clicked, this, &ClipboardManager::clearClipboard);

        layout->addWidget(listWidget);
        layout->addWidget(clearButton);

        setLayout(layout);

        connect(myApp->clipboard(), &QClipboard::dataChanged, this, &ClipboardManager::updateList);
    }

private slots:
    void updateList() {
        const QClipboard *clipboard = myApp->clipboard();
        const QMimeData *mimeData = clipboard->mimeData();

        if (mimeData->hasText()) {
            const QString clipboardText = mimeData->text();

            if (!clipboardText.isEmpty()) {
                listWidget->addItem(clipboardText);
            }
        }
    }

    void clearClipboard() {
        myApp->clipboard()->clear();
        listWidget->clear();
    }

private:
    QListWidget *listWidget;
};

class MyMainWindow : public QWidget {
Q_OBJECT
public:
    explicit MyMainWindow(QWidget *parent = nullptr) : QWidget(parent) {
        setWindowTitle("天河工具箱");

        auto *layout = new QVBoxLayout(this);

        auto *clipboardButton = new QPushButton("显示管理粘贴板记录");
        clipboardButton->setObjectName("clipboardButton");
        connect(clipboardButton, &QPushButton::clicked, this, &MyMainWindow::toggleClipboardManager);
        clipboardManager = new ClipboardManager(this);
        clipboardManager->hide();
        layout->addWidget(clipboardManager);
        layout->addWidget(clipboardButton);

        auto *jsonFormatButton = new QPushButton("显示格式化 JSON");
        jsonFormatButton->setObjectName("jsonFormatButton");
        connect(jsonFormatButton, &QPushButton::clicked, this, &MyMainWindow::toggleJsonFormatter);
        jsonFormatter = new JsonFormatter(this);
        jsonFormatter->hide();
        layout->addWidget(jsonFormatter);
        layout->addWidget(jsonFormatButton);

        auto *timestampConverterButton = new QPushButton("显示时间戳转换");
        timestampConverterButton->setObjectName("timestampConverterButton");
        connect(timestampConverterButton, &QPushButton::clicked, this, &MyMainWindow::toggleDateTimeTimestampConverter);
        timestampConverter = new DateTimeTimestampConverter(this);
        timestampConverter->hide();
        layout->addWidget(timestampConverter);
        layout->addWidget(timestampConverterButton);

        auto *numberBaseConverterButton = new QPushButton("显示进制转换器");
        numberBaseConverterButton->setObjectName("numberBaseConverterButton");
        connect(numberBaseConverterButton, &QPushButton::clicked, this, &MyMainWindow::toggleNumberBaseConverter);
        numberBaseConverter = new NumberBaseConverter(this);
        numberBaseConverter->hide();
        layout->addWidget(numberBaseConverter);
        layout->addWidget(numberBaseConverterButton);

        setLayout(layout);
    }

private slots:

    void toggleClipboardManager() {
        auto* curButton = findChild<QPushButton*>("clipboardButton");
        if (clipboardManager->isHidden()) {
            if (curButton) {
                curButton->setText("隐藏管理粘贴板记录");
            }
            clipboardManager->show();
        } else {
            if (curButton) {
                curButton->setText("显示管理粘贴板记录");
            }
            clipboardManager->hide();
        }
    }

    void toggleJsonFormatter() {
        auto* curButton = findChild<QPushButton*>("jsonFormatButton");
        if (jsonFormatter->isHidden()) {
            if (curButton) {
                curButton->setText("隐藏格式化 JSON");
            }
            jsonFormatter->show();
        } else {
            if (curButton) {
                curButton->setText("显示格式化 JSON");
            }
            jsonFormatter->hide();
        }
    }

    void toggleDateTimeTimestampConverter() {
        auto* curButton = findChild<QPushButton*>("timestampConverterButton");
        if (timestampConverter->isHidden()) {
            if (curButton) {
                curButton->setText("隐藏时间戳转换");
            }
            timestampConverter->show();
        } else {
            if (curButton) {
                curButton->setText("显示时间戳转换");
            }
            timestampConverter->hide();
        }
    }

    void toggleNumberBaseConverter() {
        auto* curButton = findChild<QPushButton*>("numberBaseConverterButton");
        if (numberBaseConverter->isHidden()) {
            if (curButton) {
                curButton->setText("隐藏进制转换器");
            }
            numberBaseConverter->show();
        } else {
            if (curButton) {
                curButton->setText("显示进制转换器");
            }
            numberBaseConverter->hide();
        }
    }

private:
    ClipboardManager *clipboardManager;
    JsonFormatter *jsonFormatter;
    DateTimeTimestampConverter *timestampConverter;
    NumberBaseConverter *numberBaseConverter;
};

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

    MyMainWindow mainWindow;
    mainWindow.show();

    return QApplication::exec();
}

#include "main.moc"

拆分讲解

本次核心代码相对好理解一些,就不逐段讲解了,就只贴出来我们用到的相关控件函数吧。

控件介绍

  • QVBoxLayout:垂直布局管理器,用于垂直排列子部件。
  • QHBoxLayout:水平布局管理器,用于水平排列子部件。
  • QLineEdit:单行文本输入框,用于输入文本。
  • QComboBox:下拉选择框,提供一个可选择的下拉列表。
  • QPushButton:按钮控件,用于触发特定操作或槽函数。
  • connect():QT中的信号与槽机制,用于连接信号和槽函数,当信号被触发时,相关的槽函数将被执行。

函数方法介绍

  • QHBoxLayout::addWidget():将子部件添加到水平布局中。
  • QVBoxLayout::addWidget():将子部件添加到垂直布局中。
  • QComboBox::addItem():向下拉选择框添加选项。
  • QLineEdit::setReadOnly():设置文本输入框为只读模式。
  • QLineEdit::clear():清空文本输入框中的内容。
  • QComboBox::currentIndex():获取当前选择的下拉列表索引。
  • QString::toInt():将字符串转换为整数,可以指定进制。
  • QString::number():将数字转换为字符串,可以指定进制。
  • QString::toUpper():将字符串转换为大写形式。

这些控件和函数方法是用于构建数字进制转换器的基础组件和功能。通过这些控件和方法,可以实现用户输入数字和选择进制,然后进行相应进制的转换,并在界面上显示转换结果。


讲解完毕,复制代码后,开始运行调试吧~

好了~ 本文就到这里了,感谢您的阅读,每天还有更多的实例学习文章等着你 。别忘了点赞、收藏~ Thanks♪(・ω・)ノ 。

你可能感兴趣的:(C++,c++,学习,qt,qt实例,qt教程,cppqt5)