Вопрос по c++ – app.exec () не может вызвать другой метод (статическая библиотека Qt)

0

Я создаю статическую библиотеку Qt. Мне нужно, вызвав какой-то метод, изменить положение картинки. Проблема в том, что & quot; app.exec () & quot; заблокировать полностью процесс. Ты знаешь как это сделать?

Большое спасибо !

Вот мой заголовочный файл библиотеки

int init(int argc, char *argv[], int width, int height);
void changePos (int x, int y);
void destroyPic();

и мой инициал это:     QWidget * window (0);     QLabel * pic (0);

int init(int argc, char *argv[], int width, int height) {
    // initialize resources, if needed
    Q_INIT_RESOURCE(target);

    QApplication app(argc, argv);
    window = new QWidget();
    window->setWindowTitle("Test");
    window->setFixedSize(width, height);
    // create and show your widgets here
    pic = new QLabel(window);

    QPixmap pixmap(QString(":/res/pic.png"));
    pic->setPixmap(pixmap);
    pic->move(100,100);
    pic->setVisible(true);
    window->show();
    app.exec();

    return 0;
}

проблема в том, что я не могу вызвать в моем основном коде (который использует эту библиотеку) метод changePos или destroy, потому что app.exec () блокирует процесс ... как это сделать?

Большое спасибо !

Вы имеете в виду запуск метода init в потоке, верно? Nakasa
Действительно, я знаю, что app.exec () является функцией блокировки, и я хочу знать, как отобразить окно, не используя эту функцию или другой способ сделать это, не блокируя мою прогу. Nakasa
У меня есть программа, которая не использует QT. Я просто добавляю библиотеку Qt внутри. Поскольку одна часть этой программы должна показывать окно с каким-либо изображением, перемещать это изображение, а затем "уничтожить" окно, я подумал, чтобы использовать lib, чтобы показать окно, рис, переместить их, а затем уничтожить их, не добавляя Qt (с помощью qmake и т. д.) в моей основной программе (потому что это сложно, и я действительно не хочу включать Qt в мою основную программу) Nakasa
кажется, ваша статическая библиотека на самом деле является программой ... что вы пытаетесь сделать снова ?? UmNyobe
В этом случае вам нужно запустить Qt в новом процессе UmNyobe

Ваш Ответ

2   ответа
1

оде ниже. Я еще не работал с OS X, но считаю, что это должно быть выполнимо. Сначала мне нужно сделать отладочную сборку для OS X, затем я посмотрю, что происходит. Он протестирован на работу в Windows и, вероятно, будет работать и на X11. Код Objective C предназначен только для Mac, он, вероятно, требуется, но еще не достаточен.

Это полностью работоспособное приложение, для библиотеки вы можете удалитьmain() Функция и вызовите init, changePos и завершите напрямую, в зависимости от ситуации.

#applib.pro
QT       += core gui
TARGET = applib
TEMPLATE = app
!x11:!embedded:!qpa:mac {
    LIBS_PRIVATE += -framework Cocoa -lz
    OBJECTIVE_SOURCES += thread.mm
}
SOURCES += main.cpp
//main.cpp
#include <cstdlib>
#include <QtCore/QThread>
#include <QtCore/QMutex>
#include <QtCore/QMutexLocker>
#include <QtCore/QWaitCondition>
#include <QtCore/QEvent>
#include <QtGui/QLabel>
#include <QtGui/QApplication>

//
// API
//

extern "C" {
    void init(int argc, char ** argv);
    void changePos(int x, int y);
    void finish();
}

// demonstration code, remove from the library
int main(int argc, char ** argv)
{
    class Helper : private QThread {
    public:
        static void msleep(unsigned long ms) {
            QThread::msleep(ms);
        }
    };

    init(argc, argv);
    Helper::msleep(2000);
    changePos(0, 0);
    Helper::msleep(2000);
    finish();
}

//
// IMPLEMENTATION
//

struct PosEvent : public QEvent
{
    PosEvent(int x_, int y_) : QEvent(t()),
        x(x_), y(y_) {}
    const int x, y;
    static QEvent::Type t() { return (QEvent::Type)(QEvent::User + 0); }
};

class Widget : public QLabel
{
public:
    Widget() : QLabel("Hello!") {}
protected:
    void customEvent(QEvent * ev) {
        if (ev->type() == PosEvent::t()) {
            PosEvent * pev = static_cast<PosEvent*>(ev);
            move(pev->x, pev->y);
        }
    }
};

class QCoreApplicationPrivate {
public:
    static QThread * theMainThread;
};

extern "C++" { Qt::HANDLE qt_application_thread_id; }

class AppThread : public QThread
{
public:
    AppThread(int& argc_, char ** argv_) {
        Q_ASSERT(!instance);
        instance = this;
        QMutexLocker lock(&argMutex);
        argc = &argc_;
        argv = argv_;
        start();
        wc.wait(&argMutex);
    }
    static void changePos(int x, int y) {
        QCoreApplication::postEvent(instance->widget, new PosEvent(x,y));
    }
    static void finish() {
        instance->app->exit();
        instance->wait();
        delete instance;
    }

protected:
    void run() {

        int i = 0;

#ifdef Q_OS_UNIX
        //qDebug("%p", qt_application_thread_id);
        QCoreApplicationPrivate::theMainThread = QThread::currentThread();
#endif
        QApplication a(i, 0);
        app = &a;
        wc.wakeAll();

        Widget w;
        widget = &w;
        w.show();

        rc = a.exec();
    }
private:
    static AppThread * instance;
    QCoreApplication * app;
    QObject * widget;
    QMutex argMutex;
    QWaitCondition wc;
    int* argc;
    char** argv;
    int rc;

};
AppThread * AppThread::instance = 0;

bool multiThreader();

#ifndef Q_OS_MAC
bool multiThreader() { return true; }
#endif

extern "C" void init(int argc, char ** argv) {
    multiThreader();
#ifdef Q_OS_MAC
    qDebug("DYLD_IMAGE_SUFFIX=%s", getenv("DYLD_IMAGE_SUFFIX"));
#endif
    new AppThread(argc, argv);
}

extern "C" void changePos(int x, int y) { AppThread::changePos(x, y); }

extern "C" void finish() { AppThread::finish(); }
//thread.mm
#import <Foundation/Foundation.h>

@interface DeadThread : NSObject { ;; }
    + (void)enterMultiThreadedMode;
    + (void)emptyThreadMethod:(id)obj;
@end
@implementation DeadThread
    + (void)enterMultiThreadedMode {
        NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
        [NSThread detachNewThreadSelector:@selector(emptyThreadMethod:)
            toTarget:[DeadThread class] withObject:nil];
        [pool release];
    }
+ (void)emptyThreadMethod:(id)obj { (void)obj; }
@end

bool multiThreader()
{
    [DeadThread enterMultiThreadedMode];
    return [NSThread isMultiThreaded];
}
0

используя QApplication :: exec ().

Единственные другие варианты, которые я могу придумать:

Lazy init, when even the user of your library calls changePos() or destroyPic() then call init() if it hasn't been called yet.

Execute after the event loop using using a single shot timer:

Что-то вроде:

QTimer::singleShot(0, this, SLOT(init()));

Это потребовало бы, чтобы у вас был QObject, и чтобы init или какая-либо другая функция, вызывающая init, были очень полезны. Вызовите это до QApplication :: exec (), и слот будет выполнен после запуска цикла событий.

Похожие вопросы