首先选择窗体显示风格,接着显现拖拽效果,文字和图标都可以作为拖拽的对象,在窗体中的文字图标可以拖拽到窗口的任意位置,它们在两个独立运行的程序间也可相互拖拽(此时是复制一份到拖拽目的程序窗口中),文字拖拽的范围更广(须注意字符集的转换)。本文解决这种比较神秘的效果,熟悉拖拽的基本流程。
(1)总体效果图如下图1所示。左边风格设置,中间文字区,右侧拖拽区。
(2)拖拽的实现过程,如下图2所示。
实现拖拽最基本的工作有3部分:一、在可拖拽对象的mousePressEvent()函数中构建QDrag对象,并调用start()函数等待DropAction的返回。二、在放置可拖拽对象的容器类中,实现dragEnterEvent()函数,判断并设置应采用何种DropAction,返回给start()函数。三、在放置可拖拽对象的容器类中,实现dragEnterEvent()函数,创建一个新的可拖拽对象并在当前鼠标位置进行显示,同时判断并设置应采用何种DropAction,返回给start()函数。
(1)系统支持的7中窗体风格,如下图所示。
QLabel *label = new QLabel(QObject::tr("窗体风格:"));
QComboBox *styleComboBox = new QComboBox;
styleComboBox->addItems(QStyleFactory::keys());
styleComboBox->setCurrentIndex(5);
void DragWidget::slotChangeStyle(QString style)
{
QApplication::setStyle(QStyleFactory::create(style));
QApplication::setPalette(QApplication::style()->standardPalette());
}
QStyleFactory::keys()获得当前系统支持的窗体风格,QApplication的setStyle()函数设置为刚创建的风格,调用setPalette()完成窗体显示的改变。
(1)同一实例程序拖拽(移动)
中间控件的文字都拖放到右侧,通过光标的选择分解它们。
void DragLabel::mousePressEvent(QMouseEvent * e)
{
QString str = text();
QPixmap pix;
pix = pix.grabWidget(this);
QByteArray data;
QDataStream stream(&data,QIODevice::WriteOnly);
stream << str << QPoint(e->pos()-rect().topLeft());
QMimeData *mimeData = new QMimeData;
mimeData->setData("Drag-Text",data);
mimeData->setText(str);
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setHotSpot(QPoint(e->pos() - rect().topLeft()));
drag->setPixmap(pix);
hide();
Qt::DropAction dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);
if (dropAction == Qt::MoveAction)
close();
else
show();
}
(2)不同实例程序拖拽(复制)
左侧文字向右侧程序中拖拽。
(3)外部程序拖拽交互
文本间的来回移动,以空格为分隔标志,也可以复制一段文字,但暂时没法控制文字的长度显示。
void DragWidget::dropEvent(QDropEvent *e)
{
if (e->mimeData()->hasFormat("Drag-Icon")) {
QByteArray data = e->mimeData()->data("Drag-Icon");
QDataStream stream(&data,QIODevice::ReadOnly);
QPixmap pix;
QPoint offset;
stream >> pix >> offset;
DragIcon *icon = new DragIcon(pix,this);
icon->move(e->pos() - offset);
icon->resize(50, 50);
icon->show();
if (children().contains(e->source())) {
e->setDropAction(Qt::MoveAction);
e->accept();
}
else e->acceptProposedAction();
}
else if (e->mimeData()->hasFormat("Drag-Text"))
{
QByteArray data = e->mimeData()->data("Drag-Text");
QDataStream stream(&data,QIODevice::ReadOnly);
QString text;
QPoint offset;
stream >> text >> offset;
DragLabel *label = new DragLabel(text,this);
label->move(e->pos() - offset);
label->show();
if (children().contains(e->source())) {
e->setDropAction(Qt::MoveAction);
e->accept();
}
else e->acceptProposedAction();
}
else if (e->mimeData()->hasText())
{
QStringList strList = e->mimeData()->text().split(QRegExp("\\s+"),QString::SkipEmptyParts);
QPoint pos = e->pos();
foreach(QString str, strList) {
DragLabel *dragLabel = new DragLabel(str,this);
dragLabel->move(pos);
dragLabel->show();
pos += QPoint(dragLabel->width(),0);
}
if (children().contains(e->source())) {
e->setDropAction(Qt::MoveAction);
e->accept();
}
else {
e->acceptProposedAction();
}
}
else {
e->ignore();
}
}
上代码的if判断可知,拖拽文本不仅支持自定义的格式hasFormat("Drag-Text"),而且还支持简单的文本格式e->mimeData()->hasText(),因此其他的文本也可来回共享(图片仅支持自己的格式)。
(1)同一实例程序拖拽(移动)
void DragIcon::mousePressEvent(QMouseEvent * e)
{
if(e->button() == Qt::LeftButton)
startPos = e->pos();
}
void DragIcon::mouseMoveEvent(QMouseEvent * e)
{
if (!e->buttons()&Qt::LeftButton)
return;
if ((e->pos() - startPos).manhattanLength() < QApplication::startDragDistance())
return;
QPixmap pix = *pixmap();
QByteArray data;
QDataStream stream(&data,QIODevice::WriteOnly);
stream << pix << QPoint(e->pos()-rect().topLeft());
QMimeData *mimeData = new QMimeData;
mimeData->setData("Drag-Icon",data);
QDrag *drag = new QDrag(this);
drag->setMimeData(mimeData);
drag->setHotSpot(QPoint(e->pos() - rect().topLeft()));
drag->setPixmap(pix);
hide();
Qt::DropAction dropAction = drag->start(Qt::CopyAction | Qt::MoveAction);
if (dropAction == Qt::MoveAction)
close();
else
show();
}
void DragWidget::dragEnterEvent(QDragEnterEvent *e)
{
if (e->mimeData()->hasText() || e->mimeData()->hasFormat("Drag-Icon"))
{
if(children().contains(e->source()))
{
e->setDropAction(Qt::MoveAction);
e->accept();
}
else
e->acceptProposedAction();
}
}
void DragWidget::dragMoveEvent(QDragMoveEvent *e)
{
if (e->mimeData()->hasText() || e->mimeData()->hasFormat("Drag-Icon"))
{
if(children().contains(e->source()))
{
e->setDropAction(Qt::MoveAction);
e->accept();
}
else
e->acceptProposedAction();
}
}
在本窗口的右侧组件中可以来回拖放图片,因改程序自定义了图片格式hasFormat("Drag-Icon"),因此其他的图片无法拖入。
(2)不同实例程序拖拽(复制)
void DragWidget::dropEvent(QDropEvent *e)
{
if (e->mimeData()->hasFormat("Drag-Icon")) {
QByteArray data = e->mimeData()->data("Drag-Icon");
QDataStream stream(&data,QIODevice::ReadOnly);
QPixmap pix;
QPoint offset;
stream >> pix >> offset;
DragIcon *icon = new DragIcon(pix,this);
icon->move(e->pos() - offset);
icon->resize(50, 50);
icon->show();
if (children().contains(e->source())) {
e->setDropAction(Qt::MoveAction);
e->accept();
}
else e->acceptProposedAction();
}
//.........................
}
(1)本文仅简单总结,还可以扩展到类似于剪贴板的机制,拖拽文字可以加入字符集的转换,拖拽图片可以考虑外部图片的转换,还可以扩展到文件的拖拽。
(2)对部分代码的理解也是不太深入,还得进一步深究。
(3)源码已经打包上传到csdn上可登录下载(http://download.csdn.net/detail/taiyang1987912/7574413)。
(4)本人思路有限,若有更好的设计建议,也可发邮件沟通,在此先感谢!邮箱地址[email protected]。