Привет всем, я хочу обновить пользовательский интерфейс из функции, не являющейся членом. Любая помощь, кроме передачи указателя this в качестве моего не члена, является обратным вызовом из библиотеки.
Ниже мой код:
mainwindow.cpp
static void callback(QString result)
{
ui->textBrowser->append(result);
}
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
int a=1,b=2;
QLibrary myLib("myaddlib");
myLib.load();
add = (myadd)myLib.resolve("add_function");
add(callback, a, b);
}
Так что все, что мне нужно, это то, что я должен иметь возможность добавлять данные в пользовательский интерфейс из моего не члена обратного вызова. Пожалуйста, помогите мне.
РЕДАКТИРОВАТЬ: мне не разрешено изменять мой обратный вызов
РЕДАКТИРОВАТЬ на основе комментария: callback
будет вызван в другом потоке, поэтому вызов метода виджета оттуда дает ошибку 'cannot send events to objects owned by a different thread'
Исходя из вашего комментария
«Я пытался создать глобальный указатель Ui :: MainWindow * myui и назначил
Мой пользовательский интерфейс в конструкторе, но он выдает мне следующую ошибку:
‘не может отправлять события объектам, принадлежащим другому потоку’. «
Проблема в том, что ваш callback
вызывается не в той ветке. Вот одно из решений:
Создайте глобальный указатель на фактический экземпляр главного окна, назовем его MainWindow *mainWinInstance;
, Также будьте осторожны, что экземпляр основного окна будет жить дольше, чем библиотека / поток, для которого предназначен обратный вызов, или используйте QPointer
если есть риск, что callback
вызывается даже после разрушения главного окна.
Добавьте следующий метод слота в MainWindow
:
MainWindow::appendText(const QString &text) { // use const ref for efficiency
ui->textBrowser->append(result);
}
Измени свой callback
чтобы вызвать этот метод, используя QMetaObject::invokeMethod
используя тип подключения в очереди:
static void callback(QString result) {
bool r = QMetaObject::invokeMethod(mainWinInstance,
"appendText",
Qt::QueuedConnection,
Q_ARG(QString, result));
Q_ASSERT(r); // should only fail if there's a mistake in above code
}
С помощью Qt::QueuedConnection
это важно. Он поместит вызов метода в очередь событий правильного потока целевого объекта и немедленно вернется. Цикл событий целевого потока будет затем выполнять фактический вызов.
Вам нужно создать интерфейс в отдельном заголовке:
itextbrowseraccessor.h
class ITextBrowserAccessor
{
public:
void appendText(const QString& text) = 0;
}
унаследовать MainWindow
от ITextBrowserAccessor
и реализовать метод:
void MainWindow::appendText(const QString& text)
{
ui->textBrowser->append(text);
}
Включают itextbrowseraccessor.h
в исходном файле вашей библиотеки. Передайте указатель на интерфейс для обратного вызова.
static void callback(ITextBrowserAccessor* accessor, QString result)
{
accessor->appendText(result);
}
Вы можете попытаться найти главное окно, используя QApplication::topLevelWidgets()
,
Как только вы нашли главное окно, используйте mainWindow->findChild<QTextBrowser*>()
найти виджет браузера, а затем изменить его содержимое по мере необходимости.
РЕДАКТИРОВАТЬ:
пример:
Q_ASSERT(QApplication::topLevelWidgets() == 1);
QWidget* mainWindow = QApplication::topLevelWidgets().first();
QTextEditor* editor = mainWindow->findChild<QTextBrowser*>();
Q_ASSERT(editor != NULL);
editor->append(QLatin1String("abc"));
Ничто из того, что было здесь упомянуто, не сработало.
Решил это, создав фиктивный объект Qobject, который имеет публичную функцию для отправки сигнала в главное окно. Создайте экземпляр этого фиктивного объекта qobject и вызовите публичную функцию внутри моего обратного вызова.
PS: у меня есть ограничение не изменять мой обратный вызов, следовательно, вышеупомянутое решение.