嵌入式开发如何使用Qt编写上位机

嵌入式技术

1368人已加入

描述

概要

使用Qt编写上位机是一个非常不错的选择,简单说一下作者的看法:

①Qt采用的是C++,所以在某种程度上与嵌入式设备数据类型兼容,所以嵌入式设备与上位机间的协议定义数据结构等都可以相互套用,

②Qt是跨平台的,所以代码开发一次,多平台运行。

③Qt学习成本低,网上资料很多,基本你遇到的问题,网上都能找到。

对于嵌入式开发者来说,会写上位机可以提高开发效率,比如可以开发抓包工具,日志数据分析,升级(网络升级,串口升级等)

说到升级,那么就有些场景,比如批量升级,某台升级等需求。有这些需求那么就要有对应的UI呈现给用户。所以Qt的自定义委托在这种场景显的尤为重要。

嵌入式开发

Qt模型视图中的委托

Qt模型视图采用类MVC框架,那什么是MVC框架?

M--模型:负责组织数据

V--试图:负责显示数据

C--控制:负责用户输入

嵌入式开发

Qt模型视图设计:①视图中集成了处理用户输入的功能,②视图将用户输入作为内部独立的子功能实现

嵌入式开发

模型视图中的委托:①委托是视图中处理用户输入的部件。②视图可以设置委托对象用于用户输入。③委托对象负责创建和显示用户输入上下文。

Qt 自定义委托--实现批量升级UI

准备工作:下载Qt工具,然后创建一个基类为QMainWindow的工程,并且带ui的。

设计一个ui,一个CheckBox控件和TableView控件

嵌入式开发

自定义表格中单选框CheckBox委托 -- 创建QRiceButtonDelegate类继承QItemDelegate

重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入

单选框其实使用按钮项样式(QStyleOptionButton)绘制。

QRiceButtonDelegate源文件

#include "qricecheckboxdelegate.h"

#include 
#include 
#include 
#include 
#include 

QRiceCheckBoxDelegate::QRiceCheckBoxDelegate(QObject *parent)
    : QItemDelegate(parent)
{

}

QRiceCheckBoxDelegate::~QRiceCheckBoxDelegate()
{

}

void QRiceCheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    if(QVariant::Bool == index.data(Qt::DisplayRole).type()) //如果数据类型为bool型,才绘制单选宽 
    {
        QStyleOptionButton checkBox;
        checkBox.state = index.data().toBool() ? QStyle::State_On : QStyle::State_Off; //绘制后的默认状态
        checkBox.state |= QStyle::State_Enabled;
        checkBox.rect = option.rect;
        checkBox.rect.setX(option.rect.x() + option.rect.width()/2 - 6); //设置在表格中的显示位置

        QApplication::style()->drawControl(QStyle::CE_CheckBox, &checkBox, painter);   // 绘制
    }
    else
    {
        QItemDelegate::paint(painter, option, index);
    }
}

bool QRiceCheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    bool ret = true;
    if(QVariant::Bool == index.data().type())
    {
        QMouseEvent* mouse = dynamic_cast(event);

        if( (NULL != mouse) && (QEvent::MouseButtonPress == mouse->type()) && (option.rect.contains(mouse->pos())) )
        {
            model->setData(index, !index.data().toBool(), Qt::DisplayRole); // 更新模型数据
        }
    }
    else
    {
        ret = QItemDelegate::editorEvent(event, model, option, index);
    }

    return ret;
}

QRiceButtonDelegate头文件

#ifndef QRICECHECKBOXDELEGATE_H
#define QRICECHECKBOXDELEGATE_H

#include 

class QRiceCheckBoxDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit QRiceCheckBoxDelegate(QObject *parent = nullptr);
    ~QRiceCheckBoxDelegate();

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
signals:

};

#endif // QRICECHECKBOXDELEGATE_H

自定义表格中进度条ProgressBar委托 -- 创建QRiceProgressBarDelegate类继承QItemDelegate

重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入

进度条其实采用进度条项样式(QStyleOptionProgressBar)绘制。

QRiceProgressBarDelegate源文件

void QRiceProgressBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    int progress = index.data(Qt::DisplayRole).toInt();
    QStyleOptionProgressBar progressBar;

    progressBar.minimum = 0;                                //设置进度条最小值
    progressBar.maximum = 100;                              //设置进度条最大值
    progressBar.progress = progress;                        //设置绘制后的数值
    progressBar.rect = option.rect.adjusted(4, 4, -4, -4);  //设置进度条的大小
    progressBar.textVisible = true;                         //设置进度条显示数值
    progressBar.textAlignment = Qt::AlignCenter;            //设置进度条数值显示位置
    progressBar.text = QString("%1%").arg(progress);        //设置进度条数值显示

    QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBar, painter); // 绘制
}

bool QRiceProgressBarDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    bool ret = true;

    if(QEvent::MouseButtonDblClick != event->type())
    {
        ret = QItemDelegate::editorEvent(event, model, option, index);
    }

    return ret;
}

QRiceProgressBarDelegate头文件

#ifndef QRICEPROGRESSBARDELEGATE_H
#define QRICEPROGRESSBARDELEGATE_H

#include 

class QRiceProgressBarDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit QRiceProgressBarDelegate(QObject *parent = nullptr);
    ~QRiceProgressBarDelegate();

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
signals:

};

#endif // QRICEPROGRESSBARDELEGATE_H

自定义表格中按纽Button委托 -- 创建QRiceButtonDelegate类继承QItemDelegate

重写paint方法和editorEvent方法,其中paint用于绘制,editorEvent用于处理用户输入

按钮其实按钮项样式(QStyleOptionButton)绘制。

QRiceButtonDelegate源文件

void QRiceButtonDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
    QStyleOptionButton *buttonStyle = buttonDelegate.value(index);
    if(!buttonStyle)
    {
        buttonStyle = new QStyleOptionButton();          // 创建按钮项样式
        buttonStyle->text = "Update";                    // 设置按钮中显示的内容
        buttonStyle->state |= QStyle::State_Enabled;     // 设置按钮中的状态
        (const_cast(this))->buttonDelegate.insert(index, buttonStyle);
    }
    buttonStyle->rect = option.rect.adjusted(4, 4, -4, -4); //设置按钮的大小
    painter->save();

    if (option.state & QStyle::State_Selected) {
        painter->fillRect(option.rect, option.palette.highlight());
    }

    painter->restore();
    QApplication::style()->drawControl(QStyle::CE_PushButton, buttonStyle, painter);   //绘制
}

bool QRiceButtonDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
    Q_UNUSED(model);
    Q_UNUSED(option);
    QMouseEvent *mouseEvent = (QMouseEvent *)event;

    if(event->type() == QEvent::MouseButtonPress)              // 按钮按下,设置按钮的状态
    {
        if(buttonDelegate.contains(index))
        {
            QStyleOptionButton *buttonStyle = buttonDelegate.value(index);
            if(buttonStyle->rect.contains(mouseEvent->x(), mouseEvent->y()))
            {
                buttonStyle->state |= QStyle::State_Sunken;
            }
        }
    }
    if(event->type() == QEvent::MouseButtonRelease)         // 按钮松开,设置按钮的状态
    {
        if(buttonDelegate.contains(index))
        {
            QStyleOptionButton *buttonStyle = buttonDelegate.value(index);
            if(buttonStyle->rect.contains(mouseEvent->x(), mouseEvent->y()))
            {
                buttonStyle->state &= (~QStyle::State_Sunken);
                showMsg(tr("btn1 column %1").arg(index.row()));   // 松开弹出消息框,显示对应行号
            }
        }
    }

    return true;
}

void QRiceButtonDelegate::showMsg(QString str)
{
    QMessageBox msg;
    msg.setText(str);
    msg.exec();
}

QRiceButtonDelegate头文件

#ifndef QRICEBUTTONDELEGATE_H
#define QRICEBUTTONDELEGATE_H

#include 

class QRiceButtonDelegate : public QItemDelegate
{
    Q_OBJECT
public:
    explicit QRiceButtonDelegate(QObject *parent = nullptr);
    ~QRiceButtonDelegate();

    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
    bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
signals:

private:
    void showMsg(QString str);

private:
    typedef QMap collButtons;
    collButtons buttonDelegate;
};

#endif // QRICEBUTTONDELEGATE_H

创建一个自定义QRiceTableView类继承QTableView类

构造方法实现:①创建QStandardItemModel模型。②创建单选框委托到视图中。③创建进度条委托到视图第五列中。④创建按钮委托到视图第六列中。⑤设置表格视图的头部。

QRiceTableView::QRiceTableView(QWidget *parent) :
    QTableView(parent)
{
    horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

    tableItemModel = new QStandardItemModel();
    setModel(tableItemModel);

    tableCheckBoxDelegate = new QRiceCheckBoxDelegate(this);
    setItemDelegate(tableCheckBoxDelegate);

    tableProgressBarDelegate = new QRiceProgressBarDelegate(this);
    setItemDelegateForColumn(4, tableProgressBarDelegate);

    tableButtonDelegate = new QRiceButtonDelegate(this);
    setItemDelegateForColumn(5, tableButtonDelegate);

    QStringList tableHeaders;
    tableHeaders << tr("Select")  <setHorizontalHeaderLabels(tableHeaders);
}

在QRiceTableView中实现用户使用方法:

方法 说明
int QRiceTableGetRow(void); 获取列表行数
int QRiceTableGetColumn(void); 获取列表列数
void QRiceTableAddItem(int row, struct tableItemInfo *info); 增加一行
void QRiceTableSetProgress(int row, int Progress); 设置某行的进度条
void QRiceTableSetSelect(int row, bool select); 单选框状态设置
bool QRiceTableGetSelect(int row); 单选框状态获取
QString QRiceTableGetString(int row, int column); 获取某行某列的数据

在QRiceTableView中方法代码:

int QRiceTableView::QRiceTableGetRow(void)
{
    return tableItemModel->rowCount();
}

int QRiceTableView::QRiceTableGetColumn(void)
{
    return tableItemModel->columnCount();
}

void QRiceTableView::QRiceTableAddItem(int row, struct tableItemInfo *info)
{
    QStandardItem* otaDeviceListStandardItem = tableItemModel->invisibleRootItem();

    QStandardItem *checkBox = new QStandardItem();
    QStandardItem *name = new QStandardItem();
    QStandardItem *age = new QStandardItem();
    QStandardItem *work = new QStandardItem();

    checkBox->setData(false, Qt::DisplayRole);
    name->setData(info->name, Qt::DisplayRole);
    age->setData(info->age, Qt::DisplayRole);
    work->setData(info->work, Qt::DisplayRole);

    otaDeviceListStandardItem->setChild(row, 0, checkBox);
    otaDeviceListStandardItem->setChild(row, 1, name);
    otaDeviceListStandardItem->setChild(row, 2, age);
    otaDeviceListStandardItem->setChild(row, 3, work);
}

void QRiceTableView::QRiceTableSetProgress(int row, int Progress)
{
    if(row < tableItemModel->rowCount())
    {
        QModelIndex index = tableItemModel->index(row, 4);
        tableItemModel->setData(index, Progress, Qt::DisplayRole);
    }
}

void QRiceTableView::QRiceTableSetSelect(int row, bool select)
{
    if(row < tableItemModel->rowCount())
    {
        QModelIndex index = tableItemModel->index(row, 0);
        tableItemModel->setData(index, select, Qt::DisplayRole);
    }
}

bool QRiceTableView::QRiceTableGetSelect(int row)
{
    if(row < tableItemModel->rowCount())
    {
        QModelIndex index = tableItemModel->index(row, 0);
        return index.data(Qt::DisplayRole).toBool();
    }
    return false;
}

QString QRiceTableView::QRiceTableGetString(int row, int column)
{
    if(row < tableItemModel->rowCount()
       && column > 0 && column < (tableItemModel->columnCount() - 2))
    {
        QModelIndex index = tableItemModel->index(row, column);
        return index.data(Qt::DisplayRole).toString();
    }
    return "";
}

QRiceTableView头文件:

#ifndef QRICETABLEVIEW_H
#define QRICETABLEVIEW_H

#include 

#include 
#include "qricecheckboxdelegate.h"
#include "qriceprogressbardelegate.h"
#include "qricebuttondelegate.h"

class QRiceTableView : public QTableView
{
    Q_OBJECT
public:
    struct tableItemInfo
    {
        QString name;
        QString age;
        QString work;
    };
public:
    explicit QRiceTableView(QWidget *parent = nullptr);
    ~QRiceTableView();

signals:

public:
    int QRiceTableGetRow(void);
    int QRiceTableGetColumn(void);
    void QRiceTableAddItem(int row, struct tableItemInfo *info);
    void QRiceTableSetProgress(int row, int Progress);
    void QRiceTableSetSelect(int row, bool select);
    bool QRiceTableGetSelect(int row);
    QString QRiceTableGetString(int row, int column);

private:
    QStandardItemModel *tableItemModel;

    QRiceCheckBoxDelegate *tableCheckBoxDelegate;
    QRiceProgressBarDelegate *tableProgressBarDelegate;
    QRiceButtonDelegate *tableButtonDelegate;
};

#endif // QRICETABLEVIEW_H

将UI中的QTableView提升为QRiceTableView:

右击QTableView控件,选择提升为:

嵌入式开发

填写对应类名,类的头文件相对路径:

嵌入式开发

点击添加后,然后点击提升按钮,就完成了控件的提升

在mainwindow.cpp中增加测试用例:

在构造方法中,创建两条数据,并且启动一个定时器刷新进度条:

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

    setWindowTitle(tr("Rice Delegate"));

    struct QRiceTableView::tableItemInfo info;
    info.name = tr("RiceChen");
    info.age = tr("18");
    info.work = tr("程序员");
    ui->tableView->QRiceTableAddItem(0, &info);

    info.name = tr("米饭");
    info.age = tr("20");
    info.work = tr("公务员");
    ui->tableView->QRiceTableAddItem(1, &info);

    QTimer * timer = new QTimer(this);
    connect(timer,&QTimer::timeout,[=](){
            static int Progress1 = 0;
            static int Progress2 = 0;

            ui->tableView->QRiceTableSetProgress(0, Progress1);
            ui->tableView->QRiceTableSetProgress(1, Progress2);
            Progress1 += 1;
            Progress2 += 2;
            if(Progress1 > 100)
            {
                Progress1 = 0;
            }
            if(Progress2 > 100)
            {
                Progress2 = 0;
            }
    });
    timer->start(1000);
}

界面中全选框的实现:

void MainWindow::on_allCheckBox_clicked()
{
    for(int row = 0; row < ui->tableView->QRiceTableGetRow(); row++)
    {
        if(ui->allCheckBox->checkState() == Qt::Checked)
        {
            ui->tableView->QRiceTableSetSelect(row, true);
        }
        else
        {
            ui->tableView->QRiceTableSetSelect(row, false);
        }
    }
}

最终呈现结果:

嵌入式开发

编辑:黄飞

 

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分