QT使用数据库

news2024/10/7 16:21:57

数据库就是保存数据的文件。可以存储大量数据,包括插入数据、更新数据、截取数据等。用专业术语来说,数据库是“按照数据结构来组织、存储和管理数据的仓库”。
什么时候需要数据库?在嵌入式里,存储大量数据,或者记录数据,就需要用到数据库。比如手机的闹钟就使用到了数据库,我们设置的闹钟数据将会保存到数据库里,闹钟程序运行时会从数据库里读取出上次保存的闹钟数据。如果没有数据库,则闹钟程序关机了数据不保存在物理储存设备里,下次运行闹钟时就没有上次设置的闹钟数据,这显然是不合理的。所以我们需要用到数据库。想要在项目中使用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可以直接访问其存储文件。

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();
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1563728.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【已解决】Out of memory interning an attribute name

问题描述&#xff1a;pycharm运行程序时报错 Out of memory interning an attribute name 原因分析&#xff1a;pycharm预设内存不足 解决办法&#xff1a;打开pycharm文件所在位置&#xff0c;打开pycharm64.exe.vmoptions配置文件&#xff0c;调整Xmx的大小。

关系(二)利用python绘制热图

关系&#xff08;二&#xff09;利用python绘制热图 热图 &#xff08;Heatmap&#xff09;简介 热图适用于显示多个变量之间的差异&#xff0c;通过颜色判断彼此之间是否存在相关性。 快速绘制 基于seaborn import seaborn as sns import pandas as pd import numpy as np i…

【JavaSE】解密 继承和多态(下)

前言 紧接着上篇 解密继承和多态&#xff08;上&#xff09;~ 欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗~ 如有错误&#xff0c;欢迎指出~ 目录 前言 protected关键字 在同一包下同一类可以访问 代码理解 在同一包下不同类可以访问 代码理解 …

【性能测试】接口测试各知识第1篇:接口测试,学习目标【附代码文档】

接口测试完整教程&#xff08;附代码资料&#xff09;主要内容讲述&#xff1a;接口测试&#xff0c;学习目标学习目标,2. 接口测试课程大纲,3. 接口学完样品,4. 学完课程,学到什么,5. 参考:,1. 理解接口的概念。学习目标&#xff0c;RESTFUL1. 理解接口的概念,2.什么是接口测试…

ZYNQ学习之Ubuntu下Linux文件系统、用户权限与磁盘管理

基本都是摘抄正点原子的文章&#xff1a;<领航者 ZYNQ 之嵌入式Linux 开发指南 V3.2.pdf&#xff0c;因初次学习&#xff0c;仅作学习摘录之用&#xff0c;有不懂之处后续会继续更新~ 一、Linux 文件系统 1.1 Linux 文件系统简介以及类型 操作系统的基本功能之一就是文件管…

JS详解-fetch核心语法

document.querySelector(.btn).addEventListener(click,async () > {const p new URLSearchParams({pname:浙江省,cname:杭州市})//1、如何请求&#xff1f;默认为get&#xff0c;参数1 url地址&#xff0c;返回promiseconst res await fetch(http://hmajax.itheima.net/…

AI提速 OpenAI 新模型GPT-5今年上线?

这两天&#xff0c;有关OpenAI新模型 GPT-5的消息又多了起来。有知情人士称&#xff0c;OpenAI将在今年年中的某个时候发布GPT-5&#xff0c;很可能是在今年夏天期间。OpenAI CEO 萨姆奥特曼在一次播客采访中透露“GPT-5的智能水平得到提升”。 有趣的是&#xff0c;播客的主理…

JavaScript库,编写$()和getElementsByClassName()方法

背景: JavaScript库是一组预先编写好的JavaScript代码集合&#xff0c;旨在简化常见的网页开发任务。这些库通常包含了许多函数和方法&#xff0c;可以帮助开发人员处理各种任务&#xff0c;比如DOM操作、事件处理、动画效果、AJAX请求等等。使用JavaScript库可以节省开发时间…

如何借助AI工具轻松绘制思维导图

前言 思维导图是一种将思维可视化的工具&#xff0c;它可以帮助我们理清思路、提高效率、促进记忆。传统的思维导图绘制方法需要一定的时间和技巧&#xff0c;而借助AI工具&#xff0c;我们可以轻松绘制思维导图&#xff0c;并将更多时间和精力集中在内容本身。 借助AI工具把…

网络以太网之(2)VLAN协议

网络以太网之(1)VLAN协议 Author: Once Day Date: 2024年4月1日 一位热衷于Linux学习和开发的菜鸟&#xff0c;试图谱写一场冒险之旅&#xff0c;也许终点只是一场白日梦… 漫漫长路&#xff0c;有人对你微笑过嘛… 全系列文档可参考专栏&#xff1a;通信网络技术_Once-Day…

输出100~200之间的素数(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//实现素数判断函数&#xff1b; int Prime(int number) {//初始化变量值&#xff1b;int divided 2;int JudgementCondition 0;//循环判断素数&#xff1b;wh…

基于SpringBoot+微信小程序的外卖跑腿点餐(订餐)系统设计与实现+毕业论文(12000字)

介绍 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Spring Boot致力于在蓬勃发展的快速应…

美联储,非必要,不降息

美联储“没必要、没空间、没动力”降息&#xff0c;也会尽量避免货币政策干扰大选&#xff0c;用“口头降息”代替实际调整是现实选择&#xff0c;市场降息预期将继续推迟和下调。 前言&#xff1a; 当前美国经济从各个方面看均并未表现出疲态——新增就业持续修复&#xff0c;…

俄罗斯Yandex广告推广如何开户及费用?

作为俄罗斯首屈一指的搜索引擎&#xff0c;Yandex凭借其超过60%的市场份额&#xff0c;成为企业进入俄罗斯、触及俄语消费者的关键入口。然而&#xff0c;对于不熟悉当地市场环境与网络营销规则的企业而言&#xff0c;成功开户并高效运营Yandex广告并非易事。云衔科技凭借专业的…

大模型量化技术-AWQ

大模型量化技术-AWQ 在2023年6月,Ji Lin等人发表了论文AWQ:Activation-aware Weight Quantization for LLM Compression and Acceleration。 这篇论文详细介绍了一种激活感知权重量化算法,可以用于压缩任何基于 Transformer 的语言模型,同时只有微小的性能下降。关于 AWQ 算…

2024 年云繁荣:驾驭人工智能驱动转型浪潮

在人工智能革命的核心&#xff0c;2024 年见证了云计算应用的空前激增。云计算的繁荣不仅仅是异地存储数据&#xff0c;而是创建动态的智能基础设施&#xff0c;推动人工智能的指数级增长。让我们深入探讨推动这一现象的关键因素和趋势。 01 人工智能和云&#xff1a;共生关系…

Mac上怎么合并多张图片?

Mac上怎么合并多张图片&#xff1f;上班过的小伙伴都应该知道&#xff0c;合并拼接图片是一件非常重要且经常需要使用到的图片处理技术&#xff0c;将多张图片合并拼成一张之后能够展现出更多的图片内容。在Mac电脑上&#xff0c;合并多张图片是一项常见的任务&#xff0c;无论…

鸿蒙OS开发实例:【ArkTS类库多线程@Concurrent装饰器校验并发函数】

在使用TaskPool时&#xff0c;执行的并发函数需要使用该装饰器修饰&#xff0c;否则无法通过相关校验。从API version 9开始&#xff0c;该装饰器支持在ArkTS卡片中使用。 装饰器说明 Concurrent并发装饰器说明装饰器参数无。使用场景仅支持在Stage模型的工程中使用。装饰的函…

2024最新软件测试【测试理论+ 接口测试】面试题(内附答案)

一、测试理论 3.1 你们原来项目的测试流程是怎么样的? 我们的测试流程主要有三个阶段&#xff1a;需求了解分析、测试准备、测试执行。 1、需求了解分析阶段 我们的 SE 会把需求文档给我们自己先去了解一到两天这样&#xff0c;之后我们会有一个需求澄清会议&#xff0c; …

【微信小程序】流量主-激励视频(激励广告)下发策略,每天三次免费体验,然后再次点击触发激励视频,当日不再触发。

如题&#xff1a; 允许用户有三次体验效果&#xff0c;然后弹出激励视频弹窗&#xff0c;之后当日不再弹出。 体验小程序&#xff1a; /*** 判断当前项目当天是否点击超过3次&#xff0c;触发广告效果。* 若&#xff0c;当天低于三次&#xff0c;则新增&#xff0c;若高于…