首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

Qt 學習之路(53):拖放技術進階——兩列表間數據互拖實現

     編輯:關於C語言

項目背景

在很多項目中,需要在兩個列表之間通過拖放移動數據。本文基於《C++ GUI Programming with Qt 4》示例,實現一個自定義 ProjectListWidget,支持列表項在兩個實例間雙向拖放移動。

類設計:ProjectListWidget

class ProjectListWidget : public QListWidget {
    Q_OBJECT
public:
    explicit ProjectListWidget(QWidget *parent = nullptr);

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

private:
    void performDrag();
    QPoint startPos;
};

關鍵實現細節

1. 構造函數:啟用拖放接收


ProjectListWidget::ProjectListWidget(QWidget *parent)
    : QListWidget(parent) {
    setAcceptDrops(true); // 關鍵:默認不接受拖放事件
}

2. 鼠標按下:記錄起始位置


void ProjectListWidget::mousePressEvent(QMouseEvent *event) {
    if (event->button() == Qt::LeftButton)
        startPos = event->pos();
    QListWidget::mousePressEvent(event); // 必須調用基類實現
}

3. 鼠標移動:判斷是否啟動拖放


void ProjectListWidget::mouseMoveEvent(QMouseEvent *event) {
    if (event->buttons() & Qt::LeftButton) {
        int distance = (event->pos() - startPos).manhattanLength();
        if (distance >= QApplication::startDragDistance()) // 通常 4px
            performDrag();
    }
    QListWidget::mouseMoveEvent(event);
}

曼哈頓距離:兩點坐標差向量的 L1 范數,這裡用於過濾手抖導致的微小移動。

4. 執行拖放:performDrag()


void ProjectListWidget::performDrag() {
    QListWidgetItem *item = currentItem();
    if (!item) return;

    QMimeData *mimeData = new QMimeData;
    mimeData->setText(item->text()); // 存儲文本數據

    QDrag *drag = new QDrag(this);
    drag->setMimeData(mimeData);
    drag->setPixmap(QPixmap(":/images/person.png")); // 拖動時的鼠標圖標

    // 執行移動操作,成功則刪除源項目
    if (drag->exec(Qt::MoveAction) == Qt::MoveAction)
        delete item;
}

QDrag::exec() 會阻塞直到拖放結束,返回實際執行的動作(MoveAction/CopyAction/LinkAction/IgnoreAction)。

5. 接收拖放事件:三個關鍵事件處理器

核心邏輯:只接受來自同類型、非自身的組件數據,並設置為移動動作。


// dragEnterEvent / dragMoveEvent 邏輯相同
void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event) {
    ProjectListWidget *source = qobject_cast<ProjectListWidget*>(event->source());
    if (source && source != this) {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

void ProjectListWidget::dropEvent(QDropEvent *event) {
    ProjectListWidget *source = qobject_cast<ProjectListWidget*>(event->source());
    if (source && source != this) {
        addItem(event->mimeData()->text()); // 取出文本添加到當前列表
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

總結

通過重寫鼠標與拖放事件,結合 QMimeData 傳遞數據、QDrag 管理拖放會話,實現了列表項雙向移動。對於同一組件內部排序等不涉及跨組件數據傳遞的場景,僅處理鼠標事件可能更輕量。

本文出自 “豆子空間” 博客,原文地址:https://devbean.blog.51cto.com/448512/286796

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved