1、Qt中的拖放事件
拖放一个文件进入窗口时将触发拖放事件
每一个QWidget对象都能够处理拖放事件
拖放事件的处理函数为
- void dragEnterEvent(QDragEnterEvent* e);
- void dropEvent(QDropEvent* e);
拖放事件中的QMimeData
- QMimeData是Qt中的多媒体数据类
- 拖放事件通过QMimeData对象传递数据
- QMimeData支持多种不同类型的多媒体数据
The QMimeData class provides a container for data
that records information about its MIME type
QMimeData::QMimeData ()
Constructs a new MIME data object with no data in it.
const QMimeData * QDropEvent::mimeData () const
Returns the data that was dropped on the widget and its associated MIME type information.
bool QMimeData::hasUrls () const
Returns true if the object can return a list of urls; otherwise returns false.
URLs correspond to the MIME type text/uri-list.
常用MIME类型数据处理函数
自定义拖放事件的步骤
1. 对接收拖放事件的对象调用setAcceptDrops成员函数
2. 重写dragEnterEvent函数并判断MIME类型
期望数据 : e- > acceptProposedAction ()
其它数据 : e- > ignore();
3. 重写dropEvent函数并判断MIME类型
期望数据:从事件对象中获取MIME数据并处理
其它数据: e- > ignore();
2、编程实验
拖放事件初探 40-1.pro
Widget.h
#ifndef WIDGET_H
#define WIDGET_H
#include <QtGui/QWidget>
class Widget : public QWidget
{
Q_OBJECT
protected:
void dragEnterEvent(QDragEnterEvent* e);
void dropEvent(QDropEvent* e);
public:
Widget(QWidget *parent = 0);
~Widget();
};
#endif // WIDGET_H
Widget.cpp
#include "Widget.h"
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QDebug>
#include <QList>
#include <QUrl>
Widget::Widget(QWidget *parent) : QWidget(parent)
{
setAcceptDrops(true);//当前对象可以接受拖放事件
}
void Widget::dragEnterEvent(QDragEnterEvent* e)//重写托的事件处理函数
{
if( e->mimeData()->hasUrls() )//判断MIME数据是路径类型
{
e->acceptProposedAction();
}
else
{
e->ignore();//交给父组件对象处理
}
}
void Widget::dropEvent(QDropEvent* e)//重写放的事件处理函数
{
if( e->mimeData()->hasUrls() )
{
QList<QUrl> list = e->mimeData()->urls();
for(int i=0; i<list.count(); i++)
{
qDebug() << list[i].toLocalFile();//将当前url转换为本地路径
}
}
else
{
e->ignore();
}
}
Widget::~Widget()
{
}
3、文本编辑器中的拖放事件
文本编辑器中的拖放操作
解决方案
1. 调用主窗口对象的setAcceptDrops成员函数
2. 重写dragEnterEvent函数并判断MIME类型
3. 重写dropEvent函数判断MIME类型后打开文件
4、编程实验
文本编辑器中的拖放事件 NotePad.pro
MainWindowUI.cpp
MainWindow::MainWindow()增加
setAcceptDrops(true);
MainWindow.h
#ifndef _MAINWINDOW_H_
#define _MAINWINDOW_H_
#include <QtGui/QMainWindow>
#include <QKeySequence>
#include <QMenuBar>
#include <QToolBar>
#include <QAction>
#include <QPlainTextEdit>
#include <QLabel>
#include <QFileDialog>
class MainWindow : public QMainWindow
{
Q_OBJECT
private:
QPlainTextEdit mainEditor;
QLabel statusLbl;
QString m_filePath;
bool m_isTextChanged;
MainWindow();
MainWindow(const MainWindow&);
MainWindow& operator= (const MainWindow&);
bool construct();
bool initMenuBar();
bool initToolBar();
bool initStatusBar();
bool initMainEditor();
bool initFileMenu(QMenuBar* mb);
bool initEditMenu(QMenuBar* mb);
bool initFormatMenu(QMenuBar* mb);
bool initViewMenu(QMenuBar* mb);
bool initHelpMenu(QMenuBar* mb);
bool initFileToolItem(QToolBar* tb);
bool initEditToolItem(QToolBar* tb);
bool initFormatToolItem(QToolBar* tb);
bool initViewToolItem(QToolBar* tb);
bool makeAction(QAction*& action, QWidget* parent, QString text, int key);
bool makeAction(QAction*& action, QWidget* parent, QString tip, QString icon);
QString showFileDialog(QFileDialog::AcceptMode mode, QString title);
int showQueryMessage(QString message);
void showErrorMessage(QString message);
QString saveCurrentData(QString path = "");
void preEditorChange();
void openFileToEditor(QString path);
protected:
void closeEvent(QCloseEvent* e);
void dragEnterEvent(QDragEnterEvent* e);
void dropEvent(QDropEvent* e);
private slots:
void onFileNew();
void onFileOpen();
void onFileSave();
void onFileSaveAs();
void onTextChanged();
public:
static MainWindow* NewInstance();
~MainWindow();
};
#endif // _MAINWINDOW_H_
MainWindowSlots.cpp
#include "MainWindow.h"
#include <QFileDialog>
#include <QMessageBox>
#include <QFile>
#include <QTextStream>
#include <QMap>
#include <QCloseEvent>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QList>
#include <QUrl>
#include <QFileInfo>
#include <QDebug>
void MainWindow::showErrorMessage(QString message)
{
QMessageBox msg(this);
msg.setWindowTitle("Error");
msg.setText(message);
msg.setIcon(QMessageBox::Critical);
msg.setStandardButtons(QMessageBox::Ok);
msg.exec();
}
int MainWindow::showQueryMessage(QString message)
{
QMessageBox msg(this);
msg.setWindowTitle("Query");
msg.setText(message);
msg.setIcon(QMessageBox::Question);
msg.setStandardButtons(QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
return msg.exec();
}
QString MainWindow::showFileDialog(QFileDialog::AcceptMode mode, QString title)
{
QString ret = "";
QFileDialog fd(this);
QStringList filters;
QMap<QString, QString> map;
const char* filterArray[][2] =
{
{"Text Files (*.txt)", ".txt"},
{"All Files (*)", "*" },
{NULL, NULL }
};
for(int i=0; filterArray[i][0]!=NULL; i++)
{
filters.append(filterArray[i][0]);
map.insert(filterArray[i][0], filterArray[i][1]);
}
fd.setWindowTitle(title);
fd.setAcceptMode(mode);
fd.setFilters(filters);
if( mode == QFileDialog::AcceptOpen )
{
fd.setFileMode(QFileDialog::ExistingFile);
}
if( fd.exec() == QFileDialog::Accepted )
{
ret = fd.selectedFiles()[0];
if( mode == QFileDialog::AcceptSave )
{
QString postfix = map[fd.selectedFilter()];
if( (postfix != "*") && !ret.endsWith(postfix) )
{
ret = ret + postfix;
}
}
}
return ret;
}
void MainWindow::preEditorChange()
{
if( m_isTextChanged )
{
int r = showQueryMessage("Do you want to save the changes to file?");
switch(r)
{
case QMessageBox::Yes:
saveCurrentData(m_filePath);
break;
case QMessageBox::No:
m_isTextChanged = false;
break;
case QMessageBox::Cancel:
break;
}
}
}
void MainWindow::onFileNew()
{
preEditorChange();
if( !m_isTextChanged )
{
mainEditor.clear();
setWindowTitle("NotePad - [ New ]");
m_filePath = "";
m_isTextChanged = false;
}
}
void MainWindow::openFileToEditor(QString path)
{
if( path != "" )
{
QFile file(path);
if( file.open(QIODevice::ReadOnly | QIODevice::Text) )
{
mainEditor.setPlainText(QString(file.readAll()));
file.close();
m_filePath = path;
m_isTextChanged = false;
setWindowTitle("NotePad - [ " + m_filePath + " ]");
}
else
{
showErrorMessage(QString("Open file error! \n\n") + "\"" + path + "\"");
}
}
}
void MainWindow::onFileOpen()
{
preEditorChange();
if( !m_isTextChanged )
{
QString path = showFileDialog(QFileDialog::AcceptOpen, "Open");
openFileToEditor(path);
}
}
QString MainWindow::saveCurrentData(QString path)
{
QString ret = path;
if( ret == "" )
{
ret = showFileDialog(QFileDialog::AcceptSave, "Save");
}
if( ret != "" )
{
QFile file(ret);
if( file.open(QIODevice::WriteOnly | QIODevice::Text) )
{
QTextStream out(&file);
out << mainEditor.toPlainText();
file.close();
setWindowTitle("NotePad - [ " + ret + " ]");
m_isTextChanged = false;
}
else
{
showErrorMessage(QString("Save file error! \n\n") + "\"" + ret + "\"");
ret = "";
}
}
return ret;
}
void MainWindow::onFileSave()
{
QString path = saveCurrentData(m_filePath);
if( path != "" )
{
m_filePath = path;
}
}
void MainWindow::onFileSaveAs()
{
QString path = saveCurrentData();
if( path != "" )
{
m_filePath = path;
}
}
void MainWindow::onTextChanged()
{
if( !m_isTextChanged )
{
setWindowTitle("*" + windowTitle());
}
m_isTextChanged = true;
}
void MainWindow::closeEvent(QCloseEvent* e)
{
preEditorChange();
if( !m_isTextChanged )
{
QMainWindow::closeEvent(e);
}
else
{
e->ignore();
}
}
void MainWindow::dragEnterEvent(QDragEnterEvent* e)
{
if( e->mimeData()->hasUrls() )
{
e->acceptProposedAction();
}
else
{
e->ignore();
}
}
void MainWindow::dropEvent(QDropEvent* e)
{
if( e->mimeData()->hasUrls() )
{
QList<QUrl> list = e->mimeData()->urls();
QString path = list[0].toLocalFile();
QFileInfo fi(path);
if( fi.isFile() )
{
preEditorChange();
if( !m_isTextChanged )
{
openFileToEditor(path);
}
}
else
{
showErrorMessage("Cannot open a folder!");
}
}
else
{
e->ignore();
}
}
5、小结
QWidget对象都能够处理拖放事件
自定义拖放事件的方法
1. 调用事件接收对象的setAcceptDrops成员函数
2. 重写dragEnterEvent函数并判断MIME类型
3. 重写dropEvent函数判断MIME类型后进行事件处理