📄 qtreeview.cpp
字号:
int i = d->itemDecorationAt(event->pos()); if (i == -1) { i = d->itemAtCoordinate(event->y()); if (i == -1) return; // user clicked outside the items const QModelIndex &index = d->viewItems.at(i).index; int column = d->header->logicalIndexAt(event->x()); QPersistentModelIndex persistent = index.sibling(index.row(), column); if (d->pressedIndex != persistent) { mousePressEvent(event); return; } // signal handlers may change the model emit doubleClicked(persistent); if (!persistent.isValid()) return; if (edit(persistent, DoubleClicked, event) || state() != NoState) return; // the double click triggered editing if (!style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, 0, this)) emit activated(persistent); d->executePostedLayout(); // we need to make sure viewItems is updated if (d->itemsExpandable && d->hasVisibleChildren(persistent)) { if (!((i < d->viewItems.count()) && (d->viewItems.at(i).index == persistent))) { // find the new index of the item for (i = 0; i < d->viewItems.count(); ++i) { if (d->viewItems.at(i).index == persistent) break; } if (i == d->viewItems.count()) return; } if (d->viewItems.at(i).expanded) d->collapse(i, true); else d->expand(i, true); updateGeometries(); viewport()->update(); } }}/*! \reimp*/void QTreeView::mouseMoveEvent(QMouseEvent *event){ Q_D(QTreeView); if (d->itemDecorationAt(event->pos()) == -1) // ### what about expanding/collapsing state ? QAbstractItemView::mouseMoveEvent(event);}/*! \reimp*/void QTreeView::keyPressEvent(QKeyEvent *event){ Q_D(QTreeView); QModelIndex current = currentIndex(); if (d->isIndexValid(current) && d->model) { switch (event->key()) { case Qt::Key_Asterisk: { QStack<QModelIndex> parents; parents.push(current); if (d->itemsExpandable) { while (!parents.isEmpty()) { QModelIndex parent = parents.pop(); for (int row = 0; row < d->model->rowCount(parent); ++row) { QModelIndex child = d->model->index(row, 0, parent); if (!d->isIndexValid(child)) break; parents.push(child); expand(child); } } expand(current); } break; } case Qt::Key_Plus: expand(current); break; case Qt::Key_Minus: collapse(current); break; } } QAbstractItemView::keyPressEvent(event);}/*! \reimp*/QModelIndex QTreeView::indexAt(const QPoint &point) const{ Q_D(const QTreeView); d->executePostedLayout(); int visualIndex = d->itemAtCoordinate(point.y()); QModelIndex idx = d->modelIndex(visualIndex); if (!idx.isValid()) return QModelIndex(); if (d->viewItems.at(visualIndex).spanning) return idx; int column = d->columnAt(point.x()); if (column == idx.column()) return idx; if (column < 0) return QModelIndex(); return d->model->sibling(idx.row(), column, idx);}/*! Returns the model index of the item above \a index.*/QModelIndex QTreeView::indexAbove(const QModelIndex &index) const{ Q_D(const QTreeView); if (!d->isIndexValid(index)) return QModelIndex(); d->executePostedLayout(); int i = d->viewIndex(index); if (--i < 0) return QModelIndex(); return d->viewItems.at(i).index;}/*! Returns the model index of the item below \a index.*/QModelIndex QTreeView::indexBelow(const QModelIndex &index) const{ Q_D(const QTreeView); if (!d->isIndexValid(index)) return QModelIndex(); d->executePostedLayout(); int i = d->viewIndex(index); if (++i >= d->viewItems.count()) return QModelIndex(); return d->viewItems.at(i).index;}/*! \internal Lays out the items in the tree view.*/void QTreeView::doItemsLayout(){ Q_D(QTreeView); d->viewItems.clear(); // prepare for new layout QModelIndex parent = d->root; if (d->model->hasChildren(parent)) { d->layout(-1); d->reexpandChildren(parent); } QAbstractItemView::doItemsLayout(); d->header->doItemsLayout();}/*! \reimp*/void QTreeView::reset(){ Q_D(QTreeView); d->expandedIndexes.clear(); d->hiddenIndexes.clear(); d->spanningIndexes.clear(); d->viewItems.clear(); QAbstractItemView::reset();}/*! Returns the horizontal offset of the items in the treeview. Note that the tree view uses the horizontal header section positions to determine the positions of columns in the view. \sa verticalOffset()*/int QTreeView::horizontalOffset() const{ Q_D(const QTreeView); return d->header->offset();}/*! Returns the vertical offset of the items in the tree view. \sa horizontalOffset()*/int QTreeView::verticalOffset() const{ Q_D(const QTreeView); if (verticalScrollMode() == QAbstractItemView::ScrollPerItem) { if (uniformRowHeights()) return verticalScrollBar()->value() * d->defaultItemHeight; // If we are scrolling per item and have non-uniform row heights, // finding the vertical offset in pixels is going to be relatively slow. // ### find a faster way to do this int offset = 0; for (int i = 0; i < d->viewItems.count(); ++i) { if (i == verticalScrollBar()->value()) return offset; offset += d->itemHeight(i); } return 0; } // scroll per pixel return verticalScrollBar()->value();}/*! Move the cursor in the way described by \a cursorAction, using the information provided by the button \a modifiers.*/QModelIndex QTreeView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers){ Q_D(QTreeView); Q_UNUSED(modifiers); d->executePostedLayout(); QModelIndex current = currentIndex(); if (!current.isValid()) { int i = 0; while (i < d->viewItems.count() && d->hiddenIndexes.contains(d->viewItems.at(i).index)) ++i; return d->viewItems.value(i).index; } int vi = qMax(0, d->viewIndex(current)); switch (cursorAction) { case MoveNext: case MoveDown:#ifdef QT_KEYPAD_NAVIGATION if (vi == d->viewItems.count()-1 && QApplication::keypadNavigationEnabled()) return d->model->index(0, 0, d->root);#endif return d->modelIndex(d->below(vi)); case MovePrevious: case MoveUp:#ifdef QT_KEYPAD_NAVIGATION if (vi == 0 && QApplication::keypadNavigationEnabled()) return d->modelIndex(d->viewItems.count() - 1);#endif return d->modelIndex(d->above(vi)); case MoveLeft: { QScrollBar *sb = horizontalScrollBar(); if (vi < d->viewItems.count() && d->viewItems.at(vi).expanded && d->itemsExpandable && sb->value() == sb->minimum()) d->collapse(vi, true); else { bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this); if (descend) { QModelIndex par = current.parent(); if (par.isValid()) return par; else descend = false; } if (!descend) { sb->setValue(sb->value() - sb->singleStep()); } } updateGeometries(); viewport()->update(); break; } case MoveRight: if (vi < d->viewItems.count() && !d->viewItems.at(vi).expanded && d->itemsExpandable) { d->expand(vi, true); } else { bool descend = style()->styleHint(QStyle::SH_ItemView_ArrowKeysNavigateIntoChildren, 0, this); if (descend) { QModelIndex idx = d->modelIndex(d->below(vi)); if (idx.parent() == current) return idx; else descend = false; } if (!descend) { QScrollBar *sb = horizontalScrollBar(); sb->setValue(sb->value() + sb->singleStep()); } } updateGeometries(); viewport()->update(); break; case MovePageUp: return d->modelIndex(d->pageUp(vi)); case MovePageDown: return d->modelIndex(d->pageDown(vi)); case MoveHome: return d->model->index(0, 0, d->root); case MoveEnd: return d->modelIndex(d->viewItems.count() - 1); } return current;}/*! Applies the selection \a command to the items in or touched by the rectangle, \a rect. \sa selectionCommand()*/void QTreeView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command){ Q_D(QTreeView); if (!selectionModel() || rect.isNull()) return; d->executePostedLayout(); QPoint tl(isRightToLeft() ? qMax(rect.left(), rect.right()) : qMin(rect.left(), rect.right()), qMin(rect.top(), rect.bottom())); QPoint br(isRightToLeft() ? qMin(rect.left(), rect.right()) : qMax(rect.left(), rect.right()), qMax(rect.top(), rect.bottom())); QModelIndex topLeft = indexAt(tl); QModelIndex bottomRight = indexAt(br); if (!topLeft.isValid() && !bottomRight.isValid()) return; if (!topLeft.isValid() && !d->viewItems.isEmpty()) topLeft = d->viewItems.first().index; if (!bottomRight.isValid() && !d->viewItems.isEmpty()) { const int column = d->header->logicalIndex(d->header->count() - 1); const QModelIndex index = d->viewItems.last().index; bottomRight = index.sibling(index.row(), column); } if (selectionBehavior() != SelectRows) { QItemSelection selection; if (topLeft.isValid() && bottomRight.isValid()) { selection.append(QItemSelectionRange(topLeft, bottomRight)); selectionModel()->select(selection, command); } } else { d->select(d->viewIndex(topLeft), d->viewIndex(bottomRight), command); }}/*! Returns the rectangle from the viewport of the items in the given \a selection.*/QRegion QTreeView::visualRegionForSelection(const QItemSelection &selection) const{ Q_D(const QTreeView); if (selection.isEmpty()) return QRegion(); QRegion selectionRegion; for (int i = 0; i < selection.count(); ++i) { QItemSelectionRange range = selection.at(i); if (!range.isValid()) continue; QModelIndex parent = range.parent(); QModelIndex leftIndex = range.topLeft(); int columnCount = d->model->columnCount(parent); while (leftIndex.isValid() && isIndexHidden(leftIndex)) { if (leftIndex.column() + 1 < columnCount) leftIndex = d->model->index(leftIndex.row(), leftIndex.column() + 1, parent); else leftIndex = QModelIndex(); } if (!leftIndex.isValid()) continue; const QRect leftRect = visualRect(leftIndex); int top = leftRect.top(); QModelIndex rightIndex = range.bottomRight(); while (rightIndex.isValid() && isIndexHidden(rightIndex)) { if (rightIndex.column() - 1 >= 0) rightIndex = d->model->index(rightIndex.row(), rightIndex.column() - 1, parent); else rightIndex = QModelIndex(); } if (!rightIndex.isValid()) continue; const QRect rightRect = visualRect(rightIndex); int bottom = rightRect.bottom(); if (top > bottom) qSwap<int>(top, bottom); int height = bottom - top + 1; if (d->header->sectionsMoved()) { for (int c = range.left(); c <= range.right(); ++c) selectionRegion += QRegion(QRect(columnViewportPosition(c), top, columnWidth(c), height)); } else { QRect combined = leftRect|rightRect; combined.setX(columnViewportPosition(isRightToLeft() ? range.right() : range.left()));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -