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
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.