Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QPushButton delegate en QTableView



  • Hola,

    Tengo una aplicación de escritorio que simula un CRUD y uso un buttondelegate
    para actualizar y borrar. La questión es que para cada delegate me despliega un
    botón de más.

    1.- clase ButtonColumnDelegate
    @
    ButtonColumnDelegate::ButtonColumnDelegate(QObject *parent) :
    QStyledItemDelegate(parent)
    {
    if(QTableView *tableView = qobject_cast<QTableView *>(parent))
    {
    myWidget = tableView;
    btn = new QPushButton("...", myWidget);
    btn->show();
    myWidget->setMouseTracking(true);
    connect(myWidget, SIGNAL(entered(QModelIndex)),
    this, SLOT(cellEntered(QModelIndex)));
    isOneCellInEditMode = false;
    }
    }

    ButtonColumnDelegate::~ButtonColumnDelegate()
    {

    }

    //createEditor
    QWidget * ButtonColumnDelegate::createEditor(QWidget *parent,
    const QStyleOptionViewItem &option,
    const QModelIndex &index) const
    {
    QString header = index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toString();
    if ((header == "Update") || (header == "Insert"))
    {
    QPushButton * btn = new QPushButton(parent);
    btn->setText(index.data().toString());
    return btn;
    } else {
    return QStyledItemDelegate::createEditor(parent, option, index);
    }
    }

    //setEditorData
    void ButtonColumnDelegate::setEditorData(QWidget *editor,
    const QModelIndex &index) const
    {
    QString header = index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toString();
    if ((header == "Update") || (header == "Insert"))
    {
    QPushButton * btn = qobject_cast<QPushButton *>(editor);
    btn->setProperty("data_value", index.data());
    } else {
    QStyledItemDelegate::setEditorData(editor, index);
    }
    }

    //setModelData
    void ButtonColumnDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
    const QModelIndex &index) const
    {
    QString header = index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toString();
    if ((header == "Update") || (header == "Insert"))
    {
    QPushButton *btn = qobject_cast<QPushButton *>(editor);
    model->setData(index, btn->property("data_value"));
    } else {
    QStyledItemDelegate::setModelData(editor, model, index);
    }
    }

    //paint
    void ButtonColumnDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    QString header = index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toString();
    if((header == "Update") || (header == "Insert"))
    {
    btn->setGeometry(option.rect);
    btn->setText(index.data().toString());
    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);
    }
    }

    //updateGeometry
    void ButtonColumnDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const
    {
    editor->setGeometry(option.rect);
    }

    //cellEntered
    void ButtonColumnDelegate::cellEntered(const QModelIndex &index)
    {
    QString header = index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toString();
    if((header == "Update") || (header == "Insert"))
    {
    if(isOneCellInEditMode)
    {
    myWidget->closePersistentEditor(currentEditedCellIndex);
    }
    myWidget->openPersistentEditor(index);
    isOneCellInEditMode = true;
    currentEditedCellIndex = index;
    } else {
    if(isOneCellInEditMode)
    {
    isOneCellInEditMode = false;
    myWidget->closePersistentEditor(currentEditedCellIndex);
    }
    }
    }
    @

    Está tomado de internet "adding-button-to-qviewtable":http://qtadventures.wordpress.com/2012/02/04/adding-button-to-qviewtable/.

    2.- clase Browser (la ventana de la aplicación)
    @
    void Browser::exec()
    {
    QSqlQueryModel *myModel = new QSqlQueryModel(table);
    myModel->setQuery(QSqlQuery(sqlEdit->toPlainText(), connectionWidget->currentDatabase()));

    if (myModel->query().isSelect()) {
        // Create the data model
        model = new QStandardItemModel();
        table->setModel(model);
        ButtonColumnDelegate *update = new ButtonColumnDelegate(table);
        ButtonColumnDelegate *insert = new ButtonColumnDelegate(table);
        table->setItemDelegateForColumn(2, update);
        table->setItemDelegateForColumn(3, insert);
    
    
        model->insertRows(0, myModel->query().size());
        model->insertColumns(0, 4);
    
        // Set the localized header captions
        model->setHeaderData(0, Qt::Horizontal, "Id", Qt::UserRole);
        model->setHeaderData(1, Qt::Horizontal, "Word", Qt::UserRole);
        model->setHeaderData(2, Qt::Horizontal, "Update", Qt::UserRole);
        model->setHeaderData(3, Qt::Horizontal, "Insert", Qt::UserRole);
    
        // ...
    

    }
    @

    Y duplica el botón de la ultima fila.

    Gracias de antemano,
    oggie



  • Creo que posiblemente la causa esté en la lógica de la función,
    @
    //cellEntered
    void ButtonColumnDelegate::cellEntered(const QModelIndex &index)
    {
    QString header = index.model()->headerData(index.column(), Qt::Horizontal, Qt::UserRole).toString();
    if((header == "Update") || (header == "Insert"))
    {
    if(isOneCellInEditMode)
    {
    myWidget->closePersistentEditor(currentEditedCellIndex);
    }
    myWidget->openPersistentEditor(index);
    isOneCellInEditMode = true;
    currentEditedCellIndex = index;
    } else {
    if(isOneCellInEditMode)
    {
    isOneCellInEditMode = false;
    myWidget->closePersistentEditor(currentEditedCellIndex);
    }
    }
    }
    @

    No estoy seguro dado que soy nuevo en esto pero posiblemente la variable booleana isOneCellInEditMode no esté bien controlada y habilite la opción de editar un botón de más.

    Cualquier sugerencia será gratamente apreciada.

    oggie



  • Al final preferí usar esta otra clase con las correciones que aparecen en el código y ya funciona.

    customitemdelegate.h.-
    @
    #ifndef CUSTOMITEMDELEGATE_H
    #define CUSTOMITEMDELEGATE_H

    #include <QItemDelegate>

    class CustomItemDelegate : public QItemDelegate
    {
    Q_OBJECT

    public:
    explicit CustomItemDelegate(QObject *parent = 0);

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

    signals:
    void updButtonClicked(const QModelIndex &index);
    void delButtonClicked(const QModelIndex &index);

    public slots:

    private:
    QStyle::State _state;
    QRect oldRect;
    };

    #endif // CUSTOMITEMDELEGATE_H
    @

    customitemdelegate.cpp.-
    @
    #include "customitemdelegate.h"
    #include <QModelIndex>
    #include <QStandardItemModel>
    #include <QStandardItem>
    #include <QPainter>
    #include <QStyleOptionButton>
    #include <QApplication>
    #include <QEvent>
    #include <QDebug>
    #include <QMouseEvent>

    CustomItemDelegate::CustomItemDelegate(QObject *parent) :
    QItemDelegate(parent)
    {
    _state = QStyle::State_Enabled;
    }

    void CustomItemDelegate::paint(QPainter painter,
    const QStyleOptionViewItem &option,
    const QModelIndex &index) const
    {
    //const QStandardItemModel
    model = static_cast<const QStandardItemModel*>(index.model());
    //QStandardItem* item = model->item(index.row());
    //QString text = item->text();

    QString text = index.data().toString();

    QRect rect = option.rect;

    //QRect textRect(rect);
    //textRect.setHeight(30);
    //painter->drawText(textRect,text);
    painter->drawText(rect,text);

    QRect buttonRect(rect);
    //buttonRect.setY(textRect.y() + 35);
    //buttonRect.setY(rect.y() + 35);
    buttonRect.setHeight(30);
    QStyleOptionButton button;
    button.rect = buttonRect;
    button.text = text;
    button.state = _state | QStyle::State_Enabled;

    QApplication::style()->drawControl(QStyle::CE_PushButton, &button, painter);
    }

    QSize CustomItemDelegate::sizeHint(const QStyleOptionViewItem &/option/,
    const QModelIndex &/index/) const
    {
    return QSize(800,70);
    }

    bool CustomItemDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
    {
    qDebug() << "editorEvent on row: " << index.row();
    qDebug() << "editorEvent:: " << event->type();

    if( event->type() == QEvent::MouseButtonPress ||
        event->type() == QEvent::MouseButtonRelease ) {
    } else {
         _state = QStyle::State_Raised;
        return true;
    }
    
    QRect buttonRect(option.rect);
    //buttonRect.setY(option.rect.y() + 35);
    buttonRect.setHeight(30);
    
    QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
    if( !buttonRect.contains( mouseEvent->pos()) ) {
        _state = QStyle::State_Raised;
        return true;
    }
    
    if( event->type() == QEvent::MouseButtonPress) {
        _state = QStyle::State_Sunken;
    } else if(event->type() == QEvent::MouseButtonRelease) {
        _state = QStyle::State_Raised;
        if(index.data().toString().contains("Update"))
            emit updButtonClicked(index);
        else if(index.data().toString().contains("Delete"))
            emit delButtonClicked(index);
        else
            qDebug() << "¡¡¡ --ERROR-- !!!" << index.row();
    }
    return true;
    

    }
    @

    No duplicaba el ultimo botón sino que los había desplazado en la columna hacia abajo.

    Gracias,
    oggie


Log in to reply