1

I want to add text to my clipboard and then quit my application right after the text has been added to clipboard.

QClipboard requires to run in the event loop, so I created QObject with a slot that does the clipboard copying for me and invoked the Slot with QTimer::singleShot. When the Slot is done it emits a signal finished() to QApplication::quit().

Now the problem is that the clipboard is empty if I emit the finished() signal and QApplication::quit() is invoked. Only when I don't quit the QApplication the clipboard text is added correctly. Why is that?

Besides QTimer::singleShot I also tried to invoke my Slot with QMetaObject::invokeMethod, but it's the same result as above.

main.cpp

#include "controller.h"
#include "worker.h"

#include <QApplication>
#include <QDebug>
#include <QTimer>
#include <QtGlobal>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    qDebug() << "Starting executing...\n";
    QString bn = QString::fromStdString(argv[1]);
    Worker b;
    // QTimer::singleShot(1, [&] { b.onEventLoopStarted(bn); });
    QMetaObject::invokeMethod(&b, "onEventLoopStarted", Qt::QueuedConnection, Q_ARG(QString, bn));
    QObject::connect(&b, SIGNAL(finished()), &app, SLOT(quit()));
    return app.exec();
}

worker.cpp

#include "worker.h"
#include <boost/format.hpp>
#include <cstdio>
#include <fstream>
#include <ios>
#include <iostream>
#include <QApplication>
#include <QClipboard>
#include <QDebug>
#include <QDir>
#include <QMessageBox>
#include <QtGui/QImage>
#include <QTimer>
#include <QThread>
#include <regex>
#include <stdio.h>
#include <stdlib.h>
#include <string>

// Worker::Worker(): bn("") {}
Worker::Worker(QObject *parent) : QObject(parent) {}

Worker::~Worker() {}

void Worker::set_bn(const QString &bn) {
    this->bn = bn;
}

void Worker::doc_filename(std::string& fn) {
    FILE *p;
    char line [1024];
    // https://stackoverflow.com/a/671528
    p = popen("ps aux | grep '[/]usr/share/typora/Typora /'", "r");
    if (!p) {
        fprintf(stderr, "Error.");
        exit(1);
    }
    while (fgets(line, sizeof(line) - 1, p)) {
        std::string sline(line);
        std::cout << "1 sline: " << sline << std::endl;
        static const std::regex re("(.*\\/usr\\/share\\/typora\\/Typora)\\ (\\/.*)\n");
        std::smatch m;
         if(std::regex_match(sline, m, re)) {
            fn = m[2];
            std::cout << "2. path: " << fn << std::endl;
        }
        else {
            std::cout << "2. not match" << std::endl;
        }
    }
    pclose(p);
}

void Worker::onEventLoopStarted(QString bn) {
    std::string fn = "";
    this->doc_filename(fn);
    if (fn == "") {
        QMessageBox msgBox;
        msgBox.setText("Open the typora document, where the image should be added to.");
        msgBox.exec();
        emit finished();
        // QApplication::quit();
    }
    // from paramater get pwd and fn
    // move fn to assets of fn
    std::cout << "fn: " << fn << std::endl;
    qDebug() << QDir::currentPath();
    QString img_fn = QDir::cleanPath(QDir::currentPath() + QDir::separator() + bn);
    qDebug() << "img_fn" << img_fn;
    /* moves
    std::ifstream in(img_fn, std::ios::in | std::ios::binary);
    std::ofstream out(new_img_fn, std::ios::out | std::ios::binary);
    out << in.rdbuf();
    std::remove(img_fn);
    */
    // Calculate img height, e.g. *0.8. use 0.8, then adjust after test
    QImage img;
    img.load(img_fn);
    QString new_width = QString::number(img.width() * 0.8);
    QString html_line = QString("<img src='%1' alt='' width='%2'>").arg(img_fn, new_width);
    qDebug() << html_line;
    // copy html_line to qt clipboard

    QClipboard *clipboard = QApplication::clipboard();
    clipboard->clear();
    clipboard->setText(html_line);

    qDebug() << "test";

    //emit finished();
    qDebug() << "finished Worker\n";
    //QApplication::quit();
}

worker.h

#ifndef CHILD_OBJECT_H
#define CHILD_OBJECT_H

#include <QObject>
#include <QThread>

class Worker : public QObject
{
    Q_OBJECT

public:
    explicit Worker(QObject *parent = 0);
    ~Worker();
    void set_bn(const QString &bn);
    void doc_filename(std::string&);

signals:
    void finished();

public slots:
    void onEventLoopStarted(QString);

private:
    QString bn;
};

#endif // CHILD_OBJECT_H
fremon
  • 105
  • 6
  • This question may be relevant (although it is written for the python version of Qt): https://stackoverflow.com/questions/2007103/how-can-i-disable-clear-of-clipboard-on-exit-of-pyqt-application – m7913d Jun 12 '19 at 19:00
  • The suggested solution from your link is not working for me. I added `QEvent event = QEvent(QEvent::Clipboard); QApplication::sendEvent(clipboard, &event);` to the Slot. I have klipper installed and running. – fremon Jun 12 '19 at 21:56
  • The same source that states that clipboard operations in X11 require a running event loop also says: "You should not store or retrieve the clipboard contents in response to timer or non-user-input events." – Martin Hennings Jun 13 '19 at 06:58

0 Answers0