Control study -> Drag拖放数据操作示例

本文介绍了一个关于按键事件和拖放操作的例子,包括如何在Windows窗体中使用DragEnter、DragDrop、DragLeave、DragOver及QueryContinueDrag事件。通过实例展示了如何实现将按钮文本拖动到文本框的功能。
2005年10月09日 00:15:00

(一).功能描述

涉及到DragEnter DragDrop DragLeave DragOver QueryContinueDrag事件用法的一个例子

(二).图片示例

演示将按钮Button1.Text文本"Button"拖动到TextBox中

拖动前:

拖动后:

(三).代码

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

namespace 拖放数据操作_按键事件_
{
/// >summary<
/// Form1 的摘要说明。
/// >/summary<
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.Windows.Forms.TextBox textBox1;
/// >summary<
/// 必需的设计器变量。
/// >/summary<
private System.ComponentModel.Container components = null;

public Form1()
{
//
// Windows 窗体设计器支持所必需的
//
InitializeComponent();

//
// TODO: 在 InitializeComponent 调用后添加任何构造函数代码
//
}

/// >summary<
/// 清理所有正在使用的资源。
/// >/summary<
protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

#region Windows 窗体设计器生成的代码
/// >summary<
/// 设计器支持所需的方法 - 不要使用代码编辑器修改
/// 此方法的内容。
/// >/summary<
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(112, 72);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.QueryContinueDrag += new System.Windows.Forms.QueryContinueDragEventHandler(this.button1_QueryContinueDrag);
this.button1.MouseDown += new System.Windows.Forms.MouseEventHandler(this.button1_MouseDown);
//
// textBox1
//
this.textBox1.AccessibleDescription = "aaaaa";
this.textBox1.AccessibleName = "bbbbbb";
this.textBox1.AllowDrop = true;
this.textBox1.Location = new System.Drawing.Point(64, 160);
this.textBox1.Multiline = true;
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(168, 48);
this.textBox1.TabIndex = 1;
this.textBox1.Text = "";
this.textBox1.DragOver += new System.Windows.Forms.DragEventHandler(this.textBox1_DragOver);
this.textBox1.DragDrop += new System.Windows.Forms.DragEventHandler(this.textBox1_DragDrop);
this.textBox1.DragEnter += new System.Windows.Forms.DragEventHandler(this.textBox1_DragEnter);
this.textBox1.DragLeave += new System.EventHandler(this.textBox1_DragLeave);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(6, 14);
this.ClientSize = new System.Drawing.Size(292, 266);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
this.Text = "Form1";
this.ResumeLayout(false);

}
#endregion

/// >summary<
/// 应用程序的主入口点。
/// >/summary<
[STAThread]
static void Main()
{
Application.Run(new Form1());
}

private void button1_QueryContinueDrag(object sender, System.Windows.Forms.QueryContinueDragEventArgs e)
{
if(e.EscapePressed)
e.Action=DragAction.Cancel;
}

private void button1_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
button1.DoDragDrop(button1.Text,DragDropEffects.Copy|DragDropEffects.Move);
}

private void textBox1_DragEnter(object sender, System.Windows.Forms.DragEventArgs e)
{
if(e.Data.GetDataPresent(DataFormats.Text))
e.Effect=DragDropEffects.Copy;
else
e.Effect=DragDropEffects.None;
}

private void textBox1_DragDrop(object sender, System.Windows.Forms.DragEventArgs e)
{
//使用KeyState属性
if((e.KeyState&(1>>3))!=0)
{
if((e.AllowedEffect&DragDropEffects.Copy)!=0)
{
e.Effect=DragDropEffects.Copy;
textBox1.Text=e.Data.GetData(DataFormats.Text).ToString();
}
}
else
{
e.Effect=DragDropEffects.Move;
textBox1.Text=e.Data.GetData(DataFormats.Text).ToString();
}
}

private void textBox1_DragLeave(object sender, System.EventArgs e)
{
textBox1.Text="执行 DragLeave";
}

private void textBox1_DragOver(object sender, System.Windows.Forms.DragEventArgs e)
{
textBox1.Text="执行 DragOver";
}
}
}


(四). 示例下载

http://www.cnblogs.com/Files/ChengKing/拖放数据操作(按键事件).rar



Trackback: http://tb.blog.youkuaiyun.com/TrackBack.aspx?PostId=497607


<think> 问题分析: 错误信息显示:在MainWindow.cpp的第52行,试图访问不完整类型'QDropEvent'的成员。这是因为在包含头文件时,可能没有包含QDropEvent所需的完整定义。 原因: 在头文件中,可能只前向声明了QDropEvent,但没有包含相应的头文件。因此,在cpp文件中,当使用QDropEvent指针并尝试访问其成员时,编译器只知道存在QDropEvent这个类,但不知道其具体成员(即不完整类型)。 解决方案: 在MainWindow.cpp中,确保包含QDropEvent的头文件。通常,QDropEvent类在<QDropEvent>中定义,但根据Qt的模块,它可能包含在QtCore或QtGui中。实际上,QDropEvent属于QtGui模块。 因此,在MainWindow.cpp的顶部添加: #include <QDropEvent> 另外,检查是否在头文件(MainWindow.h)中包含了必要的头文件。但根据错误信息,问题出在cpp文件,所以很可能是在cpp文件中缺少包含。 修改后的代码: 在MainWindow.cpp中,添加对QDropEvent的包含。 注意:如果使用了Qt5,通常包含<QtGui>或直接包含<QDropEvent>。由于Qt将一些类分模块,而QDropEvent属于QtGui模块,所以确保在.pro文件中包含了QT += gui(默认是包含的)。 具体步骤: 1. 打开MainWindow.cpp文件。 2. 在文件顶部添加一行:#include <QDropEvent> 3. 重新编译。 如果问题仍然存在,检查是否有其他遗漏的包含。另外,错误提示的第52行是: if (event->mimeData()->hasFormat("application/x-dnditemdata")) 这里访问了event的mimeData(),所以还需要确保QMimeData的头文件也被包含。不过,QDropEvent的头文件应该已经包含了QMimeData的相关声明。如果还有问题,可以显式包含<QMimeData>。 然而,根据错误信息,主要问题在于QDropEvent是不完整类型,所以先解决这个。 另外,错误信息还提到“fix available”,可能是一些IDE(如Qt Creator)会提示自动修复,即添加包含。 修改后的代码部分: 在MainWindow.cpp的包含部分添加: ``` #include <QDropEvent> ``` 如果使用了QDataStream,还需要包含<QDataStream>,如果还没有包含的话。同样,QPixmap需要包含<QPixmap>,QPoint需要包含<QPoint>。但根据错误信息,当前主要问题是QDropEvent不完整。 所以,在MainWindow.cpp中添加: ``` #include <QDropEvent> #include <QMimeData> // 为了使用mimeData()返回的指针的成员,确保包含,但通常QDropEvent会包含它,但为了安全可以加上 #include <QDataStream> #include <QPixmap> #include <QPoint> ``` 但是,根据提供的代码片段,已经使用了QByteArray,QDataStream,QPixmap,QPoint等,所以这些头文件应该已经包含。如果没有,也需要添加。 总结:主要解决方法是包含QDropEvent的头文件。 修改后的dropEvent函数代码(仅添加头文件,函数体不变): 在cpp文件开头添加必要的包含。 如果问题解决了,那么就可以。如果还有其他错误,需要根据错误提示继续添加包含。 注意:在头文件中,如果只用到某个类的指针或引用,可以使用前向声明(如class QDropEvent;),这样就不必包含整个头文件,加快编译速度。但是在实现文件中(.cpp)中,如果访问该类的成员,就必须包含其头文件。 因此,在MainWindow.h中,可能只有前向声明而没有包含,所以在.cpp中必须包含。 示例: MainWindow.h: ``` #include <QMainWindow> // 前向声明 class QDropEvent; class MainWindow : public QMainWindow { Q_OBJECT public: // ... protected: void dropEvent(QDropEvent *event) override; // ... }; ``` MainWindow.cpp: ``` #include "MainWindow.h" #include <QDropEvent> // 必须包含,因为要访问QDropEvent的成员 #include <QMimeData> // 为了使用mimeData() // ... 其他包含 ``` 这样,在头文件中使用前向声明,在cpp中包含具体头文件,是推荐的做法。 因此,请确保在MainWindow.cpp中包含了<QDropEvent>。 §§相关问题§§: 1. 在C++中,什么是不完整类型(incomplete type)? 2. 为什么在头文件中使用前向声明(forward declaration)是一种好习惯? 3. 在Qt中,如何处理拖放事件(drag and drop events)? 4. 在重写Qt事件处理函数时,有哪些注意事项? </think> ### 问题分析与解决方案 您遇到的编译错误是因为**不完整类型(incomplete type)**问题。错误信息表明编译器只知道`QDropEvent`的前向声明,但无法访问其完整定义。 ### 解决方法 在`MainWindow.cpp`文件中添加必要的头文件包含: ```cpp // 在MainWindow.cpp中添加以下包含语句 #include <QDropEvent> // 解决QDropEvent不完整类型问题 #include <QMimeData> // 访问mimeData()需要 #include <QDrag> // 拖放操作支持 #include <QByteArray> // 二进制数据处理 #include <QDataStream> // 数据流操作 ``` ### 完整修复后的代码 ```cpp #include "MainWindow.h" #include <QDropEvent> // 关键修复 #include <QMimeData> #include <QDrag> #include <QByteArray> #include <QDataStream> void MainWindow::dropEvent(QDropEvent *event) { // 检查拖放数据格式... if (event->mimeData()->hasFormat("application/x-dnditemdata")) { QByteArray itemData = event->mimeData()->data("application/x-dnditemdata"); QDataStream dataStream(&itemData, QIODevice::ReadOnly); // 读取拖放数据... QPixmap pixmap; QPoint offset; dataStream >> pixmap >> offset; // 创建新按钮... DragButton *newBtn = new DragButton(this); newBtn->setIcon(pixmap); newBtn->setIconSize(QSize(40, 40)); newBtn->move(event->pos() - offset); newBtn->show(); newBtn->setAttribute(Qt::WA_DeleteOnClose); // 处理拖放动作... if (event->source()->parent() == this) { event->setDropAction(Qt::MoveAction); event->accept(); } else { event->acceptProposedAction(); } } else { event->ignore(); } } ``` ### 问题原因详解 1. **前向声明(Forward Declaration)问题**: - 头文件可能只包含`class QDropEvent;`这样的前向声明 - 前向声明允许声明指针/引用,但不能访问成员 - `event->mimeData()`需要完整的类定义 2. **Qt事件处理机制**: - 拖放事件处理需要完整包含相关头文件 - `QDropEvent`定义在`<QDropEvent>`中 - `QMimeData`定义在`<QMimeData>`中 3. **编译器处理过程**: ```mermaid graph TD A[编译MainWindow.cpp] --> B{识别QDropEvent} B -->|仅前向声明| C[知道类型存在] B -->|需要成员访问| D[需要完整定义] D --> E[报incomplete type错误] ``` 4. **Qt拖放系统组件关系**: - `QDropEvent` ← 包含于 → `QMimeData` - `QMimeData` ← 包含于 → `QDrag` - `QDataStream` ← 依赖 → `QByteArray` ### 预防此类错误的建议 1. **在实现文件中包含完整头文件** ```cpp // 在.cpp文件中总是包含实际使用的类的头文件 #include <QDropEvent> #include <QMimeData> ``` 2. **头文件中使用前向声明** ```cpp // MainWindow.h #include <QMainWindow> // 前向声明代替包含 class QDropEvent; class QMimeData; class MainWindow : public QMainWindow { // ... protected: void dropEvent(QDropEvent *event) override; }; ``` 3. **使用Qt模块包含**(确保.pro文件配置正确) ```qmake # 项目.pro文件 QT += core gui widgets ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值