天天看點

QTableView 代理 實作行高随内容變化<二>

方法二:

重寫代理painter方法,發送消息給QTableView重置行大小resizeRowToContents,然後代理會調用sizeHint(根據幫助文檔上說此方法傳回大小作為參考值),需要計算出内容所需高度(計算有兩種方法請看代碼)

優點:比方法一簡單、代碼少,隻會計算可視行

缺點:如果資料是變化的,則一直在計算(可以優化已經計算過且字元串沒有變化的就不再計算和重置大小)

QTableView*mTableView = new QTableView(false, this);
	mTableView->horizontalHeader()->setVisible(true);
	
	ItemDelegate *mDelegate = new ItemDelegate(mTableView);
	mTableView->setItemDelegate(mDelegate);
	connect(mDelegate, &ItemDelegate::SignalResizeRowHeight, mTableView, &QTableView::resizeRowToContents);
           
#pragma once

#include <QEvent>
#include <QPainter>
#include <QApplication>
#include <QStyledItemDelegate>

class ItemDelegate : public QStyledItemDelegate
{
	Q_OBJECT
public:
	explicit ItemDelegate(QObject* parent) :QStyledItemDelegate(parent)
	{
		connect(this, &DataStreamItemDelegate::SignalResizeRow, this, [=](const int32_t& h, const QModelIndex& index)
		{
			//算法:除第一列行最高
			int col = index.column();
			int row = index.row();
			FXD << row <<"  "<< col ;
			if (col == 0)
			{
				mHeights.clear(); //每次重置行資料,保證行高可以增高或者縮小
				if (mColumnsHeight.keys().contains(row))
				{
					return;
				}
				mRowMaxHeight = h;
				mColumnsHeight.insert(row, h);
			}
			else
			{
				//得到除去第一列的行最大高度
				if (mHeights.value(row) >= h)
				{
					mRowMaxHeight = mHeights.value(row);
				}
				else
				{
					mHeights.insert(row, h);
					mRowMaxHeight = h;
				}

				//與第一列行高度比較得到最大高度,即為本行最大高度
				if (mColumnsHeight.value(row) > mRowMaxHeight) //一般情況第一行内容最多
				{
					mRowMaxHeight = mColumnsHeight.value(row);
				}
			}

			emit SignalResizeRowHeight(row);
		});
	}
	virtual~ItemDelegate() {}

	void paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const override
	{
		FXD;
		
		QStyleOptionViewItem itemOption(option);
		initStyleOption(&itemOption, index);

		if (itemOption.state & QStyle::State_HasFocus)
		{
			itemOption.state &= ~QStyle::State_HasFocus; // 去除焦點虛線
		}

		if (itemOption.state & QStyle::State_MouseOver)
		{
			itemOption.state &= ~QStyle::State_MouseOver;
		}

		if (option.state.testFlag(QStyle::State_Selected))
		{
			itemOption.state &= ~QStyle::State_Selected;
		}

		if (!index.isValid())
		{
			return;
		}

		painter->save();
		QStyledItemDelegate::paint(painter, itemOption, index);
		painter->setPen(QPen(QBrush(QColor(0xD8, 0xD8, 0xD8)), HOR_LINE_WIDTH, ((QTableView*)tableView)->gridStyle()));
		painter->drawLine(itemOption.rect.bottomLeft(), itemOption.rect.bottomRight());
		painter->restore();
		
		paint(painter, option, index);
		if (option.rect.width() <= 0)
		{
			return;
		}

		QString data = index.model()->data(index, Qt::UserRole).value<QString>();

		painter->save();
		painter->setPen(QPen(Qt::black, 1, Qt::SolidLine));
		painter->setFont(option.font);

		QTextOption toption(Qt::AlignLeft);
		toption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
		painter->drawText(option.rect.adjusted(mPadding, mPadding, -mPadding, -mPadding), data, toption);
		painter->restore();

		//計算内容所需高度方法一
		int col = index.column();
		int row = index.row();
		if (col == 0) //第一列隻計算一次
		{
			if (!mColumnsHeight.keys().contains(row))
			{
				QRect rect = option.rect.adjusted(mPadding, 0, -mPadding, 0);
				rect.setHeight(500);
				painter->setFont(option.font);
				rect = painter->boundingRect(rect, data, toption).toRect();
				rect.setHeight(rect.height() + mPadding * 2);

				emit SignalResizeRow(rect.height(), index);
			}
		}
		else
		{
			QRect rect = option.rect.adjusted(mPadding, 0, -mPadding, 0);
			rect.setHeight(500);
			painter->setFont(option.font);
			rect = painter->boundingRect(rect, data, toption).toRect();
			rect.setHeight(rect.height() + mPadding * 2);

			emit SignalResizeRow(rect.height(), index);
		}
	}

	QSize sizeHint(const QStyleOptionViewItem& option, const QModelIndex& index) const override
	{
		if (option.rect.width() <= 0)
		{
			return QStyledItemDelegate::sizeHint(option, index);
		}

		FXD;
		//計算内容所需高度方法二,此方法有一個弊端 [參考我這篇文章](https://blog.csdn.net/u011100345/article/details/115914781)
		//QString data = index.model()->data(index, Qt::UserRole).value<QString>();
		//QRect rect = option.rect.adjusted(mPadding,0,-mPadding,0);
		//rect.setHeight(500);
		//rect = QFontMetrics(option.font).boundingRect(rect, Qt::TextWordWrap | Qt::TextWrapAnywhere, data); //
		//rect.setHeight(rect.height() + mPadding * 2);

		QSize size = QStyledItemDelegate::sizeHint(option, index);
		if (mRowMaxHeight > mRowHeight)
		{
			size.setHeight(mRowMaxHeight);
		}

		return size;
	}

signals:
	void SignalResizeRow(const int32_t& h, const QModelIndex& row)const;
	void SignalResizeRowHeight(const int32_t& row);

private:
	int32_t mPadding = 16; //内容上下左右空隙
	int32_t mRowMaxHeight = 0;
	QMap<int32_t, int32_t> mHeights; //其他列對應行最大高度
	QMap<int32_t, int32_t> mColumnsHeight;//資料流第一列隻計算一次存儲用于後續比較<行号-高度>
};
           

繼續閱讀