Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/158.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
QtWebEngine-同步执行JavaScript以读取函数结果 我在C++类中使用了以下方法(使用QtWebEngEngress):_C++_Multithreading_Qt_Callback_Qtwebengine - Fatal编程技术网

QtWebEngine-同步执行JavaScript以读取函数结果 我在C++类中使用了以下方法(使用QtWebEngEngress):

QtWebEngine-同步执行JavaScript以读取函数结果 我在C++类中使用了以下方法(使用QtWebEngEngress):,c++,multithreading,qt,callback,qtwebengine,C++,Multithreading,Qt,Callback,Qtwebengine,执行test()JS函数并返回此调用的结果 不幸的是,回调是异步的,程序崩溃了。如何使其工作?回调是异步的,因为JavaScript执行不仅发生在另一个线程中,而且发生在另一个进程中。因此,没有办法使其完全同步 P>最好的解决方案是将C++代码迁移到异步工作。如果不能做到这一点,唯一可行的解决方案是使用QEventLoop,有点像这样: void ranJavaScript() { emit notifyRanJavaScript(); } QString get() { Q

执行
test()
JS函数并返回此调用的结果


不幸的是,回调是异步的,程序崩溃了。如何使其工作?

回调是异步的,因为JavaScript执行不仅发生在另一个线程中,而且发生在另一个进程中。因此,没有办法使其完全同步

<> P>最好的解决方案是将C++代码迁移到异步工作。如果不能做到这一点,唯一可行的解决方案是使用
QEventLoop
,有点像这样:

void ranJavaScript()
{
    emit notifyRanJavaScript();
}

QString get()
{
    QString result;
    QEventLoop loop;
    QObject::connect(this, SIGNAL(notifyRanJavaScript()), &loop, SLOT(quit()));
    view->page()->runJavaScript("test();", [this](const QVariant &v)
        {
            result = v.toString();
            this.ranJavaScript();
        });

    loop.exec();
    return result;
}
但是,请注意,这个示例对于实际使用来说过于简单:您需要确保在启动事件循环之前没有运行JavaScript。最合适的方法是实现一个合适的插槽,而不是lambda+将对
view->page()->runJavaScript()
的调用分解到另一个插槽中,该插槽在启动事件循环后将被异步调用。对于这样一个看似简单的任务,它需要大量的粘合代码,但这就是它所需要的。下面是一个例子:

main window.h

#ifndef TMP_MAIN_WINDOW_H
#define TMP_MAIN_WINDOW_H

#include <QMainWindow>
#include <QVariant>

class QWebEngineView;
class QPushButton;

class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget * parent = 0);

    QString get();

    void onScriptEnded(const QVariant & data);

Q_SIGNALS:
    void notifyRanJavaScript();

private Q_SLOTS:
    void onButtonPressed();

    void startScript();

private:
    QWebEngineView *    m_view;
    QPushButton *       m_button;
    QString             m_scriptResult;
};

#endif // TMP_MAIN_WINDOW_H
\ifndef TMP\u主窗口
#定义TMP_主窗口
#包括
#包括
QWebEngineView类;
类按钮;
类主窗口:公共QMainWindow
{
Q_对象
公众:
主窗口(QWidget*父窗口=0);
QString get();
脚本无效(常量变量和数据);
Q_信号:
void notifyRanJavaScript();
专用Q_插槽:
void onButtonPressed();
void startScript();
私人:
QWebEngineView*m_视图;
QPushButton*m_按钮;
QString m_脚本结果;
};
#endif//TMP\u主窗口
main window.cpp

#include "MainWindow.h"
#include <QWebEngineView>
#include <QPushButton>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QEventLoop>
#include <QDebug>
#include <QTimer>

MainWindow::MainWindow(QWidget * parent) :
    QMainWindow(parent)
{
    m_view = new QWebEngineView;
    QWebEnginePage * page = new QWebEnginePage(m_view);
    m_view->setPage(page);

    QString html = QStringLiteral("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\""
                                  "\"http://www.w3.org/TR/html4/strict.dtd\"><html>"
                                  "<head><h3>head</h3>\n</head>"
                                  "<script type=\"text/javascript\">function test() { return \"A!\"; }</script>"
                                  "<body>text\n</body></html>");
    m_view->page()->setHtml(html);

    m_button = new QPushButton;
    m_button->setMinimumWidth(35);
    m_button->setText(QStringLiteral("Test"));
    QObject::connect(m_button, SIGNAL(pressed()), this, SLOT(onButtonPressed()));

    QHBoxLayout * buttonLayout = new QHBoxLayout;
    buttonLayout->addWidget(m_button);
    buttonLayout->addStretch();

    QVBoxLayout * viewLayout = new QVBoxLayout;
    viewLayout->addLayout(buttonLayout);
    viewLayout->addWidget(m_view);

    QWidget * widget = new QWidget(this);
    widget->setLayout(viewLayout);

    setCentralWidget(widget);
}

QString MainWindow::get()
{
    QEventLoop loop;
    QObject::connect(this, SIGNAL(notifyRanJavaScript()), &loop, SLOT(quit()));

    // Schedule the slot to run in 0 seconds but not right now
    QTimer::singleShot(0, this, SLOT(startScript()));

    // The event loop would block until onScriptEnded slot is executed
    loop.exec();

    // If we got here, the script has been executed and the result was saved in m_scriptResult
    return m_scriptResult;
}

void MainWindow::onScriptEnded(const QVariant & data)
{
    qDebug() << QStringLiteral("Script ended: ") << data;
    m_scriptResult = data.toString();
    emit notifyRanJavaScript();
}

void MainWindow::onButtonPressed()
{
    QString str = get();
    QMessageBox::information(this, QStringLiteral("Script result"), str,
                             QMessageBox::StandardButton::Ok);
}

struct Functor
{
    Functor(MainWindow & window) : m_window(window) {}
    void operator()(const QVariant & data)
    {
        m_window.onScriptEnded(data);
    }
    MainWindow & m_window;
};

void MainWindow::startScript()
{
    qDebug() << QStringLiteral("Start script");
    m_view->page()->runJavaScript(QStringLiteral("test();"), Functor(*this));
}
#包括“MainWindow.h”
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
主窗口::主窗口(QWidget*父窗口):
QMainWindow(父窗口)
{
m_view=新的QWebEngineView;
QWebEnginePage*页面=新的QWebEnginePage(m_视图);
m_视图->设置页面(第页);
QString html=QStringLiteral(“”)
“头\n”
“函数测试(){return\'A!\';}”
“文本”;
m_view->page()->setHtml(html);
m_按钮=新的QPushButton;
m_按钮->设置最小宽度(35);
m_按钮->设置文本(QStringLiteral(“测试”);
QObject::connect(m_按钮,信号(按下()),此,插槽(onButtonPressed());
QHBoxLayout*按钮布局=新的QHBoxLayout;
按钮布局->添加小部件(m_按钮);
按钮布局->添加拉伸();
QVBoxLayout*viewLayout=新的QVBoxLayout;
视图布局->添加布局(按钮布局);
viewLayout->addWidget(m_视图);
QWidget*widget=新的QWidget(此);
小部件->设置布局(视图布局);
setCentralWidget(小部件);
}
QString主窗口::get()
{
QEventLoop循环;
连接(this,信号(notifyRanJavaScript()),&循环,插槽(quit());
//计划插槽在0秒内运行,但不是现在
QTimer::singleShot(0,this,SLOT(startScript());
//事件循环将一直阻塞,直到执行onScriptEnded插槽
loop.exec();
//如果我们到达这里,脚本已经执行,结果保存在m_scriptResult中
返回m_脚本结果;
}
void主窗口::onscriptend(常量变量和数据)
{

不幸的是,qDebug()Dmitry的解决方案只能部分起作用。在他的示例中,在按下按钮时调用代码。但是,如果在加载窗口时移动相同的代码以执行,则永远不会调用完成的脚本(onScriptEnded)的槽。为了解决这个问题,我必须将调用包装到JS本身的求值中(在我的项目中称为evaluateJavaScript)在另一个QTimer::singleShot中:

QTimer::singleShot(0, this, [&] { evaluateJavaScript(); });
不幸的是,在我的实际项目中,我有很多电话,通常是一个评估等待另一个评估完成。几乎不可能每次都使用这个,所以我仍然在寻找解决方案。

<>这比从JS调用C++函数简单得多,只需使用RunJavaScript传递函数作为如下参数:

view->page()->runJavaScript("jsfun();",[this](const QVariant &v) { qDebug()<<v.toString();});
view->page()->runJavaScript(“jsfun();”,[this](const QVariant&v){qDebug()在项目中,我发现了一种非常简单的方法来等待runJavaScript函数的结果。它是从QWebEngineView继承的一部分

int ViewWindow::getScrollbarPosition()
{
    QAtomicInt value = -1;

    page()->runJavaScript("document.body.scrollTop", [&value](const QVariant &v)
        {
            qDebug( "value retrieved: %d\n", v.toInt());
            value = v.toInt();
        });

    while (value == -1)
    {
        QApplication::processEvents();
    }

    qDebug( "scroll value %d", value.load() );
    return value;
}

谢谢,它看起来不错,但似乎不起作用。它正在循环中获取堆栈。exec();-这还没有结束。我将视图更改为指针(而不是引用)但这不重要。用我已经测试过的示例替换了这个示例。它工作得非常好!非常感谢。我也使用std mutex和cond.var以及阻塞队列完成了这项工作。但我必须生成新线程,因为事实上,调用runJavaScript的线程和执行回调的线程是相同的线程…我在usin中检查了这个g std::this_thread::id-这些不是不同的进程(如您所写),而是完全相同的线程。无论如何,您的解决方案是真正同步的,所以正是我所需要的。干杯!我没有说回调是在不同的进程中执行的。我说的是JavaScript代码(作为
runJavaScript
的参数)是执行的(真正的JIT编译和执行)在另一个名为
QWebEngineProcess
的进程中。
int ViewWindow::getScrollbarPosition()
{
    QAtomicInt value = -1;

    page()->runJavaScript("document.body.scrollTop", [&value](const QVariant &v)
        {
            qDebug( "value retrieved: %d\n", v.toInt());
            value = v.toInt();
        });

    while (value == -1)
    {
        QApplication::processEvents();
    }

    qDebug( "scroll value %d", value.load() );
    return value;
}