【问题标题】:Create PushButtons in QTableView with QStyledItemDelegate subclass使用 QStyledItemDelegate 子类在 QTableView 中创建 PushButtons
【发布时间】:2017-03-29 00:53:44
【问题描述】:

我有完全相同的problem,但我将使用 QTableView 小部件。我阅读了this 并想知道是否可以重写 createEditor 函数以使用例如 QFileDialog 来获取新数据。

如果可能的话,谁能给我一个例子来实现这样一个 QItemDelegate 的子类。

如果没有,任何人都可以提供一个示例来实现 QItemDelegate 的子类,女巫可以在 QLineEdit 旁边绘制一个按钮以获取功能here

编辑:也许这个问题真的很愚蠢,我没有意识到,因为我离开这个项目大约半年。

第二:从 Qt 5.7 更新到 5.8 是否安全?

【问题讨论】:

    标签: qt qtableview qitemdelegate


    【解决方案1】:

    我已经尽力了,这是我的解决方案。 QStyledItemDelegate 子类的代码大部分来自here

    解决方案图片

    但是,我很想解决一件事:(也许有人可以帮助我并发表评论)

    • QPixmap::grabWidget is deprecated, use QWidget::grab() instead 但看起来 QWidget::grab() 不是用于此目的的正确解决方案。

    foo.h:

    #ifndef LIBRARYITEMDELEGATE_H
    #define LIBRARYITEMDELEGATE_H
    
    #include <QStyledItemDelegate>
    #include <QWidget>
    #include <QPushButton>
    #include <QTableView>
    
    class LibraryItemDelegate : public QStyledItemDelegate
    {
        Q_OBJECT
    
    public:
        explicit LibraryItemDelegate(QObject *parent = 0);
        ~LibraryItemDelegate();
    
        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
    //    QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
        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 *modal, const QModelIndex &index) const Q_DECL_OVERRIDE;
        void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
    
    public slots:
        void cellEntered(const QModelIndex &index);
    
    private:
        QTableView *myView;
        QPushButton *btn;
        bool isOneCellInEditMode;
        QPersistentModelIndex currentEditedCellIndex;
    };
    
    #endif // LIBRARYITEMDELEGATE_H
    

    foo.cpp:

    #include "libraryitemdelegate.h"
    
    #include <QPainter>
    #include <QStylePainter>
    
    LibraryItemDelegate::LibraryItemDelegate(QObject *parent) : QStyledItemDelegate(parent)
    {
        if(QTableView *tableView = qobject_cast<QTableView*>(parent))
        {
            myView = tableView;
            btn = new QPushButton("...", myView);
            btn->hide();
            myView->setMouseTracking(true);
            connect(myView, SIGNAL(entered(QModelIndex)), this, SLOT(cellEntered(QModelIndex)));
            isOneCellInEditMode = false;
        }
    }
    
    LibraryItemDelegate::~LibraryItemDelegate(){}
    
    void LibraryItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        if(index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toInt() == 1)
        {
            btn->setGeometry(option.rect);
            btn->setText("...");
            if(option.state == QStyle::State_Selected)
            {
                painter->fillRect(option.rect, option.palette.highlight());
            }
            QPixmap map = QPixmap::grabWidget(btn);
            painter->drawPixmap(option.rect.x(), option.rect.y(), map);
        }
        else
        {
            QStyledItemDelegate::paint(painter, option, index);
        }
    }
    
    //QSize LibraryItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    //{
    //    // return the QSize of the item in Your view
    //}
    
    QWidget *LibraryItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        if(index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toInt() == 1)
        {
            QPushButton *btn = new QPushButton(parent);
    //        btn->setText(index.data().toString());
            btn->setText("...");
            return btn;
        }
        else
        {
            return QStyledItemDelegate::createEditor(parent, option, index);
        }
    }
    
    void LibraryItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        if(index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toInt() == 1)
        {
            QPushButton *btn = qobject_cast<QPushButton*>(editor);
    //        btn->setProperty("data_value", index.data());
            btn->setProperty("data_value", "...");
            btn->setText("...");
        }
        else
        {
            QStyledItemDelegate::setEditorData(editor, index);
        }
    }
    
    void LibraryItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
        if(index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toInt() == 1)
        {
            QPushButton *btn = qobject_cast<QPushButton*>(editor);
            model->setData(index, btn->property("data_value"));
        }
        else
        {
            QStyledItemDelegate::setModelData(editor, model, index);
        }
    }
    
    void LibraryItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        editor->setGeometry(option.rect);
    }
    
    void LibraryItemDelegate::cellEntered(const QModelIndex &index)
    {
        if(index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toInt() == 1)
        {
            if(isOneCellInEditMode)
            {
                myView->closePersistentEditor(currentEditedCellIndex);
            }
            myView->openPersistentEditor(index);
            isOneCellInEditMode = true;
            currentEditedCellIndex = index;
        }
        else
        {
            if(isOneCellInEditMode)
            {
                isOneCellInEditMode = false;
                myView->closePersistentEditor(currentEditedCellIndex);
            }
        }
    }
    

    实施:

    QStandardItemModel *myModel; // This is in the Header file
    
    myModel = new QStandardItemModel(0,2,this);
    myModel->setHeaderData(1, Qt::Horizontal, 1, Qt::UserRole);
    myModel->setHorizontalHeaderLabels(QStringList(tr("Pfad zu den bibliotheks Ordnern")));
    
    // Set Model and delegate to the View
    ui->tableView_pathes->setModel(myModel);
    LibraryItemDelegate *delegate = new LibraryItemDelegate(ui->tableView_pathes);
    ui->tableView_pathes->setItemDelegate(delegate);
    
    // Stretch only the first column
    ui->tableView_pathes->horizontalHeader()->setSectionResizeMode(0,QHeaderView::Stretch);
    ui->tableView_pathes->horizontalHeader()->setSectionResizeMode(1,QHeaderView::Fixed);
    

    编辑:这是 tableView 中按钮的代码。将 createEditor 中的信号与 connect(btn, SIGNAL(pressed()), this, SLOT(buttonPressed())); 连接,并设置为委托提供对 QStandardItemModel 的引用。

    void LibraryItemDelegate::buttonPressed()
    {
        QString dir = QFileDialog::getExistingDirectory(new QWidget(), tr("Wähle die bibliotheks Ordner"), "/home", QFileDialog::ShowDirsOnly);
    
        qDebug() << "Test: " << dir;
    
        if(!dir.isEmpty())
        {
            QModelIndex ind = currentEditedCellIndex.model()->index(currentEditedCellIndex.row(), 0);
            myModel->setData(ind, dir, Qt::DisplayRole);
        }
    }
    

    【讨论】:

    • 我曾这样使用 Widget::grab():painter->drawPixmap(r.left(),r.right(), r.width(), r.height(), widget ->抓取());但那是很久以前的事了,我不记得它是如何工作的。
    • 我想你现在只是做 widget->render() ?它返回那个小部件的像素图......我可能错了。
    【解决方案2】:
    1. 使用 QStyledItemDelegate,而不是 QItemDelegate。
    2. 阅读 Qt 手册

    QStyledItemDelegate class

    Spinboxdelegate Example

    1. 子类 QStyledItemDelegate 的代码示例(精简):

    头文件

    #ifndef MYITEMDELEGATE_H
    #define MYITEMDELEGATE_H
    
    #include <QStyledItemDelegate>
    
    class KontaktForm;
    
    class MyItemDelegate : public QStyledItemDelegate
    {
        Q_OBJECT
    
        mutable SubscriberForm *subscriberForm;
    
    public:
        explicit MyItemDelegate(QObject *parent = 0);
        ~MyItemDelegate();
    
    
    ////////!Methods - You don't need all of them
        void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
        QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
        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;
        void editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index);
    
    };
    
    #endif // MYITEMDELEGATE_H
    

    源文件

    #include "myitemdelegate.h"
    
    #include "mytreeview.h"
    #include <QModelIndex>
    #include <QSize>
    
    MyItemDelegate::MyItemDelegate(QObject *parent) : QStyledItemDelegate(parent),
        subscriberForm(Q_NULLPTR),
    {
    }
    
    QSize MyItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        //// return the QSize of the item in Your view
    }
    
    void MyItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        ////optional : implement custom painting - text, images, drawings, and such
    }
    
    
    QWidget *MyItemDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        subscriberForm = new SubscriberForm(parent);
        ////optional additional settings for Your editor
        return subscriberForm;      
    }
    
    void MyItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
        editor->setGeometry(option.rect);
    }
    
    void MyItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
    {
        ////setup the editor - your data are in index.data(Qt::DataRoles) - stored in a QVariant;
        QString value = index.model()->data(index,Qt::EditRole).toString();
        SubscriberForm *subscriberForm =  static_cast<SubscriberForm*>(editor);
    }
    
    void MyItemDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const
    {
        ////optional - if needed - return changed data, from editor to the model in a custom matter
    
        SubscriberForm *subscriberForm =  static_cast<SubscriberForm*>(editor);
        model->setData(index,QVariant(subscriberForm->getData()),Qt::EditRole);
    
    }
    

    【讨论】:

    • 这真的有效吗?例如,编辑完成后控件消失。
    • @Mikhail 此代码来自我的应用程序,因此它应该可以工作。但是我有可能忘记粘贴一些东西,所以如果你尝试过,但没有成功,请告诉我。
    • 是的,所以当它的单元格未激活时,按钮会消失。或者具体来说,paint() 被调用,它什么都不做。如何在未激活时保持按钮存在并非易事,您可以看到另一个答案使用了已弃用的屏幕抓取方法。
    • 正如我在回答中所写,这不是全部代码。我没有在这里写我的paint() 方法,因为它很大。至于要激活的编辑器,我从我的自定义 treeView 类(继承自 QTreeView)中调用 openPersistantEditor()。你是对的,我忘了在这里提到这一点。明天我会尽量记住添加代码。
    • 很遗憾,我现在没有太多时间,问题不是让编辑器处于打开状态。这就是为什么我不会改变我的答案。如果您需要更多信息,请在 Stack Overflow 上提出单独的问题,并通过私信告诉我。在接下来的一周我会有更多的时间,所以我可以回答(如果我知道的话)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-13
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 2014-10-13
    相关资源
    最近更新 更多