首页 > 其他分享 >自定义一个QAbstractItemView控件

自定义一个QAbstractItemView控件

时间:2024-02-03 15:22:18浏览次数:35  
标签:row0 控件 const u8 自定义 QAbstractItemView new appendRow QStandardItem

本文是模仿某些软件里的控件样式。在组合框里选择具有两级结构的数据,比如选某省->某市类似的数据。下述代码在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

相关文章

  • 注册表监控工具可以近乎实时地监控注册表更改情况,让您不会错过任何问题。通过可自定义
    注册表监控工具可以近乎实时地监控注册表更改情况,让您不会错过任何问题。通过可自定义通知系统,您可以更轻松地及时了解用户操作或软件安装所引起的注册表更改。会在更改发生的当下显示更改(并让您进行检查和分析),而不是按特定间隔汇总活动数据,它还提供逐行精细数据,以更准确地查看注......
  • (12)动态生成菜单及绑定自定义事件
    varAddCollctMenus:ArrayOfTMenuItem;//动态菜单      procedureTForm1.Button5Click(Sender:TObject);Vari,AddCollctMenuCount:Integer;BeginAddCollctMenuCount:=Length(AddCollctMenus)-1;Fori:=0ToAddCollctMenuCountDo......
  • OpenWrt之自定义Hostname
    OpenWrt之自定义Hostname找到对应的代码,在feeds/./luci/modules/luci-lua-runtime/luasrc/sys.lua中,有cur:foreach("dhcp","dnsmasq",function(s)ifs.leasefileandfs.access(s.leasefile)then......
  • TP5框架 之自定义标签
    一、创建控制器<?phpnamespaceapp\common\taglib;usethink\auth\Auth;usethink\template\TagLib;classMyTagextendsTagLib{protected$tags=['auth'=>['attr'=>'rule','close'=>1......
  • OpenWrt之自定义Firmware Version
    OpenWrt之自定义FirmwareVersion首先,找到显示FirmwareVersion的代码,在/usr/lib/lua/luci/version.lua中:root@OpenWrt:/usr/lib/lua/luci#catversion.lualocalpcall,dofile,_G=pcall,dofile,_Gmodule"luci.version"ifpcall(dofile,"/etc/openwrt_rele......
  • 如何创建自定义启动器
    对于要自定义启动器,我们首先分析下此依赖结构,随后再创建maven项目就拿SpringBoot起步依赖来说。1.首先需要创建一个父工程如名称aliyun-parentd,编写pom.xml文件中的内容(1).修改打包方式为pom(2).继承springboot起步依赖名称是spring-boot-parent-starter2.后面需要创建你所......
  • 自定义jdk镜像
    1、安装docker这里使用Ubuntu系统安装docker,方便一点(偷懒)apt-getinstalldocker.io-y安装不了可以试试阿里云镜像源,在/etc/apt/sources.list.d/下新增文件:aliyun.sources.list,写入如下内容(ubuntu22.04示例,其他版本参考:ubuntu镜像_ubuntu下载地址_ubuntu安装教程-阿里巴巴......
  • 无边框 自定义页面 圆角 自定义关闭按钮 wfp 钱包夹
    无边框自定义页面圆角 自定义关闭按钮wfp钱包夹C#.net4.8wpfSqlServer2012消息队列Redis 来源银柱网-李银柱个人博客http://www.liyinzhu.com......
  • vue3,封装检测元素大小变化的自定义指令
    1//resizeObserver.ts2//监听元素大小变化的指令3constmap=newWeakMap()4constob=newResizeObserver((entries)=>{5for(constentryofentries){6//获取dom元素的回调7consthandler=map.get(entry.target)8//存在回调函......
  • 博客园自定义主题
    开源项目非常感谢作者的工作,下面是github主页和官方文档https://github.com/BNDong/Cnblogs-Theme-SimpleMemoryhttps://bndong.github.io/Cnblogs-Theme-SimpleMemory/v2.1/dist/三方教程https://www.cnblogs.com/chenkeer/p/15193179.html常见错误说明修改后,博客页面一......