• Qt官方示例:Fridge Magnets Example(冰箱贴)


    冰箱贴类:

    1. #include "draglabel.h"
    2. #include
    3. DragLabel::DragLabel(const QString &text, QWidget *parent)
    4. : QLabel(parent)
    5. {
    6. QFontMetrics metric(font());
    7. QSize size = metric.size(Qt::TextSingleLine, text);
    8. QImage image(size.width() + 12, size.height() + 12, QImage::Format_ARGB32_Premultiplied);
    9. image.fill(qRgba(0, 0, 0, 0));
    10. QLinearGradient gradient(0, 0, 0, image.height()-1);
    11. gradient.setColorAt(0.0, Qt::white);
    12. gradient.setColorAt(0.2, QColor(200, 200, 255));
    13. gradient.setColorAt(0.8, QColor(200, 200, 255));
    14. gradient.setColorAt(1.0, QColor(127, 127, 200));
    15. QPainter painter(&image);
    16. painter.setRenderHint(QPainter::Antialiasing);
    17. painter.setBrush(gradient);
    18. painter.drawRoundedRect(QRectF(0.5, 0.5, image.width()-1, image.height()-1),25, 25, Qt::RelativeSize);
    19. painter.setFont(font());
    20. painter.setBrush(Qt::black);
    21. painter.drawText(QRect(QPoint(6, 6), size), Qt::AlignCenter, text);
    22. setPixmap(QPixmap::fromImage(image));
    23. m_labelText = text;
    24. }
    25. QString DragLabel::labelText() const
    26. {
    27. return m_labelText;
    28. }

    一个自定义的 QLabel,根据创建时传入的文本设确定一个图片的尺寸,使用渐变的画刷在图片绘制一个圆角矩形和文本,然后设置标签显示此图片。

    然后是一个白色的窗口:

    1. DragWidget::DragWidget(QWidget *parent)
    2. : QWidget(parent)
    3. {
    4. QFile dictionaryFile(QStringLiteral(":/dictionary/words.txt"));
    5. dictionaryFile.open(QFile::ReadOnly);
    6. QTextStream inputStream(&dictionaryFile);
    7. int x = 5;
    8. int y = 5;
    9. while (!inputStream.atEnd())
    10. {
    11. QString word;
    12. inputStream >> word;
    13. if (!word.isEmpty())
    14. {
    15. DragLabel *wordLabel = new DragLabel(word, this);
    16. wordLabel->move(x, y);
    17. wordLabel->show();
    18. wordLabel->setAttribute(Qt::WA_DeleteOnClose);
    19. x += wordLabel->width() + 2;
    20. if (x >= 245)
    21. {
    22. x = 5;
    23. y += wordLabel->height() + 2;
    24. }
    25. }
    26. }
    27. QPalette newPalette = palette();
    28. newPalette.setColor(QPalette::Window, Qt::white);
    29. setPalette(newPalette);
    30. setMinimumSize(400, qMax(200, y));
    31. setWindowTitle(tr("Fridge Magnets"));
    32. setAcceptDrops(true);
    33. }

    从一个文本文件中读取内容:

    每次读取一行,读取一行就创建一个冰箱贴并移动到相应的位置。最后设置窗口支持拖放。

    鼠标按下的操作:

    1. void DragWidget::mousePressEvent(QMouseEvent *event)
    2. {
    3. DragLabel *child = static_cast(childAt(event->position().toPoint()));
    4. if (!child)
    5. return;
    6. QPoint hotSpot = event->position().toPoint() - child->pos();//鼠标按在child上的位置
    7. QByteArray itemData;
    8. QDataStream dataStream(&itemData, QIODevice::WriteOnly);
    9. dataStream << child->labelText() << QPoint(hotSpot);
    10. QMimeData *mimeData = new QMimeData;
    11. mimeData->setData(fridgetMagnetsMimeType(), itemData);
    12. mimeData->setText(child->labelText());
    13. QDrag *drag = new QDrag(this);
    14. drag->setMimeData(mimeData);
    15. drag->setPixmap(child->pixmap());
    16. drag->setHotSpot(hotSpot);
    17. child->hide();
    18. if (drag->exec(Qt::MoveAction | Qt::CopyAction, Qt::CopyAction) == Qt::MoveAction)
    19. child->close();
    20. else
    21. child->show();
    22. }

    这里定义了一种自定义MIME类型:

    static inline QString fridgetMagnetsMimeType() { return QStringLiteral("application/x-fridgemagnet"); }

    内联的非成员函数,这种写法值得学习。

    其中包含了了冰箱贴的文本和鼠标按下的位置。

    开始拖放操作后,如果是拖放移到那么冰箱贴就隐藏了,拖动过程中显示的只是 QDrag::pixmap()。

    拖动进入事件和拖动移到事件:

    1. void DragWidget::dragEnterEvent(QDragEnterEvent *event)
    2. {
    3. if (event->mimeData()->hasFormat(fridgetMagnetsMimeType()))
    4. {
    5. if (children().contains(event->source()))
    6. {
    7. event->setDropAction(Qt::MoveAction);
    8. event->accept();
    9. }
    10. else
    11. {
    12. event->acceptProposedAction();
    13. }
    14. }
    15. else if (event->mimeData()->hasText())
    16. {
    17. event->acceptProposedAction();
    18. }
    19. else
    20. {
    21. event->ignore();
    22. }
    23. }
    24. void DragWidget::dragMoveEvent(QDragMoveEvent *event)
    25. {
    26. if (event->mimeData()->hasFormat(fridgetMagnetsMimeType()))
    27. {
    28. if (children().contains(event->source()))
    29. {
    30. event->setDropAction(Qt::MoveAction);
    31. event->accept();
    32. }
    33. else
    34. {
    35. event->acceptProposedAction();
    36. }
    37. }
    38. else if (event->mimeData()->hasText())
    39. {
    40. event->acceptProposedAction();
    41. }
    42. else
    43. {
    44. event->ignore();
    45. }
    46. }

    这两个没啥好说的,主要是拖动放下事件:

    1. void DragWidget::dropEvent(QDropEvent *event)
    2. {
    3. if (event->mimeData()->hasFormat(fridgetMagnetsMimeType()))
    4. {
    5. const QMimeData *mime = event->mimeData();
    6. QByteArray itemData = mime->data(fridgetMagnetsMimeType());
    7. QDataStream dataStream(&itemData, QIODevice::ReadOnly);
    8. QString text;
    9. QPoint offset;
    10. dataStream >> text >> offset;
    11. DragLabel *newLabel = new DragLabel(text, this);
    12. newLabel->move(event->position().toPoint() - offset);
    13. newLabel->show();
    14. newLabel->setAttribute(Qt::WA_DeleteOnClose);
    15. if (event->source() == this)
    16. {
    17. event->setDropAction(Qt::MoveAction);
    18. event->accept();
    19. }
    20. else
    21. {
    22. event->acceptProposedAction();
    23. }
    24. }
    25. else if (event->mimeData()->hasText())
    26. {
    27. QStringList pieces = event->mimeData()->text().split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts);
    28. QPoint position = event->position().toPoint();
    29. for (const QString &piece : pieces)
    30. {
    31. DragLabel *newLabel = new DragLabel(piece, this);
    32. newLabel->move(position);
    33. newLabel->show();
    34. newLabel->setAttribute(Qt::WA_DeleteOnClose);
    35. position += QPoint(newLabel->width(), 0);
    36. }
    37. event->acceptProposedAction();
    38. }
    39. else
    40. {
    41. event->ignore();
    42. }
    43. }

    第一个分支在拖动放下的位置新建冰箱贴,从 QMimeData 取出数据设置其文本和位置。

    第二个分支指示拖动能用空白符分割的文本到当前窗口,则使用其文本创建冰箱贴。

    涉及到的类:

  • 相关阅读:
    数字时代的自我呈现:探索个人形象打造的创新工具——FaceChain深度学习模型工具
    Nacos源码系列—订阅机制的前因后果(下)
    Scala在大数据领域的崛起:当前趋势和未来前景
    全面了解三极管——三极管基本参数总结
    智能运维,为新型数据中心注入科技动能
    MySQL中的复合查询与表的内外连接解析
    Mac搭建Jmeter分布式加压步骤
    使用YOLOv5-C3模块识别图像天气 - P8
    定时任务管理系统详细设计说明书
    gradle升级,plugin使用方法
  • 原文地址:https://blog.csdn.net/kenfan1647/article/details/126012095