zoukankan      html  css  js  c++  java
  • C/C++ QT之Mode/View 结构

    Model/View其实就是QT中的一种数据编排结构,其中Model代表模型,View代表视图,视图是显示和编辑数据的界面组件,而模型则是视图与原始数据之间的接口,通常该类结构都是用在数据库中较多,例如模型结构负责读取或写入数据库,视图结构则负责展示数据,其条理清晰,编写代码更加方便。

    我们主要的视图组件有:QListView,QTreeView,QTableView 这三种,而这三种结构其实是QListWidget,QTreeWidget,QTableQWidget三个类的便利类,也可以理解为QListView是基类,继承者是QListWIdget,只不过其功能更加强大,继承后做了二次封装。

    一般模型都是以Model结尾,例如QStringListModel可作为StringList的数据模型,QSqlTableModel则可作为数据库中一个数据表的数据模型,这样的结构分明,可以提高程序编写效率与质量。

    QFileSystemModel

    该模型提供了一个访问本机文件系统的接口,通常QFileSystemModel和视图组件QTreeView结合使用,可用来展示系统中的目录文件层级关系。

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        model = new QFileSystemModel(this);        // 初始化,提供单独线程
        model->setRootPath(QDir::currentPath());   // 设置文件根目录
    
        QStringList filter;
        filter << "*.txt" << "*.mp4";
    
        model->setNameFilters(filter);
        model->setNameFilterDisables(false);
        ui->treeView->setModel(model);             // 设置数据模型
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    // 当TreeView被点击则触发事件
    void MainWindow::on_treeView_clicked(const QModelIndex &index)
    {
    }
    

    QStringListModel

    该组件常用于处理字符串列表的数据模型,可作为QListView的模型接口使用,QStringListModel提供了编辑修改删除等功能的实现。

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // 初始化一个StringList字符串列表
        QStringList theStringList;
        theStringList << "北京" << "上海" << "广州";
    
        // 创建并使用数据模型
        model = new QStringListModel(this);     // 创建模型
        model->setStringList(theStringList);    // 导入模型数据
    
        ui->listView->setModel(model);          // 为listView设置模型
        ui->listView->setEditTriggers(QAbstractItemView::DoubleClicked |
                                      QAbstractItemView::SelectedClicked);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    // 添加一行
    void MainWindow::on_btnListAppend_clicked()
    {
        model->insertRow(model->rowCount());                       // 在尾部插入一行
        QModelIndex index = model->index(model->rowCount()-1,0);   // 获取最后一行的索引
        QString LineText = ui->lineEdit->text();
        model->setData(index,LineText,Qt::DisplayRole);            // 设置显示文字
        ui->listView->setCurrentIndex(index);                      // 设置当前行选中
        ui->lineEdit->clear();
    }
    
    // 插入一行数据到ListView
    void MainWindow::on_btnListInsert_clicked()
    {
        QModelIndex index;
    
        index= ui->listView->currentIndex();             // 获取当前选中行
        model->insertRow(index.row());                   // 在当前行的前面插入一行
        QString LineText = ui->lineEdit->text();
        model->setData(index,LineText,Qt::DisplayRole);             // 设置显示文字
        model->setData(index,Qt::AlignRight,Qt::TextAlignmentRole); // 设置对其方式
        ui->listView->setCurrentIndex(index);                       // 设置当前选中行
    }
    
    // 删除当前选中行
    void MainWindow::on_btnListDelete_clicked()
    {
        QModelIndex index;
        index = ui->listView->currentIndex();    // 获取当前行的ModelIndex
        model->removeRow(index.row());           // 删除选中行
    }
    
    // 清除当前列表
    void MainWindow::on_btnListClear_clicked()
    {
       model->removeRows(0,model->rowCount());
    }
    
    // 显示数据模型文本到QPlainTextEdit
    void MainWindow::on_btnTextImport_clicked()
    {
        QStringList pList;
    
        pList = model->stringList();    // 获取数据模型的StringList
        ui->plainTextEdit->clear();     // 先清空文本框
    
        // 循环追加数据
        for(int x=0;x< pList.count();x++)
        {
            ui->plainTextEdit->appendPlainText(pList.at(x) + QString(","));
        }
    }
    
    // 当ListView列表项被选中时,显示QModelIndex的行、列号
    void MainWindow::on_listView_clicked(const QModelIndex &index)
    {
            ui->LabInfo->setText(QString::asprintf("当前项:row=%d, column=%d",
                                index.row(),index.column()));
    }
    

    QStandardItemModel

    该模型是标准的一项数据为基础的标准数据模型类,通常与QTableView组合成M/V结构,实现通用二维数据的管理功能。

    如何添加,菜单栏,只需要在空白处右键选择【添加工具栏】即可。

    添加不同的菜单,只需要在下方添加,然后手动将菜单拖到工具栏上即可。

    打开文件,可以这样写。

    // 【打开文件】:当工具栏中打开文件被点击后则触发
    void MainWindow::on_actionOpen_triggered()
    {
        QString curPath=QCoreApplication::applicationDirPath(); // 获取应用程序的路径
        // 调用打开文件对话框打开一个文件
        QString aFileName=QFileDialog::getOpenFileName(this,"打开一个文件",curPath,"数据文件(*.txt);;所有文件(*.*)");
        if (aFileName.isEmpty())
        {
            return; // 如果未选择文件则退出
        }
    
        QStringList fFileContent;                              // 文件内容字符串列表
        QFile aFile(aFileName);                                // 以文件方式读出
        if (aFile.open(QIODevice::ReadOnly | QIODevice::Text)) // 以只读文本方式打开文件
        {
            QTextStream aStream(&aFile);       // 用文本流读取文件
            ui->plainTextEdit->clear();        // 清空列表
            // 循环读取只要不为空
            while (!aStream.atEnd())
            {
                QString str=aStream.readLine();          // 读取文件的一行
                ui->plainTextEdit->appendPlainText(str); // 添加到文本框显示
                fFileContent.append(str);                // 添加到StringList
            }
            aFile.close();                               // 关闭文件
    
            iniModelFromStringList(fFileContent);        // 从StringList的内容初始化数据模型
        }
    
        // 打开文件完成后,就可以将Action全部开启了
        ui->actionSave->setEnabled(true);
        ui->actionView->setEnabled(true);
        ui->actionAppend->setEnabled(true);
        ui->actionDelete->setEnabled(true);
        ui->actionInsert->setEnabled(true);
    
        // 打开文件成功后,设置状态栏当前文件列
        this->LabCurFile->setText("当前文件:"+aFileName);//状态栏显示
    }
    

    文件读写,保存文件可以这样。

    // 【保存文件】:当保存文件被点击后触发
    void MainWindow::on_actionSave_triggered()
    {
        QString curPath=QCoreApplication::applicationDirPath(); // 获取应用程序的路径
    
        // 调用打开文件对话框选择一个文件
        QString aFileName=QFileDialog::getSaveFileName(this,tr("选择一个文件"),curPath,"数据文件(*.txt);;所有文件(*.*)");
    
        if (aFileName.isEmpty()) // 未选择文件则直接退出
            return;
    
        QFile aFile(aFileName);
    
        // 以读写、覆盖原有内容方式打开文件
        if (!(aFile.open(QIODevice::ReadWrite | QIODevice::Text | QIODevice::Truncate)))
            return;
    
        QTextStream aStream(&aFile);    // 用文本流读取文件
        QStandardItem *Item;
        QString str;
        int x = 0,y = 0;
    
        ui->plainTextEdit->clear();
    
    // 获取表头文字
        for (x=0; x<model->columnCount(); x++)
        {
            Item=model->horizontalHeaderItem(x);     // 获取表头的项数据
            str= str + Item->text() + "		";        // 以TAB制表符隔开
        }
        aStream << str << "
    ";                      // 文件里需要加入换行符
    
        ui->plainTextEdit->appendPlainText(str);
    
    // 获取数据区文字
        for ( x=0; x < model->rowCount(); x++)
        {
            str = "";
            for( y=0; y < model->columnCount()-1; y++)
            {
                Item=model->item(x,y);
                str=str + Item->text() + QString::asprintf("		");
            }
    
            // 对最后一列需要转换一下,如果判断为选中则写1否则写0
            Item=model->item(x,y);
            if (Item->checkState()==Qt::Checked)
                str= str + "1";
            else
                str= str + "0";
    
             ui->plainTextEdit->appendPlainText(str);
             aStream << str << "
    ";
        }
    }
    

    格式化文件输入输出。 QStandardItem -与表格的导入导出 ,对表格的各种操作。

    QAbstractItemDelegate 自定义代理类

    代理类的作用是用来实现重写的,例如我们的TableView中默认是可编辑的,这个可编辑的组件是QT默认为我们重写了QLineEdit组件,也可理解为将组件嵌入到了表格中,实现了,可对表格的编辑功能,例如如下案例中,的样子,默认情况下,表格是可编辑的,这就是默认重写。

    初始化代码如下。

    #include <QMainWindow>
    #include <QLabel>
    #include <iostream>
    #include <QStandardItem>
    #include <QItemSelectionModel>
    
    #define FixedColumnCount 5    // 定义最大5列
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        Ui::MainWindow *ui;
    
        QStandardItemModel *model;      // 定义数据模型
        QItemSelectionModel *selection; // 定义Item选择模型
    };
    #endif // MAINWINDOW_H
    
    
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    // 默认构造函数
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        model = new QStandardItemModel(4,FixedColumnCount,this);
        selection = new QItemSelectionModel(model);
    
        ui->tableView->setModel(model);
        ui->tableView->setSelectionModel(selection);
    
    
        // 添加表头
        QStringList HeaderList;
        HeaderList << "序号" << "姓名" << "年龄" << "性别" << "婚否";
        model->setHorizontalHeaderLabels(HeaderList);
    
        // 批量添加数据
        QStringList DataList[3];
        QStandardItem *Item;
    
        DataList[0] << "1001" << "admin" << "24" << "男" << "是";
        DataList[1] << "1002" << "lyshark" << "23" << "男" << "否";
        DataList[2] << "1003" << "lucy" << "37" << "女" << "是";
    
        int Array_Length = DataList->length();                          // 获取每个数组中元素数
        int Array_Count = sizeof(DataList) / sizeof(DataList[0]);       // 获取数组个数
    
        for(int x=0; x<Array_Count; x++)
        {
            for(int y=0; y<Array_Length; y++)
            {
                // std::cout << DataList[x][y].toStdString().data() << std::endl;
                Item = new QStandardItem(DataList[x][y]);
                model->setItem(x,y,Item);
            }
        }
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    在QT中,代理类是有层级关系的,所有的代理都来自于QAbstractItemDelegate这个抽象基类,下面学习以下代理类的使用。

    先来实现一个代理,代理到Spin组件上,首先需要在项目上右键,选择addnew -> C++ Class 输入自定义类名称QWintSpinDelegate,然后基类继承QStyledItemDelegate/QMainWindow,然后下一步结束向导。

    qwintspindelegate.h 改为

    #ifndef QWINTSPINDELEGATE_H
    #define QWINTSPINDELEGATE_H
    
    #include <QMainWindow>
    #include <QStyledItemDelegate>
    
    class QWIntSpinDelegate : public QStyledItemDelegate
    {
        Q_OBJECT
    public:
        QWIntSpinDelegate(QObject *parent=0);
        QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;
        void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
        void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const Q_DECL_OVERRIDE;
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;
    };
    
    
    #endif // QWINTSPINDELEGATE_H
    

    qwintspindelegate.cpp

    #include "qwintspindelegate.h"
    #include    <QSpinBox>
    
    QWIntSpinDelegate::QWIntSpinDelegate(QObject *parent):QStyledItemDelegate(parent)
    {
    
    }
    QWidget *QWIntSpinDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        Q_UNUSED(option);
        Q_UNUSED(index);
    
        QSpinBox *editor = new QSpinBox(parent);
        editor->setFrame(false);
        editor->setMinimum(0);
        editor->setMaximum(10000);
        return editor;
    }
    
    void QWIntSpinDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
    {
        int value = index.model()->data(index, Qt::EditRole).toInt();
        QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
        spinBox->setValue(value);
    }
    
    void QWIntSpinDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
        QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
        spinBox->interpretText();
        int value = spinBox->value();
        model->setData(index, value, Qt::EditRole);
    }
    
    void QWIntSpinDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        Q_UNUSED(index);
        editor->setGeometry(option.rect);
    }
    

    最后在mainwindow.h引用

    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QMainWindow>
    #include <QLabel>
    #include <iostream>
    
    #include <QStandardItem>
    #include <QStandardItemModel>
    #include <QItemSelectionModel>
    
    #include "qwintspindelegate.h"
    
    
    QT_BEGIN_NAMESPACE
    namespace Ui { class MainWindow; }
    QT_END_NAMESPACE
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
    
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
    
    
    private slots:
        void on_pushButton_clicked();
    
    private:
        Ui::MainWindow *ui;
    
        QStandardItemModel *model;      // 定义数据模型
        QItemSelectionModel *selection; // 定义Item选择模型
    
        QWIntSpinDelegate intSpinDelegate; //整型数
    };
    #endif // MAINWINDOW_H
    

    mainwindow.cpp设置代理

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    // 默认构造函数
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        // 初始化模型数据
        model = new QStandardItemModel(4,5,this);
        selection = new QItemSelectionModel(model);
    
        ui->tableView->setModel(model);
        ui->tableView->setSelectionModel(selection);
    
        // 添加表头
        QStringList HeaderList;
        HeaderList << "序号" << "姓名" << "年龄" << "性别" << "婚否";
        model->setHorizontalHeaderLabels(HeaderList);
    
        // 批量添加数据
        QStringList DataList[3];
        QStandardItem *Item;
    
        DataList[0] << "1001" << "admin" << "24" << "男" << "是";
        DataList[1] << "1002" << "lyshark" << "23" << "男" << "否";
        DataList[2] << "1003" << "lucy" << "37" << "女" << "是";
    
        int Array_Length = DataList->length();                          // 获取每个数组中元素数
        int Array_Count = sizeof(DataList) / sizeof(DataList[0]);       // 获取数组个数
    
        for(int x=0; x<Array_Count; x++)
        {
            for(int y=0; y<Array_Length; y++)
            {
                // std::cout << DataList[x][y].toStdString().data() << std::endl;
                Item = new QStandardItem(DataList[x][y]);
                model->setItem(x,y,Item);
            }
        }
    
        // 为各列设置自定义代理组件
        ui->tableView->setItemDelegateForColumn(0,&intSpinDelegate);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    void MainWindow::on_pushButton_clicked()
    {
    
    }
    

    运行观察代理组件,可发现,第一个位置变成了我们想要的了。

    代理组件实现选择列表,通过重写comboxdelegate实现,.h代码

    #ifndef QWCOMBOBOXDELEGATE_H
    #define QWCOMBOBOXDELEGATE_H
    
    #include <QItemDelegate>
    
    class QWComboBoxDelegate : public QItemDelegate
    {
        Q_OBJECT
    
    public:
        QWComboBoxDelegate(QObject *parent=0);
        QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;
        void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
        void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const Q_DECL_OVERRIDE;
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;
    };
    
    #endif // QWCOMBOBOXDELEGATE_H
    

    comboxdelegate.cpp

    #include "comboxdelegate.h"
    #include <QComboBox>
    
    QWComboBoxDelegate::QWComboBoxDelegate(QObject *parent):QItemDelegate(parent)
    {
    
    }
    
    QWidget *QWComboBoxDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        QComboBox *editor = new QComboBox(parent);
    
        editor->addItem("已婚");
        editor->addItem("未婚");
        editor->addItem("单身");
    
        return editor;
    }
    
    void QWComboBoxDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        QString str = index.model()->data(index, Qt::EditRole).toString();
    
        QComboBox *comboBox = static_cast<QComboBox*>(editor);
        comboBox->setCurrentText(str);
    }
    
    void QWComboBoxDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
        QComboBox *comboBox = static_cast<QComboBox*>(editor);
        QString str = comboBox->currentText();
        model->setData(index, str, Qt::EditRole);
    }
    
    void QWComboBoxDelegate::updateEditorGeometry(QWidget *editor,const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        editor->setGeometry(option.rect);
    }
    

    实现效果。

    TreeView组件(拓展) 三行代码实现目录枚举

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QSplitter>
    #include <QDirModel>
    #include <QTreeView>
    #include <QTextCodec>
    
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
        QDirModel *model = new QDirModel;
    
        ui->treeView->setModel(model);
        ui->treeView->setRootIndex(model->index("c:\"));
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QSplitter>
    #include <QDirModel>
    #include <QTreeView>
    #include <QTextCodec>
    
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        /*
        QDirModel *model = new QDirModel;
    
        ui->treeView->setModel(model);
        ui->treeView->setRootIndex(model->index("c:\"));
        */
    
        QStandardItemModel *tree = new QStandardItemModel(0,3,this);
    
        ui->treeView->setColumnWidth(0,50);      // 设置列chang'd长度
        ui->treeView->setColumnWidth(1,200);
        ui->treeView->setColumnWidth(2,200);
    
        tree->setHeaderData(0, Qt::Horizontal, tr("序号"));
        tree->setHeaderData(1, Qt::Horizontal, tr("姓名"));
        tree->setHeaderData(2, Qt::Horizontal, tr("年龄"));
    
        ui->treeView->setModel(tree);
    
        for (int i = 0; i < 4; ++i)
        {
            // 设置外层
            QList<QStandardItem *> items;
            for (int i = 0; i < 3; ++i)
            {
                QStandardItem *item = new QStandardItem(QString("%0").arg(i));
                if (0 == i)
                    item->setCheckable(true);
                items.push_back(item);
            }
            tree->appendRow(items);
    
            // 设置内层
            for (int i = 0; i < 2; ++i)
            {
                QList<QStandardItem *> childItems;
                for (int i = 0; i < 3; ++i)
                {
                 QStandardItem *item = new QStandardItem(QString("%0").arg(i));
                 if (0 == i)
                     item->setCheckable(true);
                 childItems.push_back(item);
                }
                items.at(0)->appendRow(childItems);
            }
        }
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    

    添加单列,单独添加。

    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    #include <QSplitter>
    #include <QDirModel>
    #include <QTreeView>
    #include <QTextCodec>
    
    MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        /*
        QDirModel *model = new QDirModel;
    
        ui->treeView->setModel(model);
        ui->treeView->setRootIndex(model->index("c:\"));
        */
    
        QStandardItemModel *tree = new QStandardItemModel(0,3,this);
    
        ui->treeView->setColumnWidth(0,50);      // 设置列chang'd长度
        ui->treeView->setColumnWidth(1,200);
        ui->treeView->setColumnWidth(2,200);
    
        tree->setHeaderData(0, Qt::Horizontal, tr("序号"));
        tree->setHeaderData(1, Qt::Horizontal, tr("姓名"));
        tree->setHeaderData(2, Qt::Horizontal, tr("年龄"));
    
        ui->treeView->setModel(tree);
    
        QList<QStandardItem *> ptr;
    
        QStandardItem *item = new QStandardItem("1001");
        ptr.push_back(item);
    
        item = new QStandardItem("lyshark");
        ptr.push_back(item);
    
        item = new QStandardItem("22");
        ptr.push_back(item);
    
        tree->appendRow(ptr);
    }
    


    版权声明: 本博客,文章与代码均为学习时整理的笔记,博客中除去明确标注有参考文献的文章,其他文章【均为原创】作品,转载请务必【添加出处】,您添加出处是我创作的动力!

    警告:如果您恶意转载本人文章,则您的整站文章,将会变为我的原创作品!
  • 相关阅读:
    SpringBoot配置文件
    SpringBoot基础开发流程
    day06-01数字类型、数字类型的转换
    特有的循环结构(for-else、while-else)——Python篇
    分支、循环——Python基础篇
    循环关键字——Python篇
    另类三目运算符——Python篇
    原码、反码以及补码
    Python运算符
    Python变量
  • 原文地址:https://www.cnblogs.com/LyShark/p/14128449.html
Copyright © 2011-2022 走看看