在QTableView中使用各類自定義委託

https://blog.csdn.net/hu_linux/article/details/52791665 
該連接也有自定義控件用法,比較好看
 
QT的MVC(View/Delegate)模型十分強大,能夠利用各類控件來對錶格的輸入進行限制。

思路:
1:爲每一列定義委託:
A:第一列是編號列,使用只讀委託,令該列的單元格是隻讀的
B:第三列是ID列,只能輸入1-12個數字,利用QLineEdit委託和正則表達式對輸入進行限制
C:第四年齡列,利用QSpinBox委託進行輸入限制,只能輸入1-100之間的數字
D:第五列是性別列,利用QComboBox委託對輸入進行限制,該列的單元格只能輸入Male或Female
E:第六列是頭像列,在該列的單元格中央放置一張頭像
2:定義代理類,把全部單元格中的字符居中顯示。
3:利用QSS,將表格的背景色弄成黃藍相間。linux

截圖:正則表達式

 

上代碼:app

#include <QtGui>   
#include <QItemDelegate>
 #include <QSpinBox>
 
//編號列,只讀委託   
//這個方法我還真想不到,呵呵   
class ReadOnlyDelegate : public QItemDelegate  
{  
    Q_OBJECT  
public:  
    ReadOnlyDelegate(QObject *parent = 0): QItemDelegate(parent) { }  
    QWidget *createEditor(QWidget*parent, const QStyleOptionViewItem &option,  
        const QModelIndex &index) const  
    {  
        return NULL;  
    }  
};  
  
//ID列,只能輸入1-12個數字   
//利用QLineEdit委託和正則表達式對輸入進行限制   
class UserIDDelegate : public QItemDelegate  
{  
    Q_OBJECT  
public:  
    UserIDDelegate(QObject *parent = 0): QItemDelegate(parent) { }  
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,  
        const QModelIndex &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 &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 &index) const  
    {  
        QLineEdit *lineEdit = static_cast<QLineEdit*>(editor);  
        QString text = lineEdit->text();  
        model->setData(index, text, Qt::EditRole);  
    }  
    void updateEditorGeometry(QWidget *editor,  
        const QStyleOptionViewItem &option, const QModelIndex &index) const  
    {  
        editor->setGeometry(option.rect);  
    }  
};  
  
//年齡列,利用QSpinBox委託進行輸入限制,只能輸入1-100之間的數字   
class AgeDelegate : public QItemDelegate  
{  
    Q_OBJECT  
public:  
    AgeDelegate(QObject *parent = 0): QItemDelegate(parent) { }  
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,  
        const QModelIndex &index) const  
    {  
        QSpinBox *editor = new QSpinBox(parent);  
        editor->setMinimum(1);  
        editor->setMaximum(100);  
        return editor;  
    }  
    void 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 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 updateEditorGeometry(QWidget *editor,  
        const QStyleOptionViewItem &option, const QModelIndex &index) const  
    {  
        editor->setGeometry(option.rect);  
    }  
};  
  
//性別列,利用QComboBox委託對輸入進行限制   
//這一列的單元格只能輸入Male或Female   
class SexDelegate : public QItemDelegate  
{  
    Q_OBJECT  
public:  
    SexDelegate(QObject *parent = 0): QItemDelegate(parent) { }  
    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,  
        const QModelIndex &index) const  
    {  
        QComboBox *editor = new QComboBox(parent);  
        editor->addItem("Female");  
        editor->addItem("Male");  
        return editor;  
    }  
    void setEditorData(QWidget *editor, const QModelIndex &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 &index) const  
    {  
        QComboBox *comboBox = static_cast<QComboBox*>(editor);  
        QString text = comboBox->currentText();  
        model->setData(index, text, Qt::EditRole);  
    }  
    void updateEditorGeometry(QWidget *editor,  
        const QStyleOptionViewItem &option, const QModelIndex &index) const  
    {  
        editor->setGeometry(option.rect);  
    }  
};  
  
//頭像列,只是在單元格中央放一張小圖而已   
class IconDelegate : public QItemDelegate  
{  
    Q_OBJECT  
public:  
    IconDelegate(QObject *parent = 0): QItemDelegate(parent) { }  
    void paint(QPainter *painter, const QStyleOptionViewItem &option,  
        const QModelIndex & index ) const  
    {  
        //show.bmp是在工程目錄中的一張圖片(其實就是QQ的圖標啦,呵呵)  
        QPixmap pixmap = QPixmap("show.bmp").scaled(24, 24);  
        qApp->style()->drawItemPixmap(painter, option.rect,  Qt::AlignCenter, QPixmap(pixmap));  
    }  
};  
  
//代理類,把全部單元格中的字符居中顯示   
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 &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;  
  
    //把表格的背景調成黃藍相間   
    //這種方法是在網上看到的,用起來還真方便啊   
    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);  
  
    //爲每一列加載委託   
    ReadOnlyDelegate readOnlyDelegate;  
    //tableView->setItemDelegateForColumn(0, &readOnlyDelegate);  //我用了會報錯
    tableView->setItemDelegateForColumn(0, new ReadonlyDelegate(this)); //我用的是這種
    UserIDDelegate userIDDelegate;  
    tableView->setItemDelegateForColumn(1, &userIDDelegate);  
    AgeDelegate spinBoxDelegate;  
    tableView->setItemDelegateForColumn(3, &spinBoxDelegate);  
    SexDelegate comboBoxDelegate;  
    tableView->setItemDelegateForColumn(4, &comboBoxDelegate);  
    IconDelegate iconDelegate;  
    tableView->setItemDelegateForColumn(5, &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和QModelIndex;ide

 先上圖看效果吧函數

選擇文件按鈕這一列,第0行是點擊後進入編輯模式時顯示按鈕的狀況。測試

下面一行是顯示的選擇文件的全路徑。ui

第2行」C:「是初始化時設置的值,只是爲了測試顯示。this

最後一行是沒有選擇文件。url

 

我實現的這個SelectFileButton辦法:spa

QPushButton;

SelectFileButton裏實現一個槽函數:功能,點擊時選擇文件並返回路徑。

cQItemDelegate;

d、而後再重寫createEditor();返回SelectFileButton的指針

e、重寫setModelData()、setEditorData(); 設置模型數據和設置編輯數據的。

#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 & index, QWidget *parent = 0)
	:	QPushButton(parent)
	{
		Init(index);
	}
	SelectFileButton(const QModelIndex & index, const QString &text, QWidget *parent = 0) 
		: QPushButton(text, parent)
	{
		Init(index);
	}
	SelectFileButton(const QModelIndex & index, const QIcon& icon, const QString &text, QWidget *parent = 0) 
		:QPushButton(icon, text, parent)
	{
		Init(index);
	}
	~SelectFileButton() {
		qDebug() << "~SelectFileButton";
	}
protected:
	void Init(const QModelIndex & 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();	 //這裏開啓新的線程,頂層會釋放這個按鈕,因此要把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 &option,
		const QModelIndex &index) const
	{
		SelectFileButton* btn = new SelectFileButton(index,QStringLiteral("查找文件路徑"), parent);	  //這個是其餘線程裏的 因此不能保存下來。每次的btn還不同

		return btn;
		
	}
	
	void setModelData(QWidget *editor, QAbstractItemModel *model,
		const QModelIndex &index) const;
	void setEditorData(QWidget *editor, const QModelIndex &index) const;

public:
	SelectFileButtonDelegate(QObject *parent);
	~SelectFileButtonDelegate();

private:
	QPushButton* m_btn;
	
};

#endif // SELECTFILEBUTTONDELEGATE_H

  

經過painter畫自定義控件

 

 QStyleOption子類:

 

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

 

一 、painter 自定義進度條 
//自定義進度條 BarDelegate::BarDelegate( QObject *parent ) : QAbstractItemDelegate( parent ) { } void BarDelegate::paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const { if( option.state & QStyle::State_Selected ) painter->fillRect( option.rect, option.palette.highlight() ); // 數據是存儲在QStandardItemModel的QStandardItem,會自動根據當前行進行匹配(我認爲)
  int value = index.model()->data( index, Qt::DisplayRole ).toInt(); // 這句,取得當前行的數據
  qDebug() << value; double factor = double(value)/100.0; // 計算比例因子
 painter->save(); // 保存舊畫板(我認爲) // 進度條背景色
  if( factor > 0.8 ) { painter->setBrush( Qt::red ); // 超過0.8畫純紅色
    factor = 1; } else painter->setBrush( QColor( 0, int(factor*255), 255-int(factor*255) ) ); // 不然顏色依次變淡

  int n = factor*100; QString str1 = QString("%1\%").arg(n); painter->setPen( Qt::red ); // 畫筆顏色(這裏沒用到,我認爲) // 前面都是準備工做,這裏纔是真正畫進度條
  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(); // 恢復新畫板(我認爲)
} QSize BarDelegate::sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const { return QSize( 45, 15 ); // 隨便改,不影響(我認爲)
}
class BarDelegate : public QAbstractItemDelegate { public: BarDelegate( QObject *parent = 0 ); // 覆蓋兩個函數就能夠顯示進度條
  void paint( QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index ) const; QSize sizeHint( const QStyleOptionViewItem &option, const QModelIndex &index ) const; };

 1  painter進度條 QStyleOptionProgressBar

void ProgressBarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &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 & QStyle::State_Selected) { painter->fillRect(option.rect, option.palette.highlight()); painter->setBrush(option.palette.highlightedText()); } QApplication::style()->drawControl(QStyle::CE_ProgressBar, &progressBarOption, painter); painter->restore(); } else { return QItemDelegate::paint (painter, option, index); } }

 

2、painter自定義按鈕  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("編輯按鈕") << QStringLiteral("刪除按鈕"); } // 設置按鈕正常、劃過、按下樣式 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() { } // 繪製按鈕 void TableViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem viewOption(option); initStyleOption(&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) { // 計算按鈕顯示區域 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) { // 繪製按鈕  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, &button, painter, pWidget); } } } // 響應按鈕事件 - 劃過、按下 bool TableViewDelegate::editorEvent(QEvent* event, QAbstractItemModel* model, const QStyleOptionViewItem& option, const QModelIndex& 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; // 還原鼠標樣式  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); // 鼠標位於按鈕之上 if (!button.rect.contains(m_mousePoint)) continue; bRepaint = true; switch (event->type()) { // 鼠標滑過 case QEvent::MouseMove: { // 設置鼠標樣式爲手型 //QApplication::setOverrideCursor(Qt::PointingHandCursor);  m_nType = 0; QToolTip::showText(pEvent->globalPos(), m_list.at(i)); break; } // 鼠標按下 case QEvent::MouseButtonPress: { m_nType = 1; break; } // 鼠標釋放 case QEvent::MouseButtonRelease: { if (i == 0) { emit EditData(index); } else { emit deleteData(index); } break; } default: break; } } return bRepaint; }

 

三 painter 設置圖片

void ItemdelegateTest::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem viewOption(option); if (viewOption.state & 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 &option, const QModelIndex &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 && DrawRect.contains(mouseEvent->pos())) { emit deleteItem(index); } if (event->type() == QEvent::MouseMove && DrawRect.contains(mouseEvent->pos())) { QCursor cursor(Qt::PointingHandCursor); QApplication::setOverrideCursor(cursor); QToolTip::showText(mouseEvent->globalPos(), "刪除"); } else { QCursor cursor(Qt::ArrowCursor); QApplication::setOverrideCursor(cursor); } return QStyledItemDelegate::editorEvent(event, model, option, index); }

 

 

 

panier繪製checkbox

CheckBoxDelegate::CheckBoxDelegate(QObject *parent) : QStyledItemDelegate(parent) { } CheckBoxDelegate::~CheckBoxDelegate() { } // 繪製複選框
void CheckBoxDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem viewOption(option); initStyleOption(&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, &checkBoxStyle, painter, &checkBox); } } // 響應鼠標事件,更新數據
bool CheckBoxDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) { QRect decorationRect = option.rect; QMouseEvent *mouseEvent = static_cast<QMouseEvent *>(event); if (event->type() == QEvent::MouseButtonPress && 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); } --------------------- 做者:一去丶二三裏 來源:CSDN 原文:https://blog.csdn.net/liang19890820/article/details/50721200 
版權聲明:本文爲博主原創文章,轉載請附上博文連接!
相關文章
相關標籤/搜索