欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Qt實現(xiàn)拖拽功能圖文教程(支持拖放文件、拖放操作)

 更新時間:2023年11月28日 15:22:39   作者:林夕07  
這篇文章主要給大家介紹了關(guān)于Qt實現(xiàn)拖拽功能(支持拖放文件、拖放操作)的相關(guān)資料,Qt是一款多平臺的C++應(yīng)用程序開發(fā)框架,它的獨特之處在于可以快速開發(fā)出拖放式的開發(fā)桌面程序,需要的朋友可以參考下

拖放

拖放是在一個應(yīng)用程序內(nèi)或者多個應(yīng)用程序之間傳遞信息的一種直觀的現(xiàn)代操作方式。除了為剪貼板提供支持外,通常它還提供數(shù)據(jù)移動和復(fù)制的功能。

拖放操作包括兩個截然不同的動作:拖動和放下。Qt窗口部件可以作為拖動點(darg site)、放下點(drop site)或者同時作為拖動點和放下點。

Qt程序接受其他程序的拖拽

我們經(jīng)常將文本文件推拽到notepate++等類型文本編輯器軟件中。那么如何讓Qt程序也能夠支持這種操作呢?

我們需要在主窗口重新實現(xiàn)了來自父類的dragEnterEvent()和 dropEvent()函數(shù)。

protected:
    virtual void dragEnterEvent(QDragEnterEvent* event) override;
    virtual void dropEvent(QDropEvent* event) override;

在構(gòu)造函數(shù)中,創(chuàng)建了一個QTextEdit并且把它設(shè)置為中央窗口部件。默認(rèn)情況下,QTextEdit可以接受來自其他應(yīng)用程序文本的拖動,并且如果用戶在它上面放下一個文件,它將會把這個文件的內(nèi)容填充到QTextEdit部件中。

由于拖放事件是從子窗口部件傳遞給父窗口部件的,所以通過禁用QTextEdit上的放下操作以及啟用主窗口上的放下操作,就可以在整個MainWindow窗口中獲得放下事件。

#include <QMimeData>
#include <QTextStream>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    
 
    textEdit = new QTextEdit(this);
    setCentralWidget(textEdit);

    textEdit->setAcceptDrops(false);
    setAcceptDrops(true);

    setWindowTitle("Text Editor");
}

當(dāng)用戶把一個對象拖動到這個窗口部件上時,就會調(diào)用dragEnterEvent()。如果對這個事件調(diào)用acceptProposedAction(),就表明用戶可以在這個窗口部件上拖放對象。默認(rèn)情況下,窗口部件是不接受拖動的。Qt會自動改變光標(biāo)來向用戶說明這個窗口部件是不是有效的放下點。

這里,我們希望用戶拖動的只能是文件,而非其他類型的東西。為了實現(xiàn)這一點,我們可以檢查拖動的MIME類型。

MIME類型中的 text/uri-list 用于存儲一系列的統(tǒng)一資源標(biāo)識符(Universal Re-source Identifier ,URI),它們可以是文件名、統(tǒng)―資源定位器(Uniform Resource Locator , URL,如 HTTP或者FTP路徑),或者其他全局資源標(biāo)識符。標(biāo)準(zhǔn)的MIME類型是由國際因特網(wǎng)地址分配委員會(Internet Assigned Numbers Authority , IANA)定義的,它們由類型、子類型信息以及分隔兩者的斜線組·成。MME類通常由剪貼板和拖放系統(tǒng)使用,以識別不同類型的數(shù)據(jù)??梢詮南旅娴木W(wǎng)站得到正式的 MIME類型列表: http://www.iana.org/assignments/media-types/

void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    if(event->mimeData()->hasFormat("text/uri-list"))
    {
        event->acceptProposedAction();
    }
}

當(dāng)用戶在窗口部件上放下一個對象時,就會調(diào)用dropEvent()。.我們調(diào)用函數(shù)QMimeData::urls()來獲得QUrl列表。通常,用戶一次只拖動一個文件,但是通過拖動一個選擇區(qū)域來同時拖動多個文件也是可能的。如果要拖放的URL不止一個,或者要拖放的URL,不是一個本地文件名,則會立即返回到原調(diào)用處。
QWidget也提供 dragMoveEvent()和 dragLeaveEvent()函數(shù),但是在絕大多數(shù)應(yīng)用程序中并不需要重新實現(xiàn)它們。

void MainWindow::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if(urls.empty())
        return;

    QString fileName = urls.first().toLocalFile();
    if(fileName.isEmpty())
        return;

    if(ReadFile(fileName))
    {
        setWindowTitle(QString("%1-%2").arg(fileName).arg("Drag File"));
    }
}
bool MainWindow::ReadFile(const QString &filename)
{
    QFile file(filename);
    file.open(QIODevice::ReadOnly | QIODevice::Text | QIODevice::Truncate);
    if(false == file.isOpen())
    {
        return false;
    }
    QTextStream stream(&file);
    textEdit->insertPlainText(stream.readAll());
    file.flush();
    file.close();
    return true;
}

看看效果吧

部件/控件之間相互拖放

我們將實現(xiàn)類似于一個下圖的效果,但不需要向左向右的按鍵,通過拖拽目標(biāo)實現(xiàn)移動。

思路:創(chuàng)建一個支持拖拽的QListWidget子類ProjectListWidget,并且作為該界面的一個部件。

在ProjectListWidget類中需要重寫父類的五個事件,和一個私有方法以及一個坐標(biāo)記錄

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

private:
    QPoint startPos;

在構(gòu)造函數(shù)中,我們使列表框上的放下生效。

#include <QApplication>
#include <QDrag>
#include <QMimeData>
ProjectListWidget::ProjectListWidget(QWidget* parent)
    :QListWidget{parent}
{
    setAcceptDrops(true);
}

當(dāng)用戶按下鼠標(biāo)左鍵,就把鼠標(biāo)位置保存到statPos私有變量中。然后我們正常調(diào)用QListWidget 中mousePressEvent()。

void ProjectListWidget::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton)
    {
        startPos = event->pos();
    }
    QListWidget::mousePressEvent(event);
}

當(dāng)用戶按住鼠標(biāo)左鍵并移動鼠標(biāo)光標(biāo)時,就認(rèn)為這是一個拖動的開始。我們計算當(dāng)前鼠標(biāo)位置和原來鼠標(biāo)左鍵按下的點之間的距離-—這個“曼哈頓長度”(Manhattan Length)其實是從坐標(biāo)原點到該矢量長度快速計算的近似值。如果這個距離大于或等于QApplication推薦的拖動起始距離值(通常是4個像素),那么就調(diào)用私有函數(shù)performDrag()以啟動拖動操作。這可以避免用戶因為手握鼠標(biāo)抖動而產(chǎn)生拖動。

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

perfomDrag()中,創(chuàng)建了一個類型為QDrag的對象,并且把this作為它的父對象。這個QDrag對象將數(shù)據(jù)存儲在QMimeData對象中。在這個實例中,我們利用QMineData::setText()提供了作為text/plain字符串的數(shù)據(jù)。QMimeData 提供了一些可用于處理最常用拖放類型(諸如圖像、URL、顏色,等等)的函數(shù),同時也可以處理任意由QByteArrays表宗的MiME類型。QDrag::setPiximap()調(diào)用則可以在拖放發(fā)生時使圖標(biāo)隨光標(biāo)移動。

QDrag::exec()調(diào)用啟動并執(zhí)行拖動操作;直到用戶放下或取消此次拖動操作才會停止。它把所有支持的“拖放動作"(如 Qi: : CopyAction, Qt : : MoveAction和 Qt: : LinkAction)的組合作為其參數(shù),并且返回被執(zhí)行的拖放動作(如果沒有執(zhí)行任何動作,則返回Qt: IgnoreAction)。至于執(zhí)行的是哪`個動作,取決于放下發(fā)生時源窗口部件是否允許、目標(biāo)是否支持及按下了哪些組合鍵。在 exec()調(diào)用后,Qt擁有拖動對象的所有權(quán)并且可以在不需要它的時候刪除它。

void ProjectListWidget::performDrag()
{
    if(QListWidgetItem* item = currentItem();
        nullptr != item)
    {
        QMimeData* mineData = new QMimeData();
        mineData->setText(item->text());

        QDrag* drag = new QDrag(this);
        drag->setMimeData(mineData);
        drag->setPixmap(QPixmap(":/icon.jpg"));

        if(drag->exec(Qt::MoveAction) == Qt::MoveAction)
        {
            delete item;
            item = nullptr;
        }
    }
}	

ProjectListWidget窗口部件不僅能發(fā)起拖動,還可以接收同一個應(yīng)用程序中來自另外一個ProjectListWidget部件的拖動。如果窗口部件是同個應(yīng)用程序的一部分,QDragEnterEvent::source()返回一個啟動這個拖動的窗口部件的指針;否則,返回一個空指針值。

void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    ProjectListWidget* source = reinterpret_cast<ProjectListWidget*>(event->source());
    if(nullptr != source && source != this)
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

dragMoveEvent()中的代碼與dragEnterEvent()中編寫的代碼基本相同。因為需要重寫QListWidget的函數(shù)實現(xiàn)(實際上是 QAbstractItemView的函數(shù)實現(xiàn))。

void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event)
{
    ProjectListWidget* source = reinterpret_cast<ProjectListWidget*>(event->source());
    if(nullptr != source && source != this)
    {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

在dropEvent()中,我們使用QMimeData::text()重新找回拖動的文本并隨文本創(chuàng)建一個拖動項。還需要將事件作為“移動動作”來接受,從而告訴源窗口部件現(xiàn)在可以刪除原來的拖動項了。

void ProjectListWidget::dropEvent(QDropEvent *event)
{
    ProjectListWidget* source = reinterpret_cast<ProjectListWidget*>(event->source());
    if(nullptr != source && source != this)
    {
        addItem(event->mimeData()->text());
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}

效果如下

總結(jié)

拖放是在應(yīng)用程序之間傳遞數(shù)據(jù)的有力機制。但是在某些情況下;,有可能在執(zhí)行拖放時并未使用Qt的拖放工具。如果只是想在一個應(yīng)用程序的窗口部件中移動數(shù)據(jù),通常只要重新實現(xiàn)mousePressEvent()和 mouseReleaseEvent()函數(shù)就可以了。

到此這篇關(guān)于Qt實現(xiàn)拖拽功能(支持拖放文件、拖放操作)的文章就介紹到這了,更多相關(guān)Qt實現(xiàn)拖拽功能內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論