2014-06-29 59 views
2

我想製作一個Qt應用程序來監視系統剪貼板的變化。每次用戶將一些文本複製到剪貼板(應用程序外部)時,我的應用程序應該以某種方式更改文本並將更改後的文本複製到剪貼板。問題處理QClipboard :: dataChanged()信號

問題是剪貼板只能變空了!

這裏是我的代碼:

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

    connect(QApplication::clipboard(), SIGNAL(dataChanged()), 
      this, SLOT(processClipboardChange())); 
} 

void MainWindow::processClipboardChange() 
{ 
    qDebug() << "dataChanged() signal emitted."; 

    QClipboard * clipboard = QApplication::clipboard(); 

    static bool dontProcessSignal = false; 

    if (!dontProcessSignal) { 

     QString text = clipboard->text(); 
     text = "CLIPBOARD CONTENTS CHANGED."; // example. 

     qDebug() << "Setting clipboard contents..."; 
     dontProcessSignal = true; 
     clipboard->setText(text); // will trigger another dataChanged() signal. 
     dontProcessSignal = false; 
     qDebug() << "Copied " << clipboard->text() << " to clipboard."; 
    } 
    else { 
     qDebug() << "Did not process dataChanged() signal."; 
     return; 
    } 
} 

現在,當我運行該程序,並通過複製一些文字,用Ctrl + C改變剪貼板的內容,我得到這樣的輸出:

dataChanged() signal emitted. 
Setting clipboard contents... 
dataChanged() signal emitted. 
Did not process dataChanged() signal. 
Copied "CLIPBOARD CONTENTS CHANGED." to clipboard. 

但是,當我鍵入Ctrl + V將剪貼板內容粘貼到某處,沒有任何內容被粘貼。由於某種原因,剪貼板內容似乎設置爲空字符串。

QClipboard::setText()在其他代碼中工作得很好(例如,在QPushButton::clicked插槽中調用時)。

我不知所措。請幫忙。

+0

你嘗試調用'clipboard->的setText(文字,QClipboard什麼: :Selection);''''剪貼板 - > setText(文本)之後''?它在行爲上有什麼不同嗎? – vahancho

回答

1

似乎像Qt刪除了剪貼板數據,如果你在setChanged()內的setText()混亂。它不會刪除剪貼板,如果您在應用程序本身內複製。您可以使用QTimer或者invokeMethod中與QueuedConnection來解決這個問題:

void MainWindow::processClipboardChange() 
{ 
    if (!dontProcessSignal) { 
    // Solution 1, unable to pass argument 
    QTimer::singleShot(1, this, SLOT(setClipboard1())); 

    // Solution 2, able to pass argument 
    QString newText = "CLIPBOARD CONTENTS CHANGED."; 
    QMetaObject::invokeMethod(this, "setClipboard2", Qt::QueuedConnection, Q_ARG(QString, newText)); 
    } 
} 
void MainWindow::setClipboard1() { 
    dontProcessSignal = true; 
    QClipboard * clipboard = QApplication::clipboard(); 
    clipboard->setText("CLIPBOARD CONTENTS CHANGED."); 
    dontProcessSignal = false; 
} 
void MainWindow::setClipboard2(QString s) { 
    dontProcessSignal = true; 
    QClipboard * clipboard = QApplication::clipboard(); 
    clipboard->setText(s); 
    dontProcessSignal = false; 
} 
+0

如果你想知道爲什麼你得到一個'沒有這樣的方法'錯誤:'setClipboard2'需要是一個插槽 – handle

+0

不能得到這個工作,儘管標誌(在槽中總是爲false)導致無限循環。 – handle

2

我成功地使用FXAM上述QTimer的方法來解決這個問題。

這裏是我的所有對未來的讀者代碼:

mainwindow.h

#ifndef MAINWINDOW_H 
#define MAINWINDOW_H 

#include <QMainWindow> 

namespace Ui { 
class MainWindow; 
} 

class MainWindow : public QMainWindow 
{ 
    Q_OBJECT 

public: 
    explicit MainWindow(QWidget *parent = 0); 

private slots: 
    void clipboardChanged(); 
    void setClipboard(); 

private: 
    QString clipboardText; 

private: 
    Ui::MainWindow *ui; 
}; 

#endif // MAINWINDOW_H 

mainwindow.cpp

#include "mainwindow.h" 
#include "ui_mainwindow.h" 

#include <QClipboard> 
#include <QTimer> 
#include <QRegularExpression> 

MainWindow::MainWindow(QWidget *parent) : 
    QMainWindow(parent), 
    ui(new Ui::MainWindow) 
{ 
    ui->setupUi(this); 

    connect(QApplication::clipboard(), SIGNAL(dataChanged()), 
      this, SLOT(clipboardChanged())); 
} 

void MainWindow::clipboardChanged() 
{ 
    // we need to ignore every other dataChanged() signal because 
    // those signals are triggered by us calling QClipboard::setText() 
    static bool ignoreSignal = false; 

    if (ignoreSignal == false) { 
     clipboardText = QApplication::clipboard()->text(); 

     // will trigger another dataChanged() signal 
     // (after our method exits) 
     QTimer::singleShot(50, this, SLOT(setClipboard())); 

     // ignore the next dataChanged() signal 
     ignoreSignal = true; 
    } 
    else { 
     // We're ignoring this signal. Don't ignore the next signal. 
     ignoreSignal = false; 
    } 
} 

void MainWindow::setClipboard() 
{ 
    static QRegularExpression regex("x+"); // example... 
    static QString replacement("a"); 
    QString newClipboardText = clipboardText.replace(regex, replacement); 
    QApplication::clipboard()->setText(newClipboardText); 
}