拖拽之路(原生之初二):自定义QListView实现美观的拖拽样式

环境配置 :MinGW + QT 5.12
效果图(左边是QListView传统拖拽样式(很奇怪),右边是自定义拖拽样式):
拖拽之路(原生之初二):自定义QListView实现美观的拖拽样式_第1张图片

这种自定义拖拽样式的灵感来自于Chrome浏览器的书签栏。这篇文章命名为 “原生之初” 是因为没有加入 设置item在鼠标release时选中 以及 设置item在hover状态下改变图标样式 的代码,实现了最基本的自定义拖拽样式。本文中拖拽的特点是:拖拽即选中

实现功能及方法:

  • 拖拽功能实现:继承QListView(重写drag事件)
  • 绘制dropIndicator:继承QListView(使用update()进行控制) + 继承QStyledItemDelegate (使用画笔进行绘制)

拖拽时缩略图thumbnail类:

  • Qt绘制形状不规则窗口(一)

下面几篇文章除了 “原生之初” 都加入了 设置item在鼠标release时选中 以及 设置item在hover状态下改变图标样式 的代码:

  • 拖拽之路(原生之初一):自定义QListWidget实现美观的拖拽样式
  • 拖拽之路(原生之初二):自定义QListView实现美观的拖拽样式
  • 拖拽之路(一):自定义QListWidget实现美观的拖拽样式(拖拽即选中)
  • 拖拽之路(二):自定义QListWidget实现美观的拖拽样式(拖拽不影响选中)
  • 拖拽之路(三):自定义QListView实现美观的拖拽样式(拖拽即选中)
  • 拖拽之路(四):自定义QListView实现美观的拖拽样式(拖拽不影响选中)
  • 拖拽之路(五):自定义QListWidget实现美观的拖拽样式(拖拽不影响选中 + doAutoScroll)

(1)TestListView类继承自QListView(方法一)

  • TestListView.h文件:
class TestListView : public QListView
{
    Q_OBJECT

public:
    explicit TestListView(QWidget *parent = nullptr);

    bool isDraging() const {return IsDraging;}
    int offset() const {return 19;}
    int highlightedRow() const {return theHighlightedRow;}
    int dragRow() const {return theDragRow;}
    static QString myMimeType() { return QStringLiteral("TestListView/text-icon"); }

protected:
    void dragEnterEvent(QDragEnterEvent *event) override;
    void dragLeaveEvent(QDragLeaveEvent *event) override;
    void dragMoveEvent(QDragMoveEvent *event) override;
    void dropEvent(QDropEvent *event) override;
    void startDrag(Qt::DropActions supportedActions) override;

private:
    bool IsDraging = false;
    int theHighlightedRow = -2;
    int oldHighlightedRow = -2;
    int theDragRow = -1;
    int theInsertRow = -1;
};
  • TestListView.c文件:
TestListView::TestListView(QWidget *parent) :
    QListView(parent)
{
//    setMouseTracking(true);
    setDragEnabled(true);
    setAcceptDrops(true);
    //setDropIndicatorShown(false);
    setEditTriggers(QAbstractItemView::NoEditTriggers);
}

void TestListView::dragEnterEvent(QDragEnterEvent *event)
{
    TestListView *source = qobject_cast<TestListView *>(event->source());
    if (source && source == this) {
        IsDraging = true;  //IsDraging(标志位)判断是否正在拖拽
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

void TestListView::dragLeaveEvent(QDragLeaveEvent *event)
{
    oldHighlightedRow = theHighlightedRow;
    theHighlightedRow = -2;

    //之前QListWidget用的是update(QRect),这里用的是update(QModelIndex),当然这里也可以使用update(QRect),只是想换一种方法而已
    update(model()->index(oldHighlightedRow, 0));
    update(model()->index(oldHighlightedRow + 1, 0));

    IsDraging = false;

    theInsertRow = -1;
    event->accept();
}

void TestListView::dragMoveEvent(QDragMoveEvent *event)
{
    TestListView *source = qobject_cast<TestListView *>(event->source());
    if (source && source == this) {

        oldHighlightedRow = theHighlightedRow;
        theHighlightedRow = indexAt(event->pos() - QPoint(0, offset())).row();

        //offset() = 19 = 40 / 2 - 1,其中40是行高
        if(event->pos().y() >= offset()){

            if(oldHighlightedRow != theHighlightedRow){
                //刷新旧区域使dropIndicator消失
                update(model()->index(oldHighlightedRow, 0));
                update(model()->index(oldHighlightedRow + 1, 0));

                //刷新新区域使dropIndicator显示
                update(model()->index(theHighlightedRow, 0));
                update(model()->index(theHighlightedRow + 1, 0));
            }else{
                update(model()->index(theHighlightedRow, 0));
                update(model()->index(theHighlightedRow + 1, 0));
            }

            theInsertRow = theHighlightedRow + 1;
        }else{
            theHighlightedRow = -1;
            update(model()->index(0, 0));
            update(model()->index(1, 0));
            theInsertRow = 0;
        }

        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

void TestListView::dropEvent(QDropEvent *event)
{
    TestListView *source = qobject_cast<TestListView *>(event->source());
    if (source && source == this){

        IsDraging = false;  //完成拖拽

        oldHighlightedRow = theHighlightedRow;
        theHighlightedRow = -2;

        //刷新以使dropIndicator消失
        update(model()->index(oldHighlightedRow, 0));
        update(model()->index(oldHighlightedRow + 1, 0));

        if(theInsertRow == theDragRow || theInsertRow == theDragRow + 1) return;

        //这里我像QListWidget那样调用父类dropEvent(event)发现不起作用(原因尚不明),没办法,只能删除旧行,插入新行
        //if(theSelectedRow == theDragRow){
            //QListView::dropEvent(event);
            //return;
        //}

//[1]从event->mimeData()取出拖拽数据
        QString text;
        QIcon icon;
        QByteArray itemData = event->mimeData()->data(myMimeType());
        QDataStream dataStream(&itemData, QIODevice::ReadOnly);
        dataStream >> text >> icon;
//[1]

        model()->insertRow(theInsertRow);  //插入新行

        QStandardItemModel *listModel = qobject_cast<QStandardItemModel *>(model());
        listModel->setItem(theInsertRow, 0, new QStandardItem(icon, text));

        setCurrentIndex(model()->index(theInsertRow, 0));  //插入行保持选中状态

        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

//使用startDrag()则不需要判断拖拽距离
void TestListView::startDrag(Qt::DropActions)
{
    theDragRow = currentIndex().row();

    QStandardItemModel *listModel = qobject_cast<QStandardItemModel *>(model());
    QStandardItem *theDragItem = listModel->item(theDragRow);

//[1]把拖拽数据放在QMimeData容器中
        QString text = theDragItem->text();
        QIcon icon = theDragItem->icon();
        QByteArray itemData;
        QDataStream dataStream(&itemData, QIODevice::WriteOnly);
        dataStream << text << icon;

        QMimeData *mimeData = new QMimeData;
        mimeData->setData(myMimeType(), itemData);
//[1]

//[2]设置拖拽时的缩略图
        thumbnail *DragImage = new thumbnail(this);
        DragImage->setupthumbnail(icon, text);
        //DragImage->setIconSize(18);  //default:20
        QPixmap pixmap = DragImage->grab();

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);
        drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
//[2]

    //删除的行需要根据theInsertRow和theDragRow的大小关系来判断(这个也是我根据实际情况测试发现的)
    if(drag->exec(Qt::MoveAction) == Qt::MoveAction){
        int theRemoveRow = -1;
        if(theInsertRow < theDragRow) theRemoveRow = theDragRow + 1;
        else theRemoveRow = theDragRow;
        model()->removeRow(theRemoveRow);
    }
}

(2)TestListView类继承自QListView(方法二)

  • TestListView.h文件:
class TestListView : public QListView
{
    Q_OBJECT

public:
    explicit TestListView(QWidget *parent = nullptr);

    bool isDraging() const {return IsDraging;}
    int offset() const {return 19;}
    int highlightedRow() const {return theHighlightedRow;}
    int dragRow() const {return theDragRow;}
    static QString myMimeType() { return QStringLiteral("TestListView/text-icon-icon_hover"); }

protected:
    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void dragEnterEvent(QDragEnterEvent *event) override;
    void dragLeaveEvent(QDragLeaveEvent *event) override;
    void dragMoveEvent(QDragMoveEvent *event) override;
    void dropEvent(QDropEvent *event) override;

private:
    QPoint startPos;
    bool IsDraging = false;
    int theHighlightedRow = -2;
    int oldHighlightedRow = -2;
    int theDragRow = -1;
    int theInsertRow = -1;

};
  • TestListView.c文件:
TestListView::TestListView(QWidget *parent) :
    QListView(parent)
{
//    setMouseTracking(true);
//    setDragEnabled(true);
    setAcceptDrops(true);
    //setDropIndicatorShown(false);
}

//记录拖拽初始位置
void TestListView::mousePressEvent(QMouseEvent *event)
{
    QListView::mousePressEvent(event);
    if(event->buttons() & Qt::LeftButton){
        startPos = event->pos();
    }
}

void TestListView::mouseMoveEvent(QMouseEvent *event)
{
    if(event->buttons() & Qt::LeftButton){
        if((event->pos() - startPos).manhattanLength() < QApplication::startDragDistance()) return;

        QModelIndex theDragIndex = indexAt(startPos);
        theDragRow = theDragIndex.row();

        QStandardItemModel *listModel = qobject_cast<QStandardItemModel *>(model());
        QStandardItem *theDragItem = listModel->item(theDragRow);

//[1]把拖拽数据放在QMimeData容器中
        QString text = theDragItem->text();
        QIcon icon = theDragItem->icon();
        QByteArray itemData;
        QDataStream dataStream(&itemData, QIODevice::WriteOnly);
        dataStream << text << icon;

        QMimeData *mimeData = new QMimeData;
        mimeData->setData(myMimeType(), itemData);
//[1]

//[2]设置拖拽时的缩略图
        thumbnail *DragImage = new thumbnail(this);
        DragImage->setupthumbnail(icon, text);
        //DragImage->setIconSize(18);  //default:20
        QPixmap pixmap = DragImage->grab();

        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(pixmap);
        drag->setHotSpot(QPoint(pixmap.width() / 2, pixmap.height() / 2));
//[2]

        //删除的行需要根据theInsertRow和theDragRow的大小关系来判断(这个也是我根据实际情况测试发现的)
        if(drag->exec(Qt::MoveAction) == Qt::MoveAction){
            int theRemoveRow = -1;
            if(theInsertRow < theDragRow) theRemoveRow = theDragRow + 1;
            else theRemoveRow = theDragRow;
            model()->removeRow(theRemoveRow);
        }
    }
}

void TestListView::dragEnterEvent(QDragEnterEvent *event)
{
    TestListView *source = qobject_cast<TestListView *>(event->source());
    if (source && source == this) {
        IsDraging = true;  //IsDraging(标志位)判断是否正在拖拽
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

void TestListView::dragLeaveEvent(QDragLeaveEvent *event)
{
    oldHighlightedRow = theHighlightedRow;
    theHighlightedRow = -2;

    //之前QListWidget用的是update(QRect),这里用的是update(QModelIndex),当然这里也可以使用update(QRect),只是想换一种方法而已
    update(model()->index(oldHighlightedRow, 0));
    update(model()->index(oldHighlightedRow + 1, 0));

    IsDraging = false;

    theInsertRow = -1;
    event->accept();
}

void TestListView::dragMoveEvent(QDragMoveEvent *event)
{
    TestListView *source = qobject_cast<TestListView *>(event->source());
    if (source && source == this) {

        oldHighlightedRow = theHighlightedRow;
        theHighlightedRow = indexAt(event->pos() - QPoint(0, offset())).row();

        //offset() = 19 = 40 / 2 - 1,其中40是行高
        if(event->pos().y() >= offset()){

            if(oldHighlightedRow != theHighlightedRow){
                //刷新旧区域使dropIndicator消失
                update(model()->index(oldHighlightedRow, 0));
                update(model()->index(oldHighlightedRow + 1, 0));

                //刷新新区域使dropIndicator显示
                update(model()->index(theHighlightedRow, 0));
                update(model()->index(theHighlightedRow + 1, 0));
            }else{
                update(model()->index(theHighlightedRow, 0));
                update(model()->index(theHighlightedRow + 1, 0));
            }

            theInsertRow = theHighlightedRow + 1;
        }else{
            theHighlightedRow = -1;
            update(model()->index(0, 0));
            update(model()->index(1, 0));
            theInsertRow = 0;
        }

        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

void TestListView::dropEvent(QDropEvent *event)
{
    TestListView *source = qobject_cast<TestListView *>(event->source());
    if (source && source == this){

        IsDraging = false;  //完成拖拽

        oldHighlightedRow = theHighlightedRow;
        theHighlightedRow = -2;

        //刷新以使dropIndicator消失
        update(model()->index(oldHighlightedRow, 0));
        update(model()->index(oldHighlightedRow + 1, 0));

        if(theInsertRow == theDragRow || theInsertRow == theDragRow + 1) return;

        //这里我像QListWidget那样调用父类dropEvent(event)发现不起作用(原因尚不明),没办法,只能删除旧行,插入新行
        //if(theSelectedRow == theDragRow){
            //QListView::dropEvent(event);
            //return;
        //}

//[1]从event->mimeData()取出拖拽数据
        QString text;
        QIcon icon;
        QByteArray itemData = event->mimeData()->data(myMimeType());
        QDataStream dataStream(&itemData, QIODevice::ReadOnly);
        dataStream >> text >> icon;
//[1]

        model()->insertRow(theInsertRow);  //插入新行

        QStandardItemModel *listModel = qobject_cast<QStandardItemModel *>(model());
        listModel->setItem(theInsertRow, 0, new QStandardItem(icon, text));

        setCurrentIndex(model()->index(theInsertRow, 0));  //插入行保持选中状态

        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

(3)TestItemDelegate类继承自QStyledItemDelegate,主要是为了绘制dropIndicator。图示为dropIndicator组成:

在这里插入图片描述

  • TestItemDelegate.h文件:
#define POLYGON 4   //等腰三角形直角边长
#define WIDTH 1     //分隔符粗细的一半

class TestItemDelegate : public QStyledItemDelegate
{
    Q_OBJECT
public:
    TestItemDelegate(QObject *parent = nullptr);

protected:
    void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
};
  • TestItemDelegate.c文件:
TestItemDelegate::TestItemDelegate(QObject *parent)
    : QStyledItemDelegate(parent)
{
}

void TestItemDelegate::paint(QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index) const
{
    TestListView *dragView = qobject_cast<TestListView *>(option.styleObject);
    bool isDraging = dragView->isDraging();

    QRect rect = option.rect;

    painter->setRenderHint(QPainter::Antialiasing, true);
    painter->setPen(Qt::NoPen);

    if(option.state & (QStyle::State_MouseOver | QStyle::State_Selected)){

        if(option.state & QStyle::State_MouseOver){
        }
        if(option.state & QStyle::State_Selected){
            painter->setBrush(QColor(180, 0, 0));
            painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), 4, rect.height());

            painter->setBrush(QColor(230, 231, 234));
            painter->drawRect(rect.topLeft().x() + 4, rect.topLeft().y(), rect.width() - 4, rect.height());

        }
    }

//begin drag
    if(isDraging){
        int theDragRow = dragView->dragRow();
        int UpRow = dragView->highlightedRow();
        int DownRow = UpRow + 1;
        int rowCount = dragView->model()->rowCount() - 1;

//绘制DropIndicator
        if(index.row() == UpRow && index.row() != theDragRow - 1 && index.row() != theDragRow){
            painter->setBrush(QColor(66, 133, 244));

            if(UpRow == rowCount){
                //到达尾部,三角形向上移动一个WIDTH的距离,以使分隔符宽度*2
                QPolygon trianglePolygon_bottomLeft;
                trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (POLYGON + WIDTH) + 1 - WIDTH);
                trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - WIDTH + 1 - WIDTH);
                trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x() + POLYGON, rect.bottomLeft().y() - WIDTH + 1 - WIDTH);

                QPolygon trianglePolygon_bottomRight;
                trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - (POLYGON + WIDTH) + 1 - WIDTH);
                trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - WIDTH + 1 - WIDTH);
                trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() - POLYGON + 1, rect.bottomRight().y() - WIDTH + 1 - WIDTH);

                painter->drawRect(rect.bottomLeft().x(), rect.bottomLeft().y() - 2 * WIDTH + 1, rect.width(), 2 * WIDTH);  //rect
                painter->drawPolygon(trianglePolygon_bottomLeft);
                painter->drawPolygon(trianglePolygon_bottomRight);
            }
            else {
                //正常情况,组成上半部分(+1是根据实际情况修正)
                QPolygon trianglePolygon_bottomLeft;
                trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (POLYGON + WIDTH) + 1);
                trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - WIDTH + 1);
                trianglePolygon_bottomLeft << QPoint(rect.bottomLeft().x() + POLYGON, rect.bottomLeft().y() - WIDTH + 1);

                QPolygon trianglePolygon_bottomRight;
                trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - (POLYGON + WIDTH) + 1);
                trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() + 1, rect.bottomRight().y() - WIDTH + 1);
                trianglePolygon_bottomRight << QPoint(rect.bottomRight().x() - POLYGON + 1, rect.bottomRight().y() - WIDTH + 1);

                painter->drawRect(rect.bottomLeft().x(), rect.bottomLeft().y() - WIDTH + 1, rect.width(), WIDTH);  //rect
                painter->drawPolygon(trianglePolygon_bottomLeft);
                painter->drawPolygon(trianglePolygon_bottomRight);
            }
        }
        else if(index.row() == DownRow && index.row() != theDragRow + 1 && index.row() != theDragRow){
            painter->setBrush(QColor(66, 133, 244));

            if(DownRow == 0){
                //到达头部,三角形向下移动一个WIDTH的距离,以使分隔符宽度*2
                QPolygon trianglePolygon_topLeft;
                trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + (POLYGON + WIDTH) + WIDTH);
                trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + WIDTH + WIDTH);
                trianglePolygon_topLeft << QPoint(rect.topLeft().x() + POLYGON, rect.topLeft().y() + WIDTH + WIDTH);

                QPolygon trianglePolygon_topRight;
                trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + (POLYGON + WIDTH) + WIDTH);
                trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + WIDTH + WIDTH);
                trianglePolygon_topRight << QPoint(rect.topRight().x() - POLYGON + 1, rect.topRight().y() + WIDTH + WIDTH);

                painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), rect.width(), 2 * WIDTH);  //rect
                painter->drawPolygon(trianglePolygon_topLeft);
                painter->drawPolygon(trianglePolygon_topRight);
            }
            else{
                //正常情况,组成下半部分(+1是根据实际情况修正)
                QPolygon trianglePolygon_topLeft;
                trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + (POLYGON + WIDTH));
                trianglePolygon_topLeft << QPoint(rect.topLeft().x(), rect.topLeft().y() + WIDTH);
                trianglePolygon_topLeft << QPoint(rect.topLeft().x() + POLYGON, rect.topLeft().y() + WIDTH);

                QPolygon trianglePolygon_topRight;
                trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + (POLYGON + WIDTH));
                trianglePolygon_topRight << QPoint(rect.topRight().x() + 1, rect.topRight().y() + WIDTH);
                trianglePolygon_topRight << QPoint(rect.topRight().x() - POLYGON + 1, rect.topRight().y() + WIDTH);

                painter->drawRect(rect.topLeft().x(), rect.topLeft().y(), rect.width(), WIDTH);  //rect
                painter->drawPolygon(trianglePolygon_topLeft);
                painter->drawPolygon(trianglePolygon_topRight);
            }
        }
        QStyledItemDelegate::paint(painter, option, index);
        return;
    }
//end drag

    QStyledItemDelegate::paint(painter, option, index);
}

(4)使用TestListWidget和TestItemDelegate

  • 主窗口.h文件:
class test : public QWidget
{
    Q_OBJECT
public:
    explicit test(QWidget *parent = nullptr);

private:
    void initUi();
};
  • 主窗口.c文件:
test::test(QWidget *parent) : QWidget(parent)
{
    initUi();
}

void test::initUi()
{
    setFixedSize(250, 600);

    QStandardItemModel *listModel = new QStandardItemModel();
    listModel->setItem(0, 0, new QStandardItem(QIcon(":/listBar_Icon/1_hover.png"), "发现音乐"));
    listModel->setItem(1, 0, new QStandardItem(QIcon(":/listBar_Icon/2_hover.png"), "私人FM"));
    listModel->setItem(2, 0, new QStandardItem(QIcon(":/listBar_Icon/3_hover.png"), "朋友"));
    listModel->setItem(3, 0, new QStandardItem(QIcon(":/listBar_Icon/4_hover.png"), "MV"));
    listModel->setItem(4, 0, new QStandardItem(QIcon(":/listBar_Icon/5_hover.png"), "本地音乐"));
    listModel->setItem(5, 0, new QStandardItem(QIcon(":/listBar_Icon/6_hover.png"), "下载管理"));
    listModel->setItem(6, 0, new QStandardItem(QIcon(":/listBar_Icon/7_hover.png"), "我的音乐云盘"));
    listModel->setItem(7, 0, new QStandardItem(QIcon(":/listBar_Icon/8_hover.png"), "我的收藏"));

    TestListView *listView = new TestListView(this);
    listView->setIconSize(QSize(25, 25));
    listView->setFocusPolicy(Qt::NoFocus);  //这样可禁用tab键和上下方向键并且除去复选框
    listView->setFixedHeight(320);
    listView->setFont(QFont("宋体", 10, QFont::DemiBold));
    listView->setStyleSheet(
                //"*{outline:0px;}"  //除去复选框
                "QListView{background:rgb(245, 245, 247); border:0px; margin:0px 0px 0px 0px;}"
                "QListView::Item{height:40px; border:0px; padding-left:14px; color:rgba(200, 40, 40, 255);}"
                "QListView::Item:hover{color:rgba(40, 40, 200, 255); padding-left:14px;}"
                "QListView::Item:selected{color:rgba(40, 40, 200, 255); padding-left:15px;}"
                );

    TestItemDelegate *delegate = new TestItemDelegate();
    listView->setItemDelegate(delegate);
    listView->setModel(listModel);

    QVBoxLayout *layout = new QVBoxLayout(this);
    layout->setSpacing(0);
    layout->addWidget(listView);
    layout->setContentsMargins(0, 0, 0, 0);
    setLayout(layout);
}

如果想要接触更多关于拖拽的代码,在Qt例程中搜索“drag”。推荐看一下例程puzzle的两种实现方法(一种是继承QListWidget,另一种是QListView + 继承QAbstractListModel)。
在这里插入图片描述

环境配置 :MinGW + QT 5.12

你可能感兴趣的:(Qt,学习笔记,QListView,拖拽,drag,drop,自定义)