Qt表格入门(优化篇)
<br><p>摘要:<br>
为提升大数据量下的渲染性能,本文通过 <code>QStyledItemDelegate</code> 直接绘制单选按钮(使用 <code>QStyleOptionButton</code> 和 <code>drawControl</code>),并在 <code>editorEvent</code> 中处理点击逻辑,避免创建真实控件,显著优化了加载与显示效率。<br>
<br></p>
<p>关键词:<br>
<code>QStyledItemDelegate</code>、<code>QStyleOptionButton</code>、<code>drawControl</code>、<code>editorEvent</code>、优化、渲染<br>
<br></p>
<p>版本:Qt5.14.2<br>
<br></p>
<h4 id="问题描述">问题描述:</h4>
<p> 在上一篇文章中,使用样式代理类<code>QStyledItemDelegate</code>和基础组件(<code>QRadioButton</code>、<code>QWidget</code>)的组合比较简易地实现了功能,但是在后续使用中发现,大量数据导致视图渲染卡顿,需要对代码进一步优化。<br>
<br></p>
<h4 id="代码如下">代码如下:</h4>
<details open=""><summary>点击折叠或展开代码</summary>
<pre><code class="language-C++">// 优化代理类
class RadioDelegateV2 : public QStyledItemDelegate
{
Q_OBJECT
public:
RadioDelegateV2(QObject *parent = nullptr);
~RadioDelegateV2();
protected:
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index) override;
};
RadioDelegateV2::RadioDelegateV2(QObject *parent) : QStyledItemDelegate(parent)
{
}
RadioDelegateV2::~RadioDelegateV2()
{
}
void RadioDelegateV2::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
int state = index.data(Qt::DisplayRole).toInt(); // 0=女, 1=男
// 分割矩形为左右两半
QRect rect = option.rect;
QRect leftRect(rect.left(), rect.top(), rect.width() / 2, rect.height());
QRect rightRect(rect.left() + rect.width() / 2, rect.top(), rect.width() / 2, rect.height());
// 绘制“男”按钮(左)
QStyleOptionButton btnOn;
btnOn.rect = leftRect;
btnOn.text = "男";
btnOn.state |= QStyle::State_Enabled;
if (state == 1) {
btnOn.state |= QStyle::State_Sunken | QStyle::State_On;
} else {
btnOn.state |= QStyle::State_Raised;
}
// 绘制“女”按钮(右)
QStyleOptionButton btnOff;
btnOff.rect = rightRect;
btnOff.text = "女";
btnOff.state |= QStyle::State_Enabled;
if (state == 0) {
btnOff.state |= QStyle::State_Sunken | QStyle::State_On;
} else {
btnOff.state |= QStyle::State_Raised;
}
QApplication::style()->drawControl(QStyle::CE_RadioButton, &btnOn,painter);
QApplication::style()->drawControl(QStyle::CE_RadioButton, &btnOff, painter);
}
QSize RadioDelegateV2::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(index);
// 返回足够宽以容纳两个按钮
QFontMetrics fm(option.font);
int width = fm.horizontalAdvance("男") + fm.horizontalAdvance("女") + 40; // 加 padding
int height = qMax(fm.height() + 8, 24);
return QSize(width, height);
}
bool RadioDelegateV2::editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option, const QModelIndex &index)
{
if (event->type() == QEvent::MouseButtonPress) {
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
QPoint pos = mouseEvent->pos();
QRect rect = option.rect;
int half = rect.width() / 2;
int newState;
if (pos.x() < rect.left() + half) {
newState = 1; // 点击左侧 → 男
} else {
newState = 0; // 点击右侧 → 女
}
// 更新模型
model->setData(index, newState, Qt::DisplayRole);
return true;
}
return false;
}
</code></pre>
</details>
<br>
<p>代码说明:</p>
<ol>
<li>在<code>paint()</code>函数中,创建两个<code>QStyleOptionButton</code>并设置属性;两个按钮根据数据(性别)设置不同的状态;然后使用<code>drawControl()</code>函数绘制按钮;</li>
<li>在<code>sizeHint()</code>函数中,计算可以容纳下两个按钮的宽度;</li>
<li>在<code>editorEvent()</code>函数中,对编辑事件进行操作,判断点击区域,然后更新数据。<br>
<br></li>
</ol>
<h4 id="其他说明">其他说明:</h4>
<ol>
<li><code>openPersistentEditor()</code>函数调用可以全部优化掉 ;</li>
<li>如果数据变化有连接的信号,可以使用<code>QStandardItemModel</code>的<code> void itemChanged(QStandardItem *item)</code>信号修改。<br>
<br></li>
</ol>
<h4 id="参考文献">参考文献:</h4>
<ul>
<li>QTableView 一列添加两个按钮</li>
</ul>
<br>
</div>
<div id="MySignature" role="contentinfo">
<br>
<br>
<p>作者:薄暮知秋</p>
<p>本文来自博客园,转载请注明原文链接:https://www.cnblogs.com/wsry/p/19749661</p><br><br>
来源:https://www.cnblogs.com/wsry/p/19749661
頁:
[1]