当先锋百科网

首页 1 2 3 4 5 6 7

Draggable Text例子展示了怎么样拖放文本数据。

本例程序可拖动放置单个Label控件到本程序任意位置。也可以将各个控件拖到其他应用程序中(如office软件),将显示label上的单词,也可以将其他应用程序中文本拖放到其中,他将拆分并显示为一个个单词的label


项目文件有两个主要类:DragLabel  DragWidget

先看main.cpp

int main(int argc, char *argv[])

{

   Q_INIT_RESOURCE(draggabletext);

   QApplication app(argc, argv);

   DragWidget window;

#ifdef Q_OS_SYMBIAN

   window.showMaximized();

#else

   window.show();

#endif

   return app.exec();

}

Main函数里没有什么特别的,就是实例化并显示了DragWidget

由于DragWidget的实现依赖DragLabel,下面先讲DragLabel

 

class DragLabel : public QLabel

{

public:

   DragLabel(const QString &text, QWidget *parent);

};

DragLabel定义很简单,继承QLabel,只添加了一个构造函数。QLabel是继承自QFrame

 

DragLabel::DragLabel(const QString &text, QWidget *parent)

   QLabel(text, parent)

{

   setAutoFillBackground(true);   // 自动填充背景,默认是不填充透明的

   setFrameShape(QFrame::Panel);  // 设置形状:面板

   setFrameShadow(QFrame::Raised);// 设置投影类型:下沉

}

下面看DragWidgetl类。

dragwidget.h:

 

class DragWidget : public QWidget

{

public:

   DragWidget(QWidget *parent = 0);

protected:

   void dragEnterEvent(QDragEnterEvent *event);

   void dropEvent(QDropEvent *event);

   void mousePressEvent(QMouseEvent *event);

};


Dragwidget重写了dragEnterEventdropEventmousePressEvent三个事件响应函数。

 

DragWidget::DragWidget(QWidget *parent)

   QWidget(parent)

{

   QFile dictionaryFile(":/dictionary/words.txt"); // 使用资源文件

   dictionaryFile.open(QIODevice::ReadOnly);       // 以只读形式打开文件

   QTextStream inputStream(&dictionaryFile);       // 使用QTextStream提供文本写入操作

   int x = 5     // x,y 提供移动宽高的变量

   int y = 5;

   while (!inputStream.atEnd()) {

       QString word;

       inputStream >> word;      // 从文本流中取出一个单词

       if (!word.isEmpty()) {    // 非空则创建Label

           DragLabel *wordLabel = new DragLabel(word, this); // 创建一个label

           wordLabel->move(x, y);       // 向右向下移动5像素

           wordLabel->show();           // 显示

           wordLabel->setAttribute(Qt::WA_DeleteOnClose);  // 设置关闭时删除

           x += wordLabel->width() + 2       // 创建下一个前,将x移动值加当前label的宽+2

           if (x >= 245) {                     // x大于245就换行

               x = 5;

               y += wordLabel->height() + 2  // 换行要向下移动label+2

           }

       }

   }

   setAcceptDrops(true);           // 设置接受放置

   setMinimumSize(400, qMax(200, y));  // 设置控件面板的最小大小,qMax宏返回两参数的较大一个

   setWindowTitle(tr("Draggable Text"));  // 窗口标题

}

这其中QTextStream是文本流,可以被QIODeviceQByteArrayQString操作。它重载了一系列的<<>>操作符,使用起来很方便。还支持区域填充,对齐和数据格式化。例如:

QFile data("output.txt");

 if (data.open(QFile::WriteOnly | QFile::Truncate)) {

     QTextStream out(&data);

     out << "Result: " << qSetFieldWidth(10) << left << 3.14 << 2.7;

     // writes "Result: 3.14      2.7       "

 }

还可以进行控制台标准输入输出:

    QString line;

    QTextStream in(stdin);

    in >> line;

    QTextStream out(stdout);

    out << line << endl;

 

 

void DragWidget::dragEnterEvent(QDragEnterEvent *event)

{

   if (event->mimeData()->hasText()) // hasText()如果是text(MIME type text/plain)就返回true

   {

       if (event->source() == this) {

           event->setDropAction(Qt::MoveAction);

           event->accept();

       else {

           event->acceptProposedAction();

       }

   else {

       event->ignore();

   }

}

其中QMimeData还有hasUrls hasHtml hasImage hasColor这些都和hasFormat是类似的。满足一定类型信息就返回true。其他的和之前的Draggable Icons Example是一样的,同源设置事件为移动事件,否则设置为接收目标动作。

 

 

void DragWidget::mousePressEvent(QMouseEvent *event)

{

   QLabel *child = static_cast<QLabel*>(childAt(event->pos())); // 获取为QLabel的子控件

   if (!child)

       return;

   QPoint hotSpot = event->pos() - child->pos();  // 初始化热点,光标点在控件上的相对位置

   QMimeData *mimeData = new QMimeData;

   mimeData->setText(child->text());           // 设置文本

   mimeData->setData("application/x-hotspot",

                     QByteArray::number(hotSpot.x())

                     " " + QByteArray::number(hotSpot.y()));  // 设置信息(存储的热点)

   QPixmap pixmap(child->size());

   child->render(&pixmap);

   QDrag *drag = new QDrag(this);      // 设置拖动类

   drag->setMimeData(mimeData);        // MIME数据

   drag->setPixmap(pixmap);            // 拖动图片

   drag->setHotSpot(hotSpot);          // 热点

   Qt::DropAction dropAction = drag->exec(Qt::CopyAction | Qt::MoveActionQt::CopyAction);

                                       // exec第二个参数本来是默认Qt::MoveAction,这里设置为拷贝

   if (dropAction == Qt::MoveAction  // 接收到返回值为移动,则将原来的label关闭

       child->close();

}

鼠标按下事件,创建Drag对象,将MIME信息存入Drag类对象。并执行Drag,对返回值进行处理。

 

 

void DragWidget::dropEvent(QDropEvent *event)

{

   if (event->mimeData()->hasText()) {

       const QMimeData *mime = event->mimeData();      // 获取MIME类型信息

       QStringList pieces = mime->text().split(QRegExp("\\s+"), // 匹配一个或多个"空格",拆分为单个的单词

                            QString::SkipEmptyParts);

       QPoint position = event->pos();      // 获取事件位置

       QPoint hotSpot;

       QList<QByteArray> hotSpotPos = mime->data("application/x-hotspot").split(' '); // 将数据里的x,y裂分开

       if (hotSpotPos.size() == 2) {

           hotSpot.setX(hotSpotPos.first().toInt());    // 设置热点xy

           hotSpot.setY(hotSpotPos.last().toInt());

       }

       foreach (QString piece, pieces) {   // 对拖放的拆分的文本遍历并添加为DragLabel

           DragLabel *newLabel = new DragLabel(piece, this);

           newLabel->move(position - hotSpot);

           newLabel->show();

           newLabel->setAttribute(Qt::WA_DeleteOnClose);

           position += QPoint(newLabel->width(), 0);

       }

       if (event->source() == this) {    // 同源

           event->setDropAction(Qt::MoveAction);

           event->accept();

       else {

           event->acceptProposedAction();

       }

   else {

       event->ignore();

   }

   foreach (QObject *child, children()) {   // 遍历所有继承自QWidget的对象,让其在没有显示的都将其释放掉

       if (child->inherits("QWidget")) {

           QWidget *widget = static_cast<QWidget *>(child);

           if (!widget->isVisible())

               widget->deleteLater();

       }

   }

}

其中split函数式裂分成子项的功能。例如:

 QString str = "a,,b,c";

 QStringList list1 = str.split(",");

 // list1: [ "a", "", "b", "c" ]

 QStringList list2 = str.split(",", QString::SkipEmptyParts);

 // list2: [ "a", "b", "c" ]

QRegExp是一个用正则表达式的模板匹配类,在以后博客中将会详细讲它。这里“\s+”是“空白符”。

foreach (QObject *child, children()),children()返回DragWidget对象的所有子类的列表,foreach进行遍历,在判断进行删除隐藏的部件。这是个常用的小技巧。