Using various custom delegates in QTableView

QT’s MVC (View/Delegate) model is very powerful and can use various controls to limit table input.

Idea:
1: Define delegates for each column:
A: The first column is the number column. Use a read-only delegate to make the cells in this column read-only.
B: The third column is the ID column. Only 1-12 numbers can be entered. QLineEdit delegates and regular expressions are used to limit the input.
C: The fourth age column, use QSpinBox delegation to limit the input. Only numbers between 1 and 100 can be entered.
D: The fifth column is the gender column. Use the QComboBox delegate to limit the input. The cells in this column can only enter Male or Female.
E: The sixth column is the avatar column. Place an avatar in the center of the cell in this column.
2: Define a proxy class to center the characters in all cells.
3: Use QSS to change the background color of the table to yellow and blue.

Above code:

#include <QtGui>
#include <QItemDelegate>
#include <QSpinBox>
//Number column, read-only delegate
//I really can’t think of this method, haha
class ReadOnlyDelegate : public QItemDelegate
{
Q_OBJECT
public:
ReadOnlyDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget*parent, const QStyleOptionViewItem & amp;option,
const QModelIndex & amp;index) const
{
return NULL;
}
};
//ID column, only 1-12 numbers can be entered
//Use QLineEdit delegates and regular expressions to limit input
class UserIDDelegate : public QItemDelegate
{
Q_OBJECT
public:
UserIDDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem & amp;option,
const QModelIndex & amp;index) const
{
QLineEdit *editor = new QLineEdit(parent);
QRegExp regExp("[0-9]{0,10}");
editor->setValidator(new QRegExpValidator(regExp, parent));
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex & amp;index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
lineEdit->setText(text);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex & amp;index) const
{
QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);
QString text = lineEdit->text();
model->setData(index, text, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
editor->setGeometry(option.rect);
}
};
//In the age column, use the QSpinBox delegate to limit the input. Only numbers between 1 and 100 can be entered.
class AgeDelegate : public QItemDelegate
{
Q_OBJECT
public:
AgeDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem & amp;option,
const QModelIndex & amp;index) const
{
QSpinBox *editor = new QSpinBox(parent);
editor->setMinimum(1);
editor->setMaximum(100);
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex & amp;index) const
{
int value = index.model()->data(index, Qt::EditRole).toInt();
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->setValue(value);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex & amp;index) const
{
QSpinBox *spinBox = static_cast<QSpinBox*>(editor);
spinBox->interpretText();
int value = spinBox->value();
model->setData(index, value, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
editor->setGeometry(option.rect);
}
};
//Gender column, use QComboBox delegate to limit input
//The cells in this column can only enter Male or Female
class SexDelegate : public QItemDelegate
{
Q_OBJECT
public:
SexDelegate(QObject *parent = 0): QItemDelegate(parent) { }
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem & amp;option,
const QModelIndex & amp;index) const
{
QComboBox *editor = new QComboBox(parent);
editor->addItem("Female");
editor->addItem("Male");
return editor;
}
void setEditorData(QWidget *editor, const QModelIndex & amp;index) const
{
QString text = index.model()->data(index, Qt::EditRole).toString();
QComboBox *comboBox = static_cast<QComboBox*>(editor);
int tindex = comboBox->findText(text);
comboBox->setCurrentIndex(tindex);
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex & amp;index) const
{
QComboBox *comboBox = static_cast<QComboBox*>(editor);
QString text = comboBox->currentText();
model->setData(index, text, Qt::EditRole);
}
void updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
editor->setGeometry(option.rect);
}
};
//The avatar column is just a small picture placed in the center of the cell.
class IconDelegate : public QItemDelegate
{
Q_OBJECT
public:
IconDelegate(QObject *parent = 0): QItemDelegate(parent) { }
void paint(QPainter *painter, const QStyleOptionViewItem & amp;option,
const QModelIndex & amp; index ) const
{
//show.bmp is a picture in the project directory (actually it is the QQ icon, haha)
QPixmap pixmap = QPixmap("show.bmp").scaled(24, 24);
qApp->style()->drawItemPixmap(painter, option.rect, Qt::AlignCenter, QPixmap(pixmap));
}
};
//Agent class, display the characters in all cells in the center
class VIPModel : public QStandardItemModel
{
Q_OBJECT
public:
VIPModel(QObject *parent=NULL) : QStandardItemModel(parent) { }
VIPModel(int row, int column, QObject *parent=NULL)
: QStandardItemModel(row, column, parent) { }
QVariant data(const QModelIndex & amp;index, int role = Qt::DisplayRole) const
{
if( Qt::TextAlignmentRole == role )
return Qt::AlignCenter;
return QStandardItemModel::data(index, role);
}
};
#include "main.moc"
int main(int argc, char *argv[])
{
QApplication app(argc, argv);
VIPModel *model = new VIPModel(5, 5);
QTableView *tableView = new QTableView;
//Adjust the background of the table to yellow and blue
//I saw this method on the Internet, and it’s really convenient to use.
tableView->setAlternatingRowColors(true);
tableView->setStyleSheet("QTableView{background-color: rgb(250, 250, 115);"
"alternate-background-color: rgb(141, 163, 215);}");
tableView->setWindowTitle("VIP List");
tableView->resize(700, 400);
tableView->setModel(model);
QStringList headerList;
headerList << "No." << "ID" << "Name" << "Age" << "Sex" << "Show";
model->setHorizontalHeaderLabels(headerList);
tableView->verticalHeader()->setVisible(false);
tableView->horizontalHeader()->setStretchLastSection(true);
//Load delegates for each column
ReadOnlyDelegate readOnlyDelegate;
//tableView->setItemDelegateForColumn(0, & amp;readOnlyDelegate); //I will get an error if I use it
tableView->setItemDelegateForColumn(0, new ReadonlyDelegate(this)); //I use this
UserIDDelegate userIDDelegate;
tableView->setItemDelegateForColumn(1, & userIDDelegate);
AgeDelegate spinBoxDelegate;
tableView->setItemDelegateForColumn(3, & amp;spinBoxDelegate);
SexDelegate comboBoxDelegate;
tableView->setItemDelegateForColumn(4, & amp;comboBoxDelegate);
IconDelegate iconDelegate;
tableView->setItemDelegateForColumn(5, & amp;iconDelegate);
for(int i=0; i<10; i + + )
{
QModelIndex index = model->index(i, 0, QModelIndex());
model->setData(index, i);
}
tableView->show();
return app.exec();
}

QTableView, QStandardItemModel/QAbstractItemModel, QStyledItemDelegate/QItemDelegate and QModelIndex;

Let’s take a look at the picture first to see the effect.

The next line is the full path of the selected file displayed.

Line 2 “C:” is the value set during initialization, just for test display.

The last line is no file selected.

This SelectFileButton method I implemented:

QPushButton;

Implement a slot function in SelectFileButton: function, select the file and return the path when clicked.

cQItemDelegate;

d. Then rewrite createEditor(); return the pointer of SelectFileButton

e. Rewrite setModelData(), setEditorData(); set model data and set editing data.

Benefits of this article,You can receive Qt development learning materials package and technical videos for free, including (C++ language basics, introduction to Qt programming, QT signals and slots mechanism, QT interface development -Image drawing, QT network, QT database programming, QT project practice, QT embedded development, Quick module, etc.) ↓↓↓↓↓↓See below↓↓Click at the bottom of the articleto receive the fee↓↓

#ifndef SELECTFILEBUTTONDELEGATE_H
#define SELECTFILEBUTTONDELEGATE_H
#include <QItemDelegate>
#include <QPushButton>
#include <QModelIndex>
#include <QFileDialog>
#include <QAbstractItemModel>
#include <QDebug>
class TableModel;
class SelectFileButton: public QPushButton
{
Q_OBJECT
public:
SelectFileButton(const QModelIndex & amp; index, QWidget *parent = 0)
: QPushButton(parent)
{
Init(index);
}
SelectFileButton(const QModelIndex & amp; index, const QString & amp;text, QWidget *parent = 0)
: QPushButton(text, parent)
{
Init(index);
}
SelectFileButton(const QModelIndex & amp; index, const QIcon & amp; icon, const QString & amp;text, QWidget *parent = 0)
:QPushButton(icon, text, parent)
{
Init(index);
}
~SelectFileButton() {
qDebug() << "~SelectFileButton";
}
protected:
void Init(const QModelIndex & amp; index)
{
m_index = index;
connect(this, SIGNAL(clicked()), this, SLOT(btnClick_slot()));
}
public slots:
void btnClick_slot()
{
QString strValue;
QModelIndex index = this->m_index;
QFileDialog * dlg = new QFileDialog(0);
int res =dlg->exec(); //Start a new thread here, and the top layer will release this button, so you need to save a copy of the Index
if (res==QFileDialog::Accepted)
{
strValue = dlg->selectedFiles()[0];
QAbstractItemModel* model = const_cast<QAbstractItemModel*>(index.model());
model->setData(index, strValue);
}
}
private:
QModelIndex m_index;
};
/****************************************************** *********************/
class SelectFileButtonDelegate : public QItemDelegate
{
Q_OBJECT
public:
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem & amp;option,
const QModelIndex & amp;index) const
{
SelectFileButton* btn = new SelectFileButton(index,QStringLiteral("Find file path"), parent); //This is in other threads so it cannot be saved. Btn is different every time
return btn;
}
void setModelData(QWidget *editor, QAbstractItemModel *model,
const QModelIndex & amp;index) const;
void setEditorData(QWidget *editor, const QModelIndex & amp;index) const;
public:
SelectFileButtonDelegate(QObject *parent);
~SelectFileButtonDelegate();
private:
QPushButton* m_btn;
};
#endif // SELECTFILEBUTTONDELEGATE_H

Draw custom controls through painter

QStyleOption subclass:

QStyleOptionButton, QStyleOptionComplex, QStyleOptionDockWidget, QStyleOptionFocusRect, QStyleOptionFrame, QStyleOptionGraphicsItem, QStyleOptionHeader, QStyleOptionMenuItem, QStyleOptionProgressBar, QStyleOptionRubberBand, QStyleOptionTab, QStyleOptionTabBarBase, QStyleOptionTabWidgetFrame, QStyleOptionToolBar, QStyleOption ToolBox, and QStyleOptionViewItem

1. Painter custom progress bar

//Customize progress bar
BarDelegate::BarDelegate( QObject *parent ) : QAbstractItemDelegate( parent ) { }

void BarDelegate::paint( QPainter *painter, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index ) const
{
  if( option.state & amp; QStyle::State_Selected )
    painter->fillRect( option.rect, option.palette.highlight() );

  //The data is a QStandardItem stored in QStandardItemModel, which will automatically match based on the current row (I think)
  int value = index.model()->data( index, Qt::DisplayRole ).toInt(); // This sentence gets the data of the current row
  qDebug() << value;
  double factor = double(value)/100.0; // Calculate the scale factor

  painter->save(); // Save the old artboard (I think)
  //Progress bar background color
  if(factor > 0.8)
  {
    painter->setBrush( Qt::red ); // Paint pure red beyond 0.8
    factor = 1;
  }
  else
    painter->setBrush( QColor( 0, int(factor*255), 255-int(factor*255) ) ); // Otherwise, the colors will become lighter in sequence

  int n = factor*100;
  QString str1 = QString("%1\%").arg(n);
  painter->setPen( Qt::red ); // Brush color (not used here, I think)
  // The previous steps are all preparation work, here is where the progress bar is actually drawn.
  painter->drawRect( option.rect.x() + 2, option.rect.y() + 2, int(factor*(option.rect.width()-5)), option.rect.height()- 5);
  painter->drawText(option.rect.x() + int(factor*(option.rect.width())) + 2, option.rect.y() + option.rect.height()/2, str1) ;
  painter->restore(); // Restore the new artboard (I think)
}

QSize BarDelegate::sizeHint( const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index ) const
{
  return QSize( 45, 15 ); // Change it as you like, it will not affect (I think)
}
class BarDelegate : public QAbstractItemDelegate
{
public:
  BarDelegate( QObject *parent = 0 );
  // Override two functions to display the progress bar
  void paint( QPainter *painter, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index ) const;
  QSize sizeHint( const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index ) const;
};

1 painter progress bar QStyleOptionProgressBar

void ProgressBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
    if(index.column() == 0) {
        int value = index.model()->data(index).toInt();
        QStyleOptionProgressBarV2 progressBarOption;
        progressBarOption.rect = option.rect.adjusted(4, 4, -4, -4);
        progressBarOption.minimum = 0;
        progressBarOption.maximum = 100;
        progressBarOption.textAlignment = Qt::AlignRight;
        progressBarOption.textVisible = true;
        progressBarOption.progress = value;
        progressBarOption.text = tr("%1%").arg(progressBarOption.progress);

        painter->save();
        if (option.state & amp; QStyle::State_Selected) {
            painter->fillRect(option.rect, option.palette.highlight());
                    painter->setBrush(option.palette.highlightedText());
        }
                QApplication::style()->drawControl(QStyle::CE_ProgressBar, & amp;progressBarOption, painter);

        painter->restore();

    } else {
        return QItemDelegate::paint (painter, option, index);
    }
}

2. Painter custom button QStyTableViewDelegate::TableViewDelegate(int z_Column, int z_NumberButtons,QWidget *parent)

 : QStyledItemDelegate(parent),
      m_pOpenButton(new QPushButton()),
      m_pDeleteButton(new QPushButton()),
      m_nSpacing(5),
      m_nWidth(25),
      m_nHeight(20),
      m_Column(z_Column),
      m_NumberButtons(z_NumberButtons)
{if (2 == m_NumberButtons)
    {
        m_list << QStringLiteral("Edit button") << QStringLiteral("Delete button");
    }
    //Set button normal, swipe, and press styles
    QString z_Path = QCoreApplication::applicationDirPath();
    m_pOpenButton->setStyleSheet("QPushButton {border: none; background-color: transparent; image:url(" + z_Path + "/res/system.png);} \
                                 QPushButton:hover {image:url(" + z_Path + "/res/system.png);} \
                                 QPushButton:pressed {image:url(" + z_Path + "/res/system.png);}");

     m_pDeleteButton->setStyleSheet("QPushButton {border: none; background-color: transparent; image:url(" + z_Path + "/res/delete.png);} \
                                QPushButton:hover {image:url(" + z_Path + "/res/delete.png);} \
                                QPushButton:pressed {image:url(" + z_Path + "/res/delete.png);}");
}

TableViewDelegate::~TableViewDelegate()
{

}

// draw button
void TableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
    QStyleOptionViewItem viewOption(option);
    initStyleOption( & amp;viewOption, index);
    if (option.state.testFlag(QStyle::State_HasFocus))
        viewOption.state = viewOption.state ^ QStyle::State_HasFocus;

    QStyledItemDelegate::paint(painter, viewOption, index);

    if (index.column() == m_Column)
    {
        // Calculate button display area
        int nCount = m_list.count();
        int nHalf = (option.rect.width() - m_nWidth * nCount - m_nSpacing * (nCount - 1)) / 2;
        int nTop = (option.rect.height() - m_nHeight) / 2;

        for (int i = 0; i < nCount; + + i)
        {
            // draw button
            QStyleOptionButton button;
            button.rect = QRect(option.rect.left() + nHalf + m_nWidth * i + m_nSpacing * i,
                                option.rect.top() + nTop, m_nWidth, m_nHeight);
            button.state |= QStyle::State_Enabled;
            button.iconSize = QSize(20, 20);

            if (button.rect.contains(m_mousePoint))
            {
                if (m_nType == 0)
                {
                    button.state |= QStyle::State_MouseOver;
                    //button.icon = QIcon(QString(":/Images/%1Hover").arg(m_list.at(i)));
                }
                else if (m_nType == 1)
                {
                    button.state |= QStyle::State_Sunken;
                    //button.icon = QIcon(QString(":/Images/%1Pressed").arg(m_list.at(i)));
                }
            }

            //QWidget *pWidget = m_pOpenButton.data();
            QWidget *pWidget = (i == 0) ? m_pOpenButton.data() : m_pDeleteButton.data();
            pWidget->style()->drawControl(QStyle::CE_PushButton, & amp;button, painter, pWidget);
        }
    }
}

//Respond to button events - swipe, press
bool TableViewDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem & amp; option, const QModelIndex & amp; index)
{
    if (index.column() != m_Column)
        return false;

    m_nType = -1;
    bool bRepaint = false;
    QMouseEvent *pEvent = static_cast<QMouseEvent *> (event);
    m_mousePoint = pEvent->pos();

    int nCount = m_list.count();
    int nHalf = (option.rect.width() - m_nWidth * nCount - m_nSpacing * (nCount - 1)) / 2;
    int nTop = (option.rect.height() - m_nHeight) / 2;

    //Restore mouse style
    QApplication::restoreOverrideCursor();

    for (int i = 0; i < nCount; + + i)
    {
        QStyleOptionButton button;
        button.rect = QRect(option.rect.left() + nHalf + m_nWidth * i + m_nSpacing * i,
                            option.rect.top() + nTop, m_nWidth, m_nHeight);

        //The mouse is over the button
        if (!button.rect.contains(m_mousePoint))
            continue;

        bRepaint = true;
        switch (event->type())
        {
        //mouse over
        case QEvent::MouseMove:
        {
            //Set the mouse style to hand type
            //QApplication::setOverrideCursor(Qt::PointingHandCursor);

            m_nType = 0;
            QToolTip::showText(pEvent->globalPos(), m_list.at(i));
            break;
        }
            //Mouse pressed
        case QEvent::MouseButtonPress:
        {
            m_nType = 1;
            break;
        }
            //mouse release
        case QEvent::MouseButtonRelease:
        {
            if(i==0)
            {
                emit EditData(index);
            }
            else
            {
                emit deleteData(index);
            }
            break;
        }
        default:
            break;
        }
    }

    return bRepaint;
}

Three painter set pictures

void ItemdelegateTest::paint(QPainter *painter, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
    QStyleOptionViewItem viewOption(option);
    if (viewOption.state & amp; QStyle::State_HasFocus)
    {
        viewOption.state = viewOption.state ^ QStyle::State_HasFocus;
    }

    QStyledItemDelegate::paint(painter, viewOption, index);

    int height = (viewOption.rect.height()) / 2;
    QPixmap pixmap = QPixmap(":/check.png");
    //QPixmap pixmap = QPixmap("E:/qt/QtDelegateTestT/zhj.png");
    QRect DrawRect = QRect(viewOption.rect.left() + viewOption.rect.width() - 30, viewOption.rect.top() + height, 9, 9);
    painter->drawPixmap(DrawRect, pixmap);
}

bool ItemdelegateTest::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index)
{
    int height = (option.rect.height()) / 2;
    QRect DrawRect = QRect(option.rect.left() + option.rect.width() - 30, option.rect.top() + height, 9, 9);

    //QMouseEvent *mouseEvent = static_cast(event);
    QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    if (event->type() == QEvent::MouseButtonPress & amp; & amp; DrawRect.contains(mouseEvent->pos()))
    {
       emit deleteItem(index);
    }

    if (event->type() == QEvent::MouseMove & amp; & amp; DrawRect.contains(mouseEvent->pos()))
    {
        QCursor cursor(Qt::PointingHandCursor);
        QApplication::setOverrideCursor(cursor);
        QToolTip::showText(mouseEvent->globalPos(), "delete");
    }
    else
    {
        QCursor cursor(Qt::ArrowCursor);
        QApplication::setOverrideCursor(cursor);
    }

    return QStyledItemDelegate::editorEvent(event, model, option, index);
}

panier draws checkbox

CheckBoxDelegate::CheckBoxDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{

}

CheckBoxDelegate::~CheckBoxDelegate()
{

}

// draw checkbox
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index) const
{
    QStyleOptionViewItem viewOption(option);
    initStyleOption( & amp;viewOption, index);
    if (option.state.testFlag(QStyle::State_HasFocus))
        viewOption.state = viewOption.state ^ QStyle::State_HasFocus;

    QStyledItemDelegate::paint(painter, viewOption, index);

    if (index.column() == CHECK_BOX_COLUMN)
    {
        bool data = index.model()->data(index, Qt::UserRole).toBool();

        QStyleOptionButton checkBoxStyle;
        checkBoxStyle.state = data ? QStyle::State_On : QStyle::State_Off;
        checkBoxStyle.state |= QStyle::State_Enabled;
        checkBoxStyle.iconSize = QSize(20, 20);
        checkBoxStyle.rect = option.rect;

        QCheckBox checkBox;
        QApplication::style()->drawPrimitive(QStyle::PE_IndicatorCheckBox, & amp;checkBoxStyle, painter, & amp;checkBox);
    }
}

//Respond to mouse events and update data
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem & amp;option, const QModelIndex & amp;index)
{
    QRect decorationRect = option.rect;

    QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event);
    if (event->type() == QEvent::MouseButtonPress & amp; & amp; decorationRect.contains(mouseEvent->pos()))
    {
        if (index.column() == CHECK_BOX_COLUMN)
        {
            bool data = model->data(index, Qt::UserRole).toBool();
            model->setData(index, !data, Qt::UserRole);
        }
    }

    return QStyledItemDelegate::editorEvent(event, model, option, index);
}

Original link: https://www.cnblogs.com/whwywzhj/p/8883634.html

Benefits of this article,You can receive Qt development learning materials package and technical videos for free, including (C++ language basics, introduction to Qt programming, QT signals and slots mechanism, QT interface development -Image drawing, QT network, QT database programming, QT project practice, QT embedded development, Quick module, etc.) ↓↓↓↓↓↓See below↓↓Click at the bottom of the articleto receive the fee↓↓