一 问题描述
一般情况,当QTreeView的item展开后,数据较多时会展示滚动条,如果item上有右对齐的显示文本,在item展开/收起变化时,竖直滚动条会呈现显示/隐藏变化,右对齐文本会“左右移动”,视觉效果差。原因是滚动条出现后“挤占了”item的空间。
Windows下有该问题,Mac下没有问题。
二 问题展示Demo
环境Win10,Qt5.9.2
新建UI工程,在UI拖入一个QTreeView和一个QLabel。主窗体构造函数代码如下:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 设置delegate
QTreeView* tree = ui->treeView;
tree->setItemDelegate(new MyTreeDelegate(tree, ui->label));
// 设置model
QStandardItemModel *model = new QStandardItemModel(tree);
model->setHorizontalHeaderLabels(QStringList()<< "Demo");
model->appendRow(new QStandardItem("1"));
model->item(0)->appendRow(new QStandardItem("11"));
model->item(0)->appendRow(new QStandardItem("12"));
model->item(0)->appendRow(new QStandardItem("13"));
model->item(0)->appendRow(new QStandardItem("14"));
model->item(0)->appendRow(new QStandardItem("15"));
model->item(0)->appendRow(new QStandardItem("16"));
model->item(0)->appendRow(new QStandardItem("17"));
model->item(0)->appendRow(new QStandardItem("18"));
model->item(0)->appendRow(new QStandardItem("19"));
model->item(0)->appendRow(new QStandardItem("20"));
model->appendRow(new QStandardItem("2"));
model->appendRow(new QStandardItem("3"));
model->appendRow(new QStandardItem("4"));
model->appendRow(new QStandardItem("5"));
model->appendRow(new QStandardItem("6"));
model->appendRow(new QStandardItem("7"));
tree->setModel(model);
// 设置VerticalScrollBarPolicy
tree->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}
其中MyTreeDelegate为自定义派生类:
// .h
class MyTreeDelegate : public QStyledItemDelegate
{
public:
MyTreeDelegate(QObject* parent, QLabel* label);
~MyTreeDelegate(){}
protected:
void paint(QPainter* painter,
const QStyleOptionViewItem& option,
const QModelIndex& index) const;
private:
QLabel* label_;
};
// .cpp
MyTreeDelegate::MyTreeDelegate(QObject *parent, QLabel* label)
: QStyledItemDelegate(parent),label_(label)
{
}
void MyTreeDelegate::paint(QPainter *painter,
const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QRect rect = option.rect;
rect.setRight(rect.right() - 20);
painter->drawText(rect, Qt::AlignVCenter | Qt::AlignRight, QString("rect.right:") +
QString::number(rect.right()));
QStyledItemDelegate::paint(painter, option, index);
}
显示效果:
很明显在item展开,出现竖直滚动条后,右对齐文本挤向左边了。不停展开/收起,右对齐文本”左右跳动“。
三 方案
将画文本的rect.right()补偿回来。
void MyTreeDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QRect rect = option.rect;
// 改动代码部分
QTreeView* tree = dynamic_cast<QTreeView*>(parent());
if(NULL != tree->verticalScrollBar() && tree->verticalScrollBar()->isVisible())
{
label_->setText(QString("TreeView VerticalScrollBar visible, width:") +
QString::number(tree->verticalScrollBar()->width()));
// 补偿宽度
rect.setRight(rect.right() + tree->verticalScrollBar()->width());
}
else
{
label_->setText(QString("TreeView VerticalScrollBar is not visible!"));
}
rect.setRight(rect.right() - 20);
painter->drawText(rect, Qt::AlignVCenter | Qt::AlignRight, QString("rect.right:") +
QString::number(rect.right()));
QStyledItemDelegate::paint(painter, option, index);
}
如图所示,不论竖直滚动条是否出现,item上右对齐的文本位置不会发生变化。