如果由同一应用程序触发,则丢弃QClipboard :: DataChanged()信号

Discard QClipboard::dataChanged() signal if triggered by the same application

本文关键字:QClipboard DataChanged 信号 应用程序 如果      更新时间:2023-10-16

我正在应用程序中使用qclipboard,其中可以复制和粘贴大型3D对象。糊状操作可能会阻止GUI一段时间,因为必须去序列化许多数据。

我想在对象被复制并粘贴在同一应用程序窗口上的频繁情况下进行优化。在这种情况下,我不需要系统范围的剪贴板,简单的内部功能可以存储并复制C 对象而无需进行挑选化。

所以这个想法是:

1)当调用"复制"时,内部存储对象的副本,并且对象被序列化并将其放置在系统剪贴板上。设置了标志,以记住下一个糊状操作应直接采用存储的对象,而不是系统剪贴板。

2)当系统剪贴板已通过另一个应用程序修改(可能是同一程序,但另一个过程)时,设置了标志,以知道应从系统剪贴板上进行下一个粘贴操作,并具有供应。p> 3)"粘贴"操作检查标志,然后将内部存储的对象取下,或者从系统剪贴板中估算对象。

问题是1)。每当我更改系统剪贴板时,datachanged()信号就会触发。这是不同步的,在qclipboard :: SetData被调用后很长时间。因此,将blocksignals()设置为setData()的呼叫无济于事。

有什么想法吗?

谢谢!

在文档中我假设QClipboard::ownsClipboard()如果dataChanged()是由当前过程本身引起的,则返回true

因此,您可以在连接到dataChanged()和E.G.的插槽中检查一下。忽略该特定的调用。

第一个问题是您不应该在GUI线程中进行审理。您可以同时运行避难所。

固定后,您就可以针对剪贴板内部的情况进行优化。这可以使用标志完成 - 而不会阻止信号。

这是您如何解决这两个问题的草图。首先,我们有一个Data类,该类容纳数据并且复制价格昂贵 - 因此我们不让它复制:

class Data {
   Q_DISABLE_COPY(Data) // presumably expensive to copy
public:
   //...
   QMimeData* serialize() { return new QMimeData; }
   static QSharedPointer<Data> deserialize(QMimeData*);
};
Q_DECLARE_METATYPE(QSharedPointer<Data>)

然后,我们需要一种克隆MIME数据的方法:

QMimeData* clone(const QMimeData *src) {
   auto dst = new QMimeData();
   for (auto format : src->formats())
      dst->setData(format, src->data(format));
   return dst;
}

最后,具有由操作触发的on_copyon_paste方法的控制器对象。

跟踪分为两个阶段:首先,副本将内部状态切换为Copied。然后,当剪贴板指示数据已更改时,状态从CopiedReady

最后,如果状态为Ready,则on_paste将使用内部数据执行糊状。否则,它将同时进行挑选,并在避免完成后执行粘贴。

paste方法应实现数据的实际粘贴。

class Class : public QObject {
   Q_OBJECT
   QSharedPointer<Data> m_data;
   enum { None, Copied, Ready } m_internalCopy = None;
   Q_SIGNAL void reqPaste(const QSharedPointer<Data> &);
   void paste(const QSharedPointer<Data> &);
   void onDataChanged() {
      m_internalCopy = m_internalCopy == Copied ? Ready : None;
   }
public:
   Q_SLOT void on_copy() {
      m_internalCopy = Copied;
      QScopedPointer<QMimeData> mimeData(m_data->serialize());
      QApplication::clipboard()->setMimeData(mimeData.data());
   }
   Q_SLOT void on_paste() {
      if (m_internalCopy == Ready)
         return paste(m_data);
      m_internalCopy = None;
      auto mimeData = clone(QApplication::clipboard()->mimeData());
      QtConcurrent::run([=]{
         emit reqPaste(Data::deserialize(mimeData));
         delete mimeData;
      });
   }
   Class() {
      qRegisterMetaType<QSharedPointer<Data>>();
      connect(QApplication::clipboard(), &QClipboard::dataChanged, this,
              &Class::onDataChanged);
      connect(this, &Class::reqPaste, this, &Class::paste);
   }
};