Qt浅谈之十二:拖拽文字图片

一、简介

       首先选择窗体显示风格,接着显现拖拽效果,文字和图标都可以作为拖拽的对象,在窗体中的文字图标可以拖拽到窗口的任意位置,它们在两个独立运行的程序间也可相互拖拽(此时是复制一份到拖拽目的程序窗口中),文字拖拽的范围更广(须注意字符集的转换)。本文解决这种比较神秘的效果,熟悉拖拽的基本流程。

二、运行图

(1)总体效果图如下图1所示。左边风格设置,中间文字区,右侧拖拽区。

(2)拖拽的实现过程,如下图2所示。

实现拖拽最基本的工作有3部分:一、在可拖拽对象的mousePressEvent()函数中构建QDrag对象,并调用start()函数等待DropAction的返回。二、在放置可拖拽对象的容器类中,实现dragEnterEvent()函数,判断并设置应采用何种DropAction,返回给start()函数。三、在放置可拖拽对象的容器类中,实现dragEnterEvent()函数,创建一个新的可拖拽对象并在当前鼠标位置进行显示,同时判断并设置应采用何种DropAction,返回给start()函数。

三、详解

1、窗体风格

(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()完成窗体显示的改变。

2、拖拽文字

(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(),因此其他的文本也可来回共享(图片仅支持自己的格式)。

3、拖拽图标

(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]

你可能感兴趣的:(LinuxQt编程)