本文是模仿某些软件里的控件样式。在组合框里选择具有两级结构的数据,比如选某省->某市类似的数据。下述代码在VS2015和Qt5.9中测试通过。其运行效果如图。为了展示更多的功能,我还特地实现了滚动条的功能:
头文件:
class MItemView : public QAbstractItemView { Q_OBJECT public: MItemView(QWidget* parent = 0); public: void setModel(QAbstractItemModel *model) override; void paintEvent(QPaintEvent* event) override; QRect visualRect(const QModelIndex &index) const override; void scrollTo(const QModelIndex &index, ScrollHint hint) override; QModelIndex indexAt(const QPoint &point) const override; QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override; int horizontalOffset() const override; int verticalOffset() const override; bool isIndexHidden(const QModelIndex &index) const override; void setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) override; QRegion visualRegionForSelection(const QItemSelection &selection) const override; void resizeEvent(QResizeEvent* event) override; void verticalScrollbarValueChanged(int value) override; private: void updateRegion(); private: int offy; int preIndex; int subIndex; QVector<QRect> titleRegion; QVector<QRect> nameRegion; };
CPP文件。下面只实现了基本功能,鼠标悬停在某一项上的悬浮效果没有实现,如需要可自行重写QAbstractItemView::mouseMoveEvent(...)事件。另外,QAbstractItemView默认是可以多选和编辑的,如不需要可以禁用这些功能。本例虽不支持上述功能但未禁用:
const int titleWidth = 80; const int titleHeight = 26; const int nameWidth = 64; const int lineHeight = 2; MItemView::MItemView(QWidget* parent) : QAbstractItemView(parent) { setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); preIndex = 0; subIndex = -1; offy = 0; } void MItemView::setModel(QAbstractItemModel *model) { QAbstractItemView::setModel(model); updateRegion(); } void MItemView::updateRegion() { titleRegion.clear(); nameRegion.clear(); QAbstractItemModel* myModel = model(); QRect rect(0, offy, titleWidth, titleHeight); for (int i = 0; i < myModel->rowCount(); i++) { titleRegion.append(rect); rect.moveTo(rect.left() + rect.width(), rect.top()); } QModelIndex focus = myModel->index(preIndex, 0); rect = QRect(0, rect.bottom() + lineHeight, nameWidth, titleHeight); for (int i = 0; i < myModel->rowCount(focus); i++) { nameRegion.append(rect); rect.moveTo(rect.left() + rect.width(), rect.top()); if (rect.right() > width()) { rect = QRect(0, rect.bottom(), rect.width(), rect.height()); } } } void MItemView::paintEvent(QPaintEvent* event) { QPainter painter(viewport()); QAbstractItemModel* myData = model(); painter.setPen(Qt::black); for (int i = 0; i < myData->rowCount(); i++) { QString title = myData->data(myData->index(i, 0), Qt::DisplayRole).toString(); if (i == preIndex) { painter.fillRect(titleRegion[i], QColor(232, 174, 59)); } painter.drawText(titleRegion[i], Qt::AlignCenter, title); } QRect line(0, titleRegion[0].bottom(), width(), lineHeight); painter.fillRect(line, QColor(52, 114, 240)); QModelIndex focus = myData->index(preIndex, 0); for (int i = 0; i < myData->rowCount(focus); i++) { QString name = myData->data(myData->index(i, 0, focus), Qt::DisplayRole).toString(); if (subIndex == i) { painter.fillRect(nameRegion[i], QColor(255, 204, 51)); } painter.drawText(nameRegion[i], Qt::AlignCenter, name); } } QRect MItemView::visualRect(const QModelIndex &index) const { if (!index.parent().isValid()) { return titleRegion[index.row()]; } return nameRegion[index.row()]; } void MItemView::scrollTo(const QModelIndex &index, ScrollHint hint) { } QModelIndex MItemView::indexAt(const QPoint &point) const { for (int i = 0; i < titleRegion.size(); i++) { if (titleRegion[i].contains(point)) { return model()->index(i, 0); } } for (int i = 0; i < nameRegion.size(); i++) { if (nameRegion[i].contains(point)) { return model()->index(i, 0, model()->index(preIndex, 0)); } } return QModelIndex(); } //--------------------------------------------------------------------------------------- // 此函数是系统在用户使用键盘的上下左右等方向键操作时调用的。此例不支持键盘操作所以 // 不实现了 //--------------------------------------------------------------------------------------- QModelIndex MItemView::moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { return QModelIndex(); } int MItemView::horizontalOffset() const { return 0; } int MItemView::verticalOffset() const { return offy; } bool MItemView::isIndexHidden(const QModelIndex &index) const { return false; } void MItemView::setSelection(const QRect &rect, QItemSelectionModel::SelectionFlags command) { if ((command | QItemSelectionModel::Clear) || (command | QItemSelectionModel::Select)) { QModelIndex index = indexAt(rect.center()); if (index.parent().isValid()) { preIndex = index.parent().row(); subIndex = index.row(); } else /* 点击的是标题 */ { preIndex = index.row(); subIndex = -1; } updateRegion(); viewport()->update(); } } QRegion MItemView::visualRegionForSelection(const QItemSelection &selection) const { return QRegion(); } void MItemView::resizeEvent(QResizeEvent* event) { QAbstractItemView::resizeEvent(event); updateRegion(); if (!nameRegion.empty()) { int h = nameRegion.last().bottom(); if (h > height()) { QScrollBar* vbar = verticalScrollBar(); vbar->setMinimum(0); vbar->setMaximum(h - viewport()->height()); vbar->setPageStep(viewport()->height()); vbar->setSingleStep(10); } } } void MItemView::verticalScrollbarValueChanged(int value) { QAbstractItemView::verticalScrollbarValueChanged(value); for (auto& item : titleRegion) { item.adjust(0, -value - offy, 0, -value - offy); } for (auto& item : nameRegion) { item.adjust(0, -value - offy, 0, -value - offy); } offy = -value; }
在主窗口的构造函数初始化组合框。下方的QtTest是主窗口类;ui.cbSelect是组合框:
QtTest::QtTest(QWidget *parent) : QMainWindow(parent) { ui.setupUi(this); QStandardItemModel* model = new QStandardItemModel(this); QStandardItem* row0 = new QStandardItem(u8"特热突然"); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"1321")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"se地方")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"画图")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"士大夫")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"画图")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"看i他")); row0->appendRow(new QStandardItem(u8"突然")); row0->appendRow(new QStandardItem(u8"合肥")); row0->appendRow(new QStandardItem(u8"突然")); row0->appendRow(new QStandardItem(u8"别认识")); model->appendRow(row0); QStandardItem* row1 = new QStandardItem(u8"因为人"); row1->appendRow(new QStandardItem(u8"口语")); row1->appendRow(new QStandardItem(u8"1321")); row1->appendRow(new QStandardItem(u8"三个")); row1->appendRow(new QStandardItem(u8"说额")); row1->appendRow(new QStandardItem(u8"合肥")); row1->appendRow(new QStandardItem(u8"uio额")); row1->appendRow(new QStandardItem(u8"合肥")); model->appendRow(row1); QStandardItem* row2 = new QStandardItem(u8"iur一天"); row2->appendRow(new QStandardItem(u8"认为")); row2->appendRow(new QStandardItem(u8"1321")); row2->appendRow(new QStandardItem(u8"居就")); row2->appendRow(new QStandardItem(u8"维度")); row2->appendRow(new QStandardItem(u8"合肥")); row2->appendRow(new QStandardItem(u8"如同额")); row2->appendRow(new QStandardItem(u8"合肥")); model->appendRow(row2); ui.cbSelect->setModel(model); ui.cbSelect->setView(new MItemView()); }
标签:row0,控件,const,u8,自定义,QAbstractItemView,new,appendRow,QStandardItem From: https://www.cnblogs.com/mengxiangdu/p/17894722.html