我有两列的QTreeView
对象。我希望第一个能够拉伸(stretch),第二个具有固定宽度。
This question有一个答案,我尝试将其应用于我的案例。我将这些设置为我的树头:
header->setSectionResizeMode(0, QHeaderView::Stretch);
header->setSectionResizeMode(1, QHeaderView::Fixed);
header->setStretchLastSection(false);
这样我的程序崩溃了。我猜问题是当我调用setSectionResizeMode()
时,该列不存在。摘录自文档:现在,当我将这些属性设置为
QTreeWidget
对象时,一切都很好:#include <QApplication>
#include <QTreeWidget>
#include <QHeaderView>
int main(int argc, char **argv)
{
QApplication app(argc, argv);
QTreeWidget treeWidget;
treeWidget.setColumnCount(2);
QList<QTreeWidgetItem *> items;
for (int i = 0; i < 5; ++i)
items.append(new QTreeWidgetItem(&treeWidget,
QStringList{ "item", QString("%1").arg(i) }));
treeWidget.insertTopLevelItems(0, items);
auto header = treeWidget.header();
header->setSectionResizeMode(0, QHeaderView::Stretch);
header->setSectionResizeMode(1, QHeaderView::Fixed);
header->setStretchLastSection(false);
header->setDefaultSectionSize(50);
treeWidget.show();
return QApplication::exec();
}
QTreeView
有什么问题?使用时应何时调用setSectionResizeMode()
?附言这是我的代码:
main.cpp
#include <QApplication>
#include <QTreeWidget>
#include "TreeModel.h"
#include "TreeItem.h"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
TreeModel model;
NodeDelegate delegate;
QTreeView treeView;
treeView.setModel(&model);
treeView.setItemDelegate(&delegate);
TreeHeader header(Qt::Horizontal, &treeView);
header.setStretchLastSection(false);
header.setSectionResizeMode(0, QHeaderView::Stretch); // <--- crashes, column 0 doesn't exist yet
header.setSectionResizeMode(1, QHeaderView::Fixed); // <--- crashes, column 1 doesn't exist yet
header.setDefaultSectionSize(50);
treeView.setHeader(&header);
treeView.show();
return QApplication::exec();
}
TreeItem.h #pragma once
#include <QVariant>
#include <QVector>
#include <QStyleOptionViewItem>
#include <QItemDelegate>
#include <QPainter>
class TreeItem
{
public:
TreeItem(QVector<QVariant> data, TreeItem *parent = nullptr)
: m_itemData(std::move(data))
, m_parentItem(parent)
{
}
~TreeItem()
{
qDeleteAll(m_childItems);
}
TreeItem *child(const int row) const
{
return m_childItems.value(row);
}
int childCount() const
{
return m_childItems.count();
}
int row() const
{
if (m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem *>(this));
return 0;
}
int columnCount() const
{
return m_itemData.count();
}
QVariant data(const int column) const
{
return m_itemData.value(column);
}
TreeItem *parentItem() const
{
return m_parentItem;
}
bool setData(const int column, const QVariant &value)
{
return column >= 0 && column < m_itemData.size() && (m_itemData[column] = value, true);
}
bool insertRows(const int position, const int count, const int columns)
{
if (position < 0 || position > m_childItems.size())
return false;
for (auto row = 0; row < count; ++row)
{
// create a new row with columns number of columns
const QVector<QVariant> newData(columns);
m_childItems.insert(position, new TreeItem{ newData, this });
}
return true;
}
bool removeRows(const int position, const int count)
{
if (position < 0 || position > m_itemData.size())
return false;
for (auto row = 0; row < count; ++row)
delete m_childItems.takeAt(position);
return true;
}
bool insertColumns(const int position, const int columns)
{
if (position < 0 || position > m_childItems.size())
return false;
for (auto column = 0; column < columns; ++column)
m_itemData.insert(position, QVariant{});
for (auto child : m_childItems)
child->insertColumns(position, columns);
return true;
}
bool removeColumns(const int position, const int columns)
{
if (position < 0 || position > m_childItems.size())
return false;
for (auto column = 0; column < columns; ++column)
m_itemData.remove(position);
for (auto child : m_childItems)
child->removeColumns(position, columns);
return true;
}
bool paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QRect rect = option.rect;
painter->drawText(rect, "data");
return true;
}
private:
QList<TreeItem *> m_childItems;
QVector<QVariant> m_itemData;
TreeItem *m_parentItem = nullptr;
};
class NodeDelegate : public QItemDelegate
{
public:
NodeDelegate(QObject *parent = nullptr)
: QItemDelegate(parent)
{
}
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override
{
if (!index.isValid()) return;
auto node = static_cast<TreeItem *>(index.internalPointer());
if (!node->paint(painter, option, index))
QItemDelegate::paint(painter, option, index);
}
};
TreeModel.h #pragma once
#include <QAbstractItemModel>
#include <QHeaderView>
#include "TreeItem.h"
/*
* A read-only tree model
*/
class TreeModel final : public QAbstractItemModel
{
Q_OBJECT
public:
TreeModel(QObject *parent = nullptr)
: QAbstractItemModel(parent)
{
const auto rootData = QVector<QVariant>{} << "Number" << "Data";
m_pRootItem = new TreeItem{ rootData };
}
QModelIndex index(const int row, const int column, const QModelIndex &parent /* = QModelIndex() */) const
{
return QModelIndex{};
}
QModelIndex parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex{};
const auto childItem = getItem(index);
const auto parentItem = childItem->parentItem();
// don't return a model index corresponding to the root item
if (parentItem == m_pRootItem)
return QModelIndex{};
return createIndex(parentItem->row(), 0, parentItem);
}
int rowCount(const QModelIndex &parent /* = QModelIndex() */) const
{
const auto parentItem = getItem(parent);
return parentItem->childCount();
}
int columnCount(const QModelIndex &parent /* = QModelIndex() */) const
{
// all items have the same number of columns
return m_pRootItem->columnCount();
}
QVariant data(const QModelIndex &index, const int role /* = Qt::DisplayRole */) const
{
if (!index.isValid())
return QVariant{};
if (role != Qt::DisplayRole)
return QVariant{};
const auto item = static_cast<TreeItem *>(index.internalPointer());
return item->data(index.column());
}
Qt::ItemFlags flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
}
QVariant headerData(const int section, const Qt::Orientation orientation, const int role /* = Qt::DisplayRole */) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole)
return m_pRootItem->data(section);
return QVariant{};
}
bool setData(const QModelIndex &index, const QVariant &value, int role /* = Qt::EditRole */)
{
if (role != Qt::EditRole)
return false;
auto item = getItem(index);
const auto result = item->setData(index.column(), value);
if (result)
emit dataChanged(index, index);
return result;
}
bool setHeaderData(int section, Qt::Orientation orientation,
const QVariant &value, int role)
{
if (role != Qt::EditRole || orientation != Qt::Horizontal)
return false;
const auto result = m_pRootItem->setData(section, value);
if (result)
emit headerDataChanged(orientation, section, section);
return result;
}
TreeItem *getItem(const QModelIndex &index) const
{
if (index.isValid())
{
if (const auto item = static_cast<TreeItem *>(index.internalPointer()))
return item;
}
return m_pRootItem;
}
TreeItem *m_pRootItem{};
};
class TreeHeader : public QHeaderView
{
public:
TreeHeader(Qt::Orientation orientation, QWidget *parent = nullptr)
: QHeaderView(orientation, parent)
{
}
protected:
void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const override
{
if (!rect.isValid()) return;
QStyleOptionHeader option;
option.initFrom(this);
option.text = logicalIndex == 0 ? "Header text" : "#";
if (logicalIndex == 1)
option.textAlignment = Qt::AlignLeft;
}
};
最佳答案
您必须在QTreeView中设置标题,因为列数是通过模型处理的,即标题使用的是在 View 中建立的模型:
TreeHeader header(Qt::Horizontal, &treeView);
treeView.setHeader(&header); // <---
header.setStretchLastSection(false);
// ...