数据库就是保存数据的文件。可以存储大量数据,包括插入数据、更新数据、截取数据等。用专业术语来说,数据库是“按照数据结构来组织、存储和管理数据的仓库”。
什么时候需要数据库?在嵌入式里,存储大量数据,或者记录数据,就需要用到数据库。比如手机的闹钟就使用到了数据库,我们设置的闹钟数据将会保存到数据库里,闹钟程序运行时会从数据库里读取出上次保存的闹钟数据。如果没有数据库,则闹钟程序关机了数据不保存在物理储存设备里,下次运行闹钟时就没有上次设置的闹钟数据,这显然是不合理的。所以我们需要用到数据库。想要在项目中使用Qt SQL模块,需要在项目配置文件里添加QT += core gui sql

Qt SQL模块为数据库提供了编程支持,Qt支持很多种常见的数据库,如MySQL、Oracle、MS SQL Server、SQLite等。Qt SQL模块里包含了很多个类,可以轻松实现数据库的连接、执行SQL语句,获取数据库里的数据与界面显示等功能,一般数据与界面之间会采用Model/View架构,很方便的显示数据界面和操作数据库。在嵌入式里,一般常用的数据库就是Sqlite3。SQLite是非常小的,是轻量级的,完全配置时小于400KB,省略可选功能配置时小于250KB。SQLite是一个进程内的库,实现了自给自足的、无服务器的、零配置的、事务性的SQL数据库引擎。它是一个零配置的数据库,这意味着与其他数据库不一样,您不需要在系统中配置。就像其他数据库SQLite引擎不是一个独立的进程,可以按应用程序需求进行静态或动态连接。SQLite可以直接访问其存储文件。

QT使用数据库-LMLPHP

pro文件

QT       += core gui sql

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp \
    numberpicker.cpp \
    switchbutton.cpp

HEADERS += \
    mainwindow.h \
    numberpicker.h \
    switchbutton.h

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    res.qrc

main.cpp

#include "mainwindow.h"
#include <QApplication>
#include <QFile>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    /* 指定文件 */
    QFile file(":/style.qss");
    /* 判断文件是否存在 */
    if (file.exists() ) 
	{
        /* 以只读的方式打开 */
        file.open(QFile::ReadOnly);
        /* 以字符串的方式保存读出的结果 */
        QString styleSheet = QLatin1String(file.readAll());
        /* 设置全局样式 */
        qApp->setStyleSheet(styleSheet);
        /* 关闭文件 */
        file.close();
    }
    MainWindow w;
    w.show();
    return a.exec();
}

 

MainWindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QSqlDatabase>
#include <QSqlQuery>
#include <QMainWindow>
#include <QDialog>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QPushButton>
#include <QListWidget>
#include <QLabel>
#include <QTime>
#include <QSqlTableModel>
#include "numberpicker.h"
#include "switchbutton.h"

class NumberPicker;
class SwitchButton;

/* ListWiget项结构体 */
struct ItemObjectInfo {
    /* 闹钟开关 */
    SwitchButton *switchButton;
    /* Widget容器 */
    QWidget *widget;
    /* 水平布局 */
    QHBoxLayout *hBoxLayout;
};


class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:

    /* 数据库连接类 */
    QSqlDatabase sqlDatabase;

    /* 数据库操作模型 */
    QSqlTableModel *model;

    /* 时针选择器 */
    NumberPicker *hourPicker;

    /* 分钟选择器 */
    NumberPicker *minutePicker;

    /* 弹出选择时间对话框 */
    QDialog *alarmDialog;

    /* 水平布局 */
    QHBoxLayout *hBoxLayout[3];

    /* 垂直布局 */
    QVBoxLayout *vBoxLayout[2];

    /* 显示闹钟列表 */
    QListWidget *listWidget;

    /* 主Widget */
    QWidget *mainWidget;

    /* 底部Wiget */
    QWidget *bottomWidget;

    /* 弹出对话框布局窗口选择时间容器 */
    QWidget *timeWidget;

    /* 弹出对话框布局窗口按钮容器 */
    QWidget *btWidget;

    /* 添加闹钟按钮 */
    QPushButton *addAlarm;

    /* 确认按钮 */
    QPushButton *yesButton;

    /* 取消按钮 */
    QPushButton *cancelButton;

    /* listWiget项信息存储 */
    QVector<ItemObjectInfo> itemObjectInfo;

private slots:
    /* 添加闹钟按钮被点击 */
    void addAlarmClicked();

    /* 列表被点击 */
    void listWidgetItemClicked(QListWidgetItem *);

    /* 确认按钮被点击 */
    void yesButtonClicked();

    /* 取消按钮被点击 */
    void cancelButtonClicked();

    /* 开关按钮点击 */
    void switchButtonClicked(bool);
};
#endif // MAINWINDOW_H

 MainWindow.cpp

#include "mainwindow.h"
#include <QDebug>
#include <QSqlError>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    /* 设置主窗体的显示位置与大小 */
    this->setGeometry(0, 0, 800, 480);

    /* 查看本机可用的数据库驱动 */
    QStringList drivers = QSqlDatabase::drivers();
    foreach(QString driver, drivers) {
        qDebug()<<driver;
    }

    /* 以QSQLITE驱动方式打开或者创建数据库 */
    sqlDatabase = QSqlDatabase::addDatabase("QSQLITE");
    sqlDatabase.setDatabaseName("alarm.db");
    /* 以open的方式打开alarm.db数据库,则会创建一个alarm.db */
    if (!sqlDatabase.open())
        qDebug()<<"连接数据库错误"<<sqlDatabase.lastError()<<endl;
    else
        qDebug()<<"连接数据库成功"<<endl;

    QSqlQuery query(sqlDatabase);
    /* 使用指令式创建表 */
    query.exec("create table alarm (id int primary key, time vchar(15), flag vchar(5))");
    /* 以指令的方式插入数据 */
    //query.exec("insert into alarm values(0, '06:00', 'false')");

    model = new QSqlTableModel(this, sqlDatabase);

    /* 模型设置表的名字,需要与数据库的表的名字相同 */
    model->setTable("alarm");

    /* 如果有修改则同步修改到数据库,
     * 注意这个规则需要与tabview这样的控件才生效,
     * 因为tabview可以直接编辑表里的内容 */
    model->setEditStrategy(QSqlTableModel::OnFieldChange);

    /* 成功则返回true,查看数据库里是否有alarm这个表格 */
    model->select();

    /* 如果数据表数据为空,则添加两个闹钟 */
    if (model->rowCount() == 0) {
        /* 插入一行 */
        model->insertRow(model->rowCount());
        /* 在该行插入数据 */
        model->setData(model->index(0, 0), 1);
        model->setData(model->index(0, 1), "06:00");
        model->setData(model->index(0, 2), "false");
        /* 插入数据后记得提交 */
        model->submit();

        /* 再插入一行 */
        model->insertRow(model->rowCount());
        model->setData(model->index(1, 0), 2);
        model->setData(model->index(1, 1), "18:00");
        model->setData(model->index(1, 2), "true");
        /* 提交 */
        model->submit();
    }

    hourPicker = new NumberPicker(this);
    hourPicker->setRange(0, 24);

    minutePicker = new NumberPicker(this);
    minutePicker->setRange(0, 60);

    /* 标签,用于显示时&分 */
    QLabel *label[3];
    label[0] = new QLabel();
    label[1] = new QLabel();
    label[2] = new QLabel();

    QFont font;
    font.setBold(true);
    font.setPixelSize(10);
    QPalette pal;
    pal.setBrush(QPalette::WindowText, QColor(0, 0, 0));

    label[0]->setFont(font);
    label[1]->setFont(font);
    label[2]->setFont(font);

    label[0]->setText(" ");
    label[1]->setText("时");
    label[2]->setText("分");

    /* 主布局初始化 */
    listWidget = new QListWidget();
    mainWidget = new QWidget();
    bottomWidget = new QWidget();
    alarmDialog = new QDialog(this);
    timeWidget = new QWidget();
    btWidget = new QWidget();
    addAlarm = new QPushButton();
    yesButton = new QPushButton();
    cancelButton = new QPushButton();
    vBoxLayout[0] = new QVBoxLayout();
    vBoxLayout[1] = new QVBoxLayout();
    hBoxLayout[0] = new QHBoxLayout();
    hBoxLayout[1] = new QHBoxLayout();
    hBoxLayout[2] = new QHBoxLayout();

    addAlarm->setMaximumSize(84, 84);
    addAlarm->setObjectName("addAlarm");
    addAlarm->setMinimumSize(84, 84);
    bottomWidget->setMinimumHeight(84);
    bottomWidget->setMaximumHeight(84);
    yesButton->setText("确认");
    cancelButton->setText("取消");
    yesButton->setMaximumSize(100, 50);
    yesButton->setMinimumSize(100, 50);
    cancelButton->setMinimumSize(100, 50);
    cancelButton->setMaximumSize(100, 50);
    btWidget->setMaximumHeight(70);
    btWidget->setMinimumHeight(70);
    alarmDialog->setMinimumSize(300, 300);
    alarmDialog->setMaximumSize(300, 300);
    alarmDialog->setModal(true);
    yesButton->setObjectName("yesButton");
    cancelButton->setObjectName("cancelButton");

    /* 主布局 */
    vBoxLayout[0]->addWidget(listWidget);
    vBoxLayout[0]->addWidget(bottomWidget);
    vBoxLayout[0]->setContentsMargins(0, 0, 0, 0);

    mainWidget->setLayout(vBoxLayout[0]);

    setCentralWidget(mainWidget);

    /* 底部按钮布局 */
    hBoxLayout[0]->addWidget(addAlarm);
    hBoxLayout[0]->setContentsMargins(0, 0, 0, 0);
    bottomWidget->setLayout(hBoxLayout[0]);

    /* 对话框布局 */
    vBoxLayout[1]->addWidget(timeWidget);
    vBoxLayout[1]->addWidget(btWidget);
    vBoxLayout[1]->setContentsMargins(0, 0, 0, 0);
    alarmDialog->setLayout(vBoxLayout[1]);

    hBoxLayout[1]->addWidget(label[0]);
    hBoxLayout[1]->addWidget(hourPicker);
    hBoxLayout[1]->addWidget(label[1]);
    hBoxLayout[1]->addWidget(minutePicker);
    hBoxLayout[1]->addWidget(label[2]);
    hBoxLayout[1]->setContentsMargins(0, 0, 0, 0);
    timeWidget->setLayout(hBoxLayout[1]);

    hBoxLayout[2]->addWidget(yesButton);
    hBoxLayout[2]->addWidget(cancelButton);

    btWidget->setLayout(hBoxLayout[2]);

    /* 打印出闹钟数据库里的信息 */
    for (int i = 0; i < model->rowCount(); i++) {
        for (int j = 0; j < 3; j++) {
            QModelIndex qindex = model->index(i, j);
            switch (j) {
            case 0:
                qDebug()<<"第"<<model->data(qindex).toInt()<<"行数据";
                break;
            case 1:
                listWidget->addItem(model->data(qindex).toString());
                qDebug()<<"闹钟时间为:"<<model->data(qindex).toString();
                break;
            case 2:
                qDebug()<<"闹钟状态为:"
                       <<model->data(qindex).toString()<<endl;
                if (model->data(qindex).toString() != "true")
                    listWidget->item(i)
                            ->setTextColor(QColor(22, 22, 22, 60));
                else
                    listWidget->item(i)
                            ->setTextColor(QColor(22, 22, 22, 225));
                break;
            default:
                break;
            }
        }
    }

    /* 在列表里添加闹钟开关 */
    for (int i = 0; i < model->rowCount(); i++) {
        ItemObjectInfo info;
        info.widget = new QWidget();
        info.switchButton = new SwitchButton();
        info.hBoxLayout = new QHBoxLayout();
        info.switchButton->setMaximumSize(55, 30);
        info.switchButton->setMinimumSize(55, 30);
        info.hBoxLayout->setContentsMargins(0, 0, 0, 0);
        info.hBoxLayout->setAlignment(Qt::AlignRight);
        info.hBoxLayout->addWidget(info.switchButton);
        info.widget->setLayout(info.hBoxLayout);
        listWidget->setItemWidget(listWidget->item(i),
                                  info.widget);
        itemObjectInfo.append(info);

        /* 连接信号槽 */
        connect(info.switchButton,
                SIGNAL(toggled(bool)),
                this,
                SLOT(switchButtonClicked(bool)));

        /* 获取数据库里的闹钟开关状态 */
        QModelIndex qindex = model->index(i, 2);
        if (model->data(qindex).toBool())
            /* 设置列表里的闹钟开关按钮状态 */
            info.switchButton->setToggle(true);
    }

    /* 按钮 */
    connect(addAlarm, SIGNAL(clicked()), this,
            SLOT(addAlarmClicked()));

    connect(yesButton, SIGNAL(clicked()), this,
            SLOT(yesButtonClicked()));

    connect(cancelButton, SIGNAL(clicked()), this,
            SLOT(cancelButtonClicked()));

    /* 列表 */
    connect(listWidget,
            SIGNAL(itemClicked(QListWidgetItem*)),
            this,
            SLOT(listWidgetItemClicked(QListWidgetItem*)));
}

MainWindow::~MainWindow()
{
    /* 关闭数据库 */
    sqlDatabase.close();
}

void MainWindow::addAlarmClicked()
{
    /* 选择时间对话框里显示当前系统时间 */
    hourPicker->setValue(QTime::currentTime().hour());
    minutePicker->setValue(QTime::currentTime().minute());

    /* 取消按钮显示文本为"取消" */
    cancelButton->setText("取消");

    /* 如果是点击添加闹钟的按钮,则设置闹钟列表的索引index为-1 */
    listWidget->setCurrentRow(-1);

    /* 显示对话框 */
    alarmDialog->show();
}

void MainWindow::listWidgetItemClicked(QListWidgetItem *item)
{
    /* 从被点击项里获取闹钟数据 */
    QStringList list =
            listWidget->item(listWidget->row(item))->text().split(":");

    /* 选择时间对话框里显示被选择项的时间 */
    hourPicker->setValue(list.at(0).toInt());
    minutePicker->setValue(list.at(1).toInt());

    /* 取消按钮显示文本为"删除" */
    cancelButton->setText("删除");

    /* 显示闹钟选择对话框 */
    alarmDialog->show();

    /* 作用使其失去选择 */
    listWidget->clearSelection();
}

void MainWindow::yesButtonClicked()
{
    /* 获取数值选择值的数据,转为字符串 */
    QString hour;
    QString minute;

    if (hourPicker->readValue() < 10)
        hour = "0" + QString::number(hourPicker->readValue()) + ":";
    else
        hour = QString::number(hourPicker->readValue()) + ":";

    if (minutePicker->readValue() < 10)
        minute = "0" + QString::number(minutePicker->readValue());
    else
        minute = QString::number(minutePicker->readValue());

    /* 如果不是选中闹钟列表的数据 */
    if (listWidget->currentRow() == -1) {
        /* 插入一行数据,闹钟时间为选择的闹钟时间 */
        int row = model->rowCount();

        /* 插入数据到数据库 */
        model->insertRow(row);
        model->setData(model->index(row, 0), row + 1);
        model->setData(model->index(row, 1), hour + minute);
        model->setData(model->index(row, 2), "true");
        model->submit();

        /* 添加闹钟到列表 */
        listWidget->addItem(hour + minute);

        /* 添加到容器 */
        ItemObjectInfo info;
        info.widget = new QWidget();
        info.switchButton = new SwitchButton();
        info.hBoxLayout = new QHBoxLayout();
        info.switchButton->setMaximumSize(55, 30);
        info.switchButton->setMinimumSize(55, 30);
        info.hBoxLayout->setContentsMargins(0, 0, 0, 0);
        info.hBoxLayout->setAlignment(Qt::AlignRight);
        info.hBoxLayout->addWidget(info.switchButton);
        info.widget->setLayout(info.hBoxLayout);
        info.switchButton->setToggle(true);

        /* 连接信号槽 */
        connect(info.switchButton, SIGNAL(toggled(bool)), this,
                SLOT(switchButtonClicked(bool)));

        listWidget->setItemWidget(
                    listWidget->item(listWidget->count() - 1),
                    info.widget);
        itemObjectInfo.append(info);
    } else {
        /* 修改数据(更新闹钟数据) */
        int row =  listWidget->currentRow();
        model->setData(model->index(row, 0), row + 1);
        model->setData(model->index(row, 1), hour + minute);
        model->setData(model->index(row, 2), "true");
        model->submit();

        /* 设置当前项的闹钟文本 */
        listWidget->currentItem()->setText(hour + minute);
    }

    /* 再确保提交 */
    if (model->isDirty())
        model->submitAll();

    /* 关闭对话框 */
    alarmDialog->close();
}

void MainWindow::cancelButtonClicked()
{
    if (cancelButton->text() == "删除") {
        /* 删除数据库整一行数据 */
        model->removeRow(listWidget->currentRow());
        model->submit();
        /* 执行上面语句 */
        model->select();
        itemObjectInfo.remove(listWidget->currentRow());
        listWidget->takeItem(listWidget->currentRow());
    }

    /* 再确保提交 */
    if (model->isDirty())
        model->submitAll();

    /* 关闭对话框 */
    alarmDialog->close();
}


/* 当点击闹钟开关时,将闹钟开关状态同步更新到数据库里 */
void MainWindow::switchButtonClicked(bool checked)
{
    listWidget->clearSelection();

    SwitchButton *button = (SwitchButton *)sender();
    for (int i = 0; i < itemObjectInfo.count(); i++) {
        if (button == itemObjectInfo.at(i).switchButton) {
            if (checked) {
                model->setData(model->index(i, 2), "true");
                listWidget->item(i)
                        ->setTextColor(QColor(22, 22, 22, 225));
            } else {
                model->setData(model->index(i, 2), "false");
                listWidget->item(i)
                        ->setTextColor(QColor(22, 22, 22, 60));
            }

            model->submit();
            break;
        }
    }
}

numberpicker.h

#ifndef NUMBERPICKER_H
#define NUMBERPICKER_H

#include <QMainWindow>
#include <QPropertyAnimation>

class NumberPicker : public QWidget
{
    Q_OBJECT

    Q_PROPERTY(int deviation READ readDeviation WRITE setDeviation )
public:
    NumberPicker(QWidget *parent = nullptr);
    ~NumberPicker();

    /* 设置最大值与最小值的范围 */
    void setRange(int min, int max);

    /* 读取当前值 */
    int readValue();

protected:
    void mousePressEvent(QMouseEvent *);

    void mouseMoveEvent(QMouseEvent *);

    void mouseReleaseEvent(QMouseEvent *);

    void wheelEvent(QWheelEvent *);

    void paintEvent(QPaintEvent *);

public:
    /* 描绘数字 */
    void paintNum(QPainter &painter, int num, int deviation);

    /* 使选中的数字回到屏幕中间 */
    void homing();

    /* 鼠标移动偏移量,默认为0 */
    int readDeviation();

    /* 设置偏移量 */
    void setDeviation(int n);

    /* 设置字体大小 */
    void setNumSize(int);

    /* 设置间隔大小 */
    void setInterval(int);

    /* 设置分格数量,一般设置为3、5、7... */
    void setDevide(int);

    /* 设置数字颜色,设置rgb的数值 */
    void setNumberColor(QRgb rgb);

    /* 设置当前值 */
    void setValue(int value);

signals:

    void currentValueChanged(int value);

    void deviationChange(int deviation);

private:
    /* 最小值 */
    int minRange;

    /* 最大值 */
    int maxRange;

    /* 当前选中的值 */
    int currentValue;

    /* 鼠标是否按下 */
    bool isDragging;

    /* 偏移量,记录鼠标按下后移动的垂直距离 */
    int deviation;

    /* 鼠标按下的垂直位置 */
    int mouseSrcPos;

    /* 数字大小 */
    int numSize;

    /* 动画 */
    QPropertyAnimation *homingAni;

    /* 间隔大小 */
    int interval;

    /* 分格数量 */
    int devide;

    /* 数字颜色 */
    QColor numberColor;
};
#endif // NUMBERPICKER_H

numberpicker.cpp

#include <QMouseEvent>
#include <QDebug>
#include "numberpicker.h"
#include <QPainter>

NumberPicker::NumberPicker(QWidget *parent) :
    /* 最小值默认为0 */
    minRange(0),

    /* 最大值默认60 */
    maxRange(60),

    /* 当前值默认0 */
    currentValue(0),

    /* 按下标志位为假 */
    isDragging(false),

    /* 默认偏移量为0 */
    deviation(0),

    /* 数值越大 */
    numSize(15),

    /* 间隔为1 */
    interval(1),

    /* 默认分成3格 */
    devide(3),

    /* 默认颜色黑色 */
    numberColor(0, 0, 0)
{
    setParent(parent);
    setMinimumSize(50, 150);
    homingAni = new QPropertyAnimation(this, "deviation");
    homingAni->setDuration(300);
    homingAni->setEasingCurve(QEasingCurve::OutQuad);
}

NumberPicker::~NumberPicker()
{

}

void NumberPicker::setRange(int min, int max)
{
    minRange = min;
    maxRange = max;
    if (currentValue < min) {
        currentValue = min;
    }
    if (currentValue > max) {
        currentValue = max;
    }
    repaint();
}

int NumberPicker::readValue()
{
    return currentValue;
}

void NumberPicker::mousePressEvent(QMouseEvent *e)
{
    homingAni->stop();
    isDragging = true;
    mouseSrcPos = e->pos().y();
    QWidget::mousePressEvent(e);
}

void NumberPicker::mouseMoveEvent(QMouseEvent *e)
{
    if (isDragging){
        deviation = e->pos().y() - mouseSrcPos;

        /* 若移动速度过快,则进行限制 */
        if (deviation > (height() - 1) / devide) {
            deviation = (height() - 1) / devide;
        } else if (deviation < -(height() - 1) / devide) {
            deviation = -( height() - 1) / devide;
        }

        emit deviationChange(deviation / ((height() - 1) / devide));
        repaint();
    }
}

void NumberPicker::mouseReleaseEvent(QMouseEvent *)
{
    if (isDragging) {
        isDragging = false;
        homing();
    }
}

void NumberPicker::wheelEvent(QWheelEvent *e)
{
    if (e->delta() > 0) {
        deviation = (this->height() - 1) / devide;
    } else {
        deviation = -(this->height() - 1) / devide;
    }

    homing();
    repaint();
}

void NumberPicker::paintEvent(QPaintEvent *)
{
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    int Height = height() - 1;

    if (deviation >= Height / devide && currentValue > minRange ) {
        mouseSrcPos += Height / devide;
        deviation -= Height / devide;
        currentValue -= interval;
        /* 负数处理 */
        if (currentValue < 0)
            currentValue = maxRange + currentValue;
    }

    if (deviation <= -Height / devide && currentValue < maxRange ) {
        mouseSrcPos -= Height / devide;
        deviation += Height / devide;
        currentValue += interval;
    }

    if (qAbs(int(currentValue)) >= int(maxRange))
        currentValue = minRange;

    paintNum(painter, qAbs(int(currentValue + maxRange) % maxRange),
             deviation);

    paintNum(painter,
             qAbs((currentValue - interval + maxRange) % maxRange),
             deviation - Height / devide);

    paintNum(painter,
             qAbs((currentValue + interval + maxRange) % maxRange),
             deviation + Height / devide);

    for (int i = 2; i <= devide / 2; ++i) {
        if (qAbs(currentValue - interval * i) >= minRange) {
            paintNum(painter,
                     qAbs((currentValue - interval * i + maxRange)
                          % maxRange),
                     deviation - Height / devide * i);
        }

        if (qAbs(currentValue + interval * i) <= maxRange) {
            paintNum(painter,
                     qAbs((currentValue + interval * i + maxRange)
                          % maxRange),
                     deviation + Height / devide * i);
        }
    }
}

void NumberPicker::paintNum(QPainter &painter, int num, int deviation)
{
    int Width = width() - 1;
    int Height = height() - 1;

    /* 偏移量越大,数字越小 */
    //int size = (Height - qAbs(deviation)) / numSize;
    int size = (Height - qAbs(deviation)) * numSize / 80;
    int transparency = 255 - 255 * qAbs(deviation) / Height;
    int height = Height / devide;
    int y = Height / 2 + deviation - height / 2;

    QFont font;
    font.setPixelSize(size);
    painter.setFont(font);
    painter.setPen(QColor(numberColor.red(),
                          numberColor.green(),
                          numberColor.blue(),
                          transparency));

    if ( y >= 0 && y + height < Height) {
        //painter.drawRect(0, y, Width, height);
        if (num < 10)
            painter.drawText(QRectF(0, y, Width, height),
                             Qt::AlignCenter,
                             "0" + QString::number(num, 'f', 0));
        else
            painter.drawText(QRectF(0, y, Width, height),
                             Qt::AlignCenter,
                             QString::number(num, 'f', 0));
    }
}

void NumberPicker::homing()
{
    if (deviation > height() / 10) {
        homingAni->setStartValue((height() - 1 ) / 8 - deviation);
        homingAni->setEndValue(0);
        currentValue -= interval;
    } else if (deviation > -height() / 10) {
        homingAni->setStartValue(deviation);
        homingAni->setEndValue(0);
    } else if (deviation < -height() / 10) {
        homingAni->setStartValue(-(height() - 1) / 8 - deviation);
        homingAni->setEndValue(0);
        currentValue += interval;
    }

    emit currentValueChanged(currentValue);
    homingAni->start();
}

int NumberPicker::readDeviation()
{
    return deviation;
}

void NumberPicker::setDeviation(int n)
{
    deviation = n;
    repaint();
}

void NumberPicker::setNumSize(int size)
{
    numSize = size;
    repaint();
}

void NumberPicker::setInterval(int n)
{
    interval = n;
    repaint();
}

void NumberPicker::setDevide(int n)
{
    devide = n;
    repaint();
}

void NumberPicker::setNumberColor(QRgb rgb)
{
    numberColor.setRgb(rgb);
    repaint();
}

void NumberPicker::setValue(int value)
{
    if (value < minRange || value > maxRange) 
    {
        qDebug()<<"数值设置必须在"<<minRange<<"和"<<maxRange<<"之间"<<endl;
        return;
    }
    currentValue = value;
    repaint();
}
03-31 10:19