天天看点

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;//数据流第一列只计算一次存储用于后续比较<行号-高度>
};
           

继续阅读