9-1 支持托拽功能(Enabling Drag and Drop)

本文详细介绍了Qt中实现拖拽功能的方法,包括如何使控件支持拖拽、响应拖拽事件以及处理拖拽数据等。并通过两个实例展示了不同场景下的应用。
 
9-1 支持托拽功能(Enabling Drag and Drop)
名次解释:
Drag :拖动,拉动,计算机中就是用鼠标拖动的过程
Drop :滴下,落下,松开,计算机中就是鼠标拖动到某一个位置后放开左键的过程,Drag后总会Drop的。
Drag 和Drop是两个完全不同的动作。Qt中的控件可以作为拖动(drag)的地点,也可以作为松开(drop)的地点,或者同时作为拖动和松开的地点。
第一个例子用来说明一个Qt应用程序接受 另一个程序触发的拖动事件。Qt应用程序为一个QTextEdit为中央控件的窗口。当用户从桌面或者一个文件浏览器中拖动一个文本文件到Qt程序时,程序把文件显示在QTextEdit控件中。
下面是主窗口的定义
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow();
protected:
    void dragEnterEvent(QDragEnterEvent *event);
    void dropEvent(QDropEvent *event);
private:
    bool readFile(const QString &fileName);
    QTextEdit *textEdit;
};
 
在MainWindow类中,重新实现了QWidget的函数dragEnterEvent()和dropEvent()。由于这个例子主要用来显示托拽,主窗口的很多其他功能都省略了。
 
MainWindow::MainWindow()
{
    textEdit = new QTextEdit;
    setCentralWidget(textEdit);
    textEdit->setAcceptDrops(false);
    setAcceptDrops(true);
    setWindowTitle(tr("Text Editor"));
}
 
在构造函数中,我们创建了一个QTextEdit控件,并设置为中央控件。缺省情况下,QTextEdit接受来自其他应用程序托拽来的文本,把文件名显示出来。由于drop事件是由子控件向父控件传播的,通过禁止QTextEdit控件的drop,允许主窗口得到drop事件,我们就得到了MainWindow的drop事件。
void MainWindow::dragEnterEvent(QDragEnterEvent *event)
{
    if (event->mimeData()->hasFormat("text/uri-list"))
        event->acceptProposedAction();
}
 
任何时候用户拖动一个对象到一个控件上,函数dragEnterEvent()都会被调用。如果在这个事件处理函数中调用函数acceptProposeAction(),说明我们允许用户这个对象托拽到这个控件上。通常,控件不允许drag。Qt会自动改变光标状态指示用户当前的控件是否是一个合法的drop地点。
在这里我们只允许用户drag一个文本文件,因此,我们检查这个这个dravg的MIME类型。MIME类型text/uri-list用来保存URL的一个地址列表,可以使一个文本文件,也可以是其他URL(HTTP或者FTP路径),也可以是其他的全局资源标识。标准的MIME类型由IANA(Internet Assigned Numbers Authority)定义,由一个类型名/子类型名组成。MIME类型用于在剪贴板和托拽时区别不同的数据类型,MIME类型列表可以点击访问http://www.iana.org/assignments/media-types/得到
void MainWindow::dropEvent(QDropEvent *event)
{
    QList<QUrl> urls = event->mimeData()->urls();
    if (urls.isEmpty())
       return;
    QString fileName = urls.first().toLocalFile();
    if (fileName.isEmpty())
        return;
    if (readFile(fileName))
        setWindowTitle(tr("%1 - %2").arg(fileName)
                                    .arg(tr("Drag File")));
}
 
当用户drop一个对象到控件上,函数dropEvent()就会调用。QMineData::urls()得到一个QUrls列表。通常用户一次只会托拽一个文件,但是托拽多个文件也是允许的。如果用户拖动了多个文件或者多个URLs,程序立即返回。
QWidget 还提供了dragMoveEvent()和dragLeaveEvent(),但是对于大多数应用程序,这两个函数都不需要重写。
第二个例子来说明怎样进行drag,怎样接受drop。我们将会创建一个QListWidget子类,这个控件可以接受drag和drop。并把它作为Project Choonser 程序的一个组件,如9.1所示:
Figure 9.1. The Project Chooser application
Project Chooser 程序由两个名字列表控件组成。每一个列表控件表示一个项目。用户可以drag和drop列表中的名字,把一个名字从一个项目移到另一个项目中。
在列表控件的子类中实现了drag和drop部分的代码。下面是类的定义:
class ProjectListWidget : public QListWidget
{
    Q_OBJECT
public:
    ProjectListWidget(QWidget *parent = 0);
protected:
    void mousePressEvent(QMouseEvent *event);
    void mouseMoveEvent(QMouseEvent *event);
    void dragEnterEvent(QDragEnterEvent *event);
    void dragMoveEvent(QDragMoveEvent *event);
    void dropEvent(QDropEvent *event);
private:
    void startDrag();
    QPoint startPos;
};
 
ProjectListWidget::ProjectListWidget(QWidget *parent)
    : QListWidget(parent)
{
    setAcceptDrops(true);
}
在构造函数中,我们让列表控件允许drop。
 
void ProjectListWidget::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton)
        startPos = event->pos();
    QListWidget::mousePressEvent(event);
}
当用户点击了鼠标左键时,我们把鼠标位置保存在startPos变量中。然后调用基类的mousePressEvent(),使列表控件的鼠标点击事件进入程序的消息循环。
 
void ProjectListWidget::mouseMoveEvent(QMouseEvent *event)
{
    if (event->buttons() & Qt::LeftButton) {
        int distance = (event->pos() - startPos).manhattanLength();
        if (distance >= QApplication::startDragDistance())
            startDrag();
    }
    QListWidget::mouseMoveEvent(event);
}
如果用户点中鼠标左边同时移动鼠标,把这个过程认为是一个drag。计算当前鼠标位置和鼠标第一次点击的位置之间的距离,如果这个距离大于QApplication认定的拖动的最小距离(通常为四个象素),调用私有函数startDrag()开始拖动。通过判断距离可以避免因为用户手抖动引起的误操作。
 
void ProjectListWidget::startDrag()
{
    QListWidgetItem *item = currentItem();
    if (item) {
        QMimeData *mimeData = new QMimeData;
        mimeData->setText(item->text());
        QDrag *drag = new QDrag(this);
        drag->setMimeData(mimeData);
        drag->setPixmap(QPixmap(":/images/person.png"));
        if (drag->start(Qt::MoveAction) == Qt::MoveAction)
            delete item;
    }
}
在startDrag()中,我们创建一个QDrag对象,父类为当前的列表控件ProjectListWidget。QDrag对象保存量一个QMimeData对象中的数据。在这个例子中,我们只是使用QMimeData::setText()保存了一个文本。QMimeData提供了很多函数处理经常用到的数据类型(如图像,URLs,颜色等等),对于用QByteArrays表示的任意MIME类型都可以处理。当drag发生时,函数QDrag::setPixmap()设置了跟随鼠标的图标。
调用QDrag::start()开始拖动,直到用户开始drop或者取消了拖动。函数的参数为多个“drag actions”的组合(Qt::CopyAction, Qt::MoveAction, Qt::LinkAction)。返回值为执行拖动的“drag action”,如果没有执行拖动的操作,则返回Qt::IgnoreAction。具体执行那个action取决于原控件允许的操作,目标控件允许的操作和是否有附加键同时按下。调用start()后,Qt拥有被拖动的对象,在不需要时将其删除。
void ProjectListWidget::dragEnterEvent(QDragEnterEvent *event)
{
    ProjectListWidget *source =
            qobject_cast<ProjectListWidget *>(event->source());
    if (source && source != this) {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}
ProjectListWidget 不但可以产生drag,还可以接受来自程序中其他ProjectListWidget控件的drag。如果drag发生在同一个应用程序中,QDragEnterEvent::source()得到产生drag控件的指针。如果不是一个程序,则返回空指针。qobject_cast<T>()可以确保拖动来自与一个ProjectListWidget控件。如果一切正常,则调用accept()通知Qt接受这个action作为一个移动操作
 
void ProjectListWidget::dragMoveEvent(QDragMoveEvent *event)
{
    ProjectListWidget *source =
            qobject_cast<ProjectListWidget *>(event->source());
    if (source && source != this) {
        event->setDropAction(Qt::MoveAction);
        event->accept();
    }
}
函数dragMoveEvent()和dragEnterEvent()很相似。
 
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();
    }
}
在dropEvent()中,用QMimeData::text()得到拖动的文本,并用这个文本创建一个列表项目。我们还需要调用event->setDropAction(Qt::MoveAction),用参数Qt::MoveAction通知源控件可以删除原来拖动的项目。
在程序间需要转移数据时,托拽是一个非常有用的机制。但是有时候不用托拽机制也可以实现托拽同样的操作。如果我们只是想在同一个控件中移动数据,只需要重写mousePressEvent()和mouseReleaseEvent()就可以。
 
 
### RuoYI-Vue-Plus Drag-and-Drop Report Component Documentation and Usage Examples #### Introduction to the Drag-and-Drop Report Feature The drag-and-drop report feature within RuoYI-Vue-Plus allows users to create complex reports through an intuitive interface without needing extensive coding knowledge. This tool simplifies data visualization by enabling developers or business analysts to design, customize, and manage various types of charts directly via a graphical user interface[^1]. #### Key Features Supported - **Draggable Components**: Users can easily add different chart components (such as bar graphs, line plots, pie charts) into designated areas on the canvas. - **Real-Time Preview**: Instantly see changes applied during configuration adjustments before finalizing designs. - **Data Source Binding**: Connect multiple datasets from diverse origins seamlessly with minimal setup effort required. #### Basic Setup Guide for Developers To integrate this functionality effectively: Install necessary dependencies using npm: ```bash npm install ruoyi-vue-plus --save ``` Import specific modules needed in your Vue project file: ```javascript import { defineComponent } from &#39;vue&#39;; import RuoyiReportBuilder from &#39;@ruoyi/report-builder&#39;; export default defineComponent({ name: "App", components: { RuoyiReportBuilder, }, }); ``` Use `<RuoyiReportBuilder />` tag inside template section where you want it displayed: ```html <template> <div id="app"> <!-- Other elements --> <RuoyiReportBuilder /> <!-- More content here --> </div> </template> ``` #### Advanced Configuration Options Available For more advanced scenarios such as custom styling rules or event handling mechanisms, refer to official documentation provided alongside source code repository which includes comprehensive API references covering all aspects related to customization possibilities offered by this powerful reporting solution[^2]. --related questions-- 1. How does one bind external APIs as data sources when building reports? 2. What are some best practices while designing interactive dashboards utilizing these tools? 3. Can animations be added between transitions of visualizations created through drag-and-drop interfaces? 4. Is there support available for exporting generated visuals into formats like PDFs or images programmatically? [^1]: Placeholder reference indicating information about features supported by RuoYI-Vue-Plus&#39;s drag-and-drop report builder. [^2]: Hypothetical citation pointing towards detailed instructions regarding deeper integration options not covered above.
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值