WebEngine ウィジェット シンプルなブラウザの例

Qt WebEngine ウィジェットをベースにしたシンプルなブラウザです。

Simple Browserは、Qt WebEngine C++ classes を使用して、以下の要素を含む小さなウェブブラウザアプリケーションを開発する方法を示します:

  • 保存されたページを開いたり、ウィンドウやタブを管理するためのメニューバー
  • URLを入力したり、ウェブページの閲覧履歴を前後に移動したりするためのナビゲーションバー。
  • タブ内にウェブコンテンツを表示するためのマルチタブエリア。
  • ホバーされたリンクを表示するステータスバー
  • シンプルなダウンロードマネージャー

ウェブコンテンツは、新しいタブまたは別のウィンドウで開くことができます。ウェブページへのアクセスにHTTP認証とプロキシ認証を使用できます。

サンプルを実行する

Qt Creator からサンプルを実行するには、Welcome モードを開き、Examples からサンプルを選択します。詳細は、Building and Running an Example を参照してください。

クラス階層

まず、これから実装する主なクラスをスケッチします:

  • Browser はアプリケーションのウィンドウを管理するクラスです。
  • BrowserWindow は 、メニュー、ナビゲーション・バー、 、ステータス・バーを示します。QMainWindow TabWidget
  • TabWidget は で、1 つまたは複数のブラウザー・タブを含みます。QTabWidget
  • WebView は で、 のビューを提供し、 のタブとして追加されます。QWebEngineView WebPage TabWidget
  • WebPage は で、ウェブサイトのコンテンツを表します。QWebEnginePage

さらに、いくつかの補助クラスを実装します:

  • WebPopupWindow は、ポップアップ・ウィンドウを表示するための です。QWidget
  • DownloadManagerWidget はダウンロードリストを実装する です。QWidget

ブラウザのメインウィンドウの作成

この例では、Browser オブジェクトが所有する複数のメインウィンドウをサポートしています。このクラスは、DownloadManagerWidget も所有し、ブックマークや履歴マネージャなどのさらなる機能にも使用できます。

main.cpp で、最初のBrowserWindow インスタンスを作成し、Browser オブジェクトに追加します。コマンドラインに引数が渡されなければ、Qtホームページを開きます:

int main(int argc, char **argv)
{
    QCoreApplication::setOrganizationName("QtExamples");

    QApplication app(argc, argv);
    app.setWindowIcon(QIcon(u":AppLogoColor.png"_s));
    QLoggingCategory::setFilterRules(u"qt.webenginecontext.debug=true"_s);

    QWebEngineProfile::defaultProfile()->settings()->setAttribute(QWebEngineSettings::PluginsEnabled, true);
    QWebEngineProfile::defaultProfile()->settings()->setAttribute(QWebEngineSettings::DnsPrefetchEnabled, true);
    QWebEngineProfile::defaultProfile()->settings()->setAttribute(
            QWebEngineSettings::ScreenCaptureEnabled, true);

    QUrl url = commandLineUrlArgument();

    Browser browser;
    BrowserWindow *window = browser.createHiddenWindow();
    window->tabWidget()->setUrl(url);
    window->show();
    return app.exec();
}

ウィンドウをOpenGLレンダリングに切り替えたときのちらつきを抑えるため、最初のブラウザ・タブが追加された後にshowを呼び出します。

タブの作成

BrowserWindow コンストラクタは、必要なユーザーインターフェース関連オブジェクトをすべて初期化します。BrowserWindowcentralWidget にはTabWidget のインスタンスが含まれます。TabWidget には、1つまたは複数のWebView インスタンスがタブとして含まれ、現在選択されているものにシグナルとスロットを委譲します:

class TabWidget : public QTabWidget
{
    ...
signals:
    // current tab/page signals
    void linkHovered(const QString &link);
    void loadProgress(int progress);
    void titleChanged(const QString &title);
    void urlChanged(const QUrl &url);
    void favIconChanged(const QIcon &icon);
    void webActionEnabledChanged(QWebEnginePage::WebAction action, bool enabled);
    void devToolsRequested(QWebEnginePage *source);
    void findTextFinished(const QWebEngineFindTextResult &result);

public slots:
    // current tab/page slots
    void setUrl(const QUrl &url);
    void triggerWebPageAction(QWebEnginePage::WebAction action);
    ...
};

各タブはWebView のインスタンスを含む:

WebView *TabWidget::createTab()
{
    WebView *webView = createBackgroundTab();
    setCurrentWidget(webView);
    return webView;
}

WebView *TabWidget::createBackgroundTab()
{
    WebView *webView = new WebView;
    WebPage *webPage = new WebPage(m_profile, webView);
    webView->setPage(webPage);
    setupView(webView);
    int index = addTab(webView, tr("(Untitled)"));
    setTabIcon(index, webView->favIcon());
    // Workaround for QTBUG-61770
    webView->resize(currentWidget()->size());
    webView->show();
    return webView;
}

TabWidget::setupView() では、TabWidget が常に現在選択されているWebView のシグナルを転送するようにしています:

void TabWidget::setupView(WebView *webView)
{
    QWebEnginePage *webPage = webView->page();

    connect(webView, &QWebEngineView::titleChanged, [this, webView](const QString &title) {
        int index = indexOf(webView);
        if (index != -1) {
            setTabText(index, title);
            setTabToolTip(index, title);
        }
        if (currentIndex() == index)
            emit titleChanged(title);
    });
    connect(webView, &QWebEngineView::urlChanged, [this, webView](const QUrl &url) {
        int index = indexOf(webView);
        if (index != -1)
            tabBar()->setTabData(index, url);
        if (currentIndex() == index)
            emit urlChanged(url);
    });
    connect(webView, &QWebEngineView::loadProgress, [this, webView](int progress) {
        if (currentIndex() == indexOf(webView))
            emit loadProgress(progress);
    });
    connect(webPage, &QWebEnginePage::linkHovered, [this, webView](const QString &url) {
        if (currentIndex() == indexOf(webView))
            emit linkHovered(url);
    });
    connect(webView, &WebView::favIconChanged, [this, webView](const QIcon &icon) {
        int index = indexOf(webView);
        if (index != -1)
            setTabIcon(index, icon);
        if (currentIndex() == index)
            emit favIconChanged(icon);
    });
    connect(webView, &WebView::webActionEnabledChanged, [this, webView](QWebEnginePage::WebAction action, bool enabled) {
        if (currentIndex() ==  indexOf(webView))
            emit webActionEnabledChanged(action,enabled);
    });
    connect(webPage, &QWebEnginePage::windowCloseRequested, [this, webView]() {
        int index = indexOf(webView);
        if (webView->page()->inspectedPage())
            window()->close();
        else if (index >= 0)
            closeTab(index);
    });
    connect(webView, &WebView::devToolsRequested, this, &TabWidget::devToolsRequested);
    connect(webPage, &QWebEnginePage::findTextFinished, [this, webView](const QWebEngineFindTextResult &result) {
        if (currentIndex() == indexOf(webView))
            emit findTextFinished(result);
    });
}

タブを閉じる

ユーザーがタブを閉じると、まず対応するWebViewRequestClose Web アクションをトリガーします:

    connect(tabBar, &QTabBar::tabCloseRequested, [this](int index) {
        if (WebView *view = webView(index))
            view->page()->triggerAction(QWebEnginePage::WebAction::RequestClose);
    });

これにより、JavaScript のbeforeunload イベントリスナーが起動し、ページを閉じるかどうかを確認するダイアログが表示されます。この場合、ユーザーは閉じる要求を拒否し、タブを開いたままにすることができます。そうでなければ、windowCloseRequested シグナルが発せられ、タブを閉じます:

    connect(webPage, &QWebEnginePage::windowCloseRequested, [this, webView]() {
        int index = indexOf(webView);
        if (webView->page()->inspectedPage())
            window()->close();
        else if (index >= 0)
            closeTab(index);
    });

WebView 機能の実装

WebViewQWebEngineView から派生したもので、以下の機能をサポートしています:

  • renderProcess が終了した場合のエラーメッセージの表示
  • createWindow リクエストの処理
  • コンテキストメニューへのカスタムメニュー項目の追加

まず、必要なメソッドとシグナルを持つWebView を作成します:

class WebView : public QWebEngineView
{
    Q_OBJECT

public:
    explicit WebView(QWidget *parent = nullptr);
    ...
protected:
    void contextMenuEvent(QContextMenuEvent *event) override;
    QWebEngineView *createWindow(QWebEnginePage::WebWindowType type) override;

signals:
    void webActionEnabledChanged(QWebEnginePage::WebAction webAction, bool enabled);
    ...
};
エラーメッセージの表示

レンダリング処理が終了した場合は、エラーコードとともにQMessageBox を表示し、ページを再読み込みします:

WebView::WebView(QWidget *parent)
    : QWebEngineView(parent)
{
    ...
    connect(this, &QWebEngineView::renderProcessTerminated,
            [this](QWebEnginePage::RenderProcessTerminationStatus termStatus, int statusCode) {
        QString status;
        switch (termStatus) {
        case QWebEnginePage::NormalTerminationStatus:
            status = tr("Render process normal exit");
            break;
        case QWebEnginePage::AbnormalTerminationStatus:
            status = tr("Render process abnormal exit");
            break;
        case QWebEnginePage::CrashedTerminationStatus:
            status = tr("Render process crashed");
            break;
        case QWebEnginePage::KilledTerminationStatus:
            status = tr("Render process killed");
            break;
        }
        QMessageBox::StandardButton btn = QMessageBox::question(window(), status,
                                                   tr("Render process exited with code: %1\n"
                                                      "Do you want to reload the page ?").arg(statusCode));
        if (btn == QMessageBox::Yes)
            QTimer::singleShot(0, this, &WebView::reload);
    });
}
WebWindows の管理

QWebEnginePage::WebWindowTypeたとえば、JavaScript プログラムが新しいウィンドウやダイアログでドキュメントを開くように要求した場合などです。この場合はQWebView::createWindow() をオーバーライドします:

QWebEngineView *WebView::createWindow(QWebEnginePage::WebWindowType type)
{
    BrowserWindow *mainWindow = qobject_cast<BrowserWindow*>(window());
    if (!mainWindow)
        return nullptr;

    switch (type) {
    case QWebEnginePage::WebBrowserTab: {
        return mainWindow->tabWidget()->createTab();
    }

QWebEnginePage::WebDialog の場合、WebPopupWindow クラスのインスタンスを作成します:

class WebPopupWindow : public QWidget
{
    Q_OBJECT

public:
    explicit WebPopupWindow(QWebEngineProfile *profile);
    WebView *view() const;

private slots:
    void handleGeometryChangeRequested(const QRect &newGeometry);

private:
    QLineEdit *m_urlLineEdit;
    QAction *m_favAction;
    WebView *m_view;
};
コンテキストメニュー項目の追加

コンテキストメニューにメニュー項目を追加して、ユーザが右クリックでインスペクタを新しいウィンドウで開けるようにします。QWebEngineView::contextMenuEvent をオーバーライドし、QWebEnginePage::createStandardContextMenu を使用して、QWebEnginePage::WebAction アクションのデフォルトリストを持つデフォルトのQMenu を作成します。

QWebEnginePage::InspectElement アクションのデフォルト名はInspect です。わかりやすくするために、インスペクタがまだ存在しない場合はOpen Inspector In New Window に、すでに作成されている場合はInspect Element に名前を変更します。

また、QWebEnginePage::ViewSource アクションがメニューにあるかどうかもチェックする。もしなければ、セパレーターも追加しなければならないからだ。

void WebView::contextMenuEvent(QContextMenuEvent *event)
{
    QMenu *menu = createStandardContextMenu();
    const QList<QAction *> actions = menu->actions();
    auto inspectElement = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::InspectElement));
    if (inspectElement == actions.cend()) {
        auto viewSource = std::find(actions.cbegin(), actions.cend(), page()->action(QWebEnginePage::ViewSource));
        if (viewSource == actions.cend())
            menu->addSeparator();

        QAction *action = menu->addAction("Open inspector in new window");
        connect(action, &QAction::triggered, [this]() { emit devToolsRequested(page()); });
    } else {
        (*inspectElement)->setText(tr("Inspect element"));
    }

    // add conext menu for image policy
    QMenu *editImageAnimation = new QMenu(tr("Image animation policy"));

    m_imageAnimationGroup = new QActionGroup(editImageAnimation);
    m_imageAnimationGroup->setExclusive(true);

    QAction *disableImageAnimation =
            editImageAnimation->addAction(tr("Disable all image animation"));
    disableImageAnimation->setCheckable(true);
    m_imageAnimationGroup->addAction(disableImageAnimation);
    connect(disableImageAnimation, &QAction::triggered, [this]() {
        handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::Disallow);
    });
    QAction *allowImageAnimationOnce =
            editImageAnimation->addAction(tr("Allow animated images, but only once"));
    allowImageAnimationOnce->setCheckable(true);
    m_imageAnimationGroup->addAction(allowImageAnimationOnce);
    connect(allowImageAnimationOnce, &QAction::triggered,
            [this]() { handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::AnimateOnce); });
    QAction *allowImageAnimation = editImageAnimation->addAction(tr("Allow all animated images"));
    allowImageAnimation->setCheckable(true);
    m_imageAnimationGroup->addAction(allowImageAnimation);
    connect(allowImageAnimation, &QAction::triggered, [this]() {
        handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy::Allow);
    });

    switch (page()->settings()->imageAnimationPolicy()) {
    case QWebEngineSettings::ImageAnimationPolicy::Allow:
        allowImageAnimation->setChecked(true);
        break;
    case QWebEngineSettings::ImageAnimationPolicy::AnimateOnce:
        allowImageAnimationOnce->setChecked(true);
        break;
    case QWebEngineSettings::ImageAnimationPolicy::Disallow:
        disableImageAnimation->setChecked(true);
        break;
    default:
        allowImageAnimation->setChecked(true);
        break;
    }

    menu->addMenu(editImageAnimation);
    menu->popup(event->globalPos());
}

WebPageとWebView機能の実装

QWebEnginePage のサブクラスとしてWebPage を実装し、QWebEngineView のサブクラスとしてWebView を実装して、HTTP、プロキシ認証、およびウェブページへのアクセス時の SSL 証明書エラーの無視を有効にします:

class WebPage : public QWebEnginePage
{
    Q_OBJECT

public:
    explicit WebPage(QWebEngineProfile *profile, QObject *parent = nullptr);

signals:
    void createCertificateErrorDialog(QWebEngineCertificateError error);

private slots:
    void handleCertificateError(QWebEngineCertificateError error);
    void handleSelectClientCertificate(QWebEngineClientCertificateSelection clientCertSelection);
    void handleDesktopMediaRequest(const QWebEngineDesktopMediaRequest &request);
};

class WebView : public QWebEngineView
{
    Q_OBJECT

public:
    explicit WebView(QWidget *parent = nullptr);
    ~WebView();
    void setPage(WebPage *page);

    int loadProgress() const;
    bool isWebActionEnabled(QWebEnginePage::WebAction webAction) const;
    QIcon favIcon() const;

protected:
    void contextMenuEvent(QContextMenuEvent *event) override;
    QWebEngineView *createWindow(QWebEnginePage::WebWindowType type) override;

signals:
    void webActionEnabledChanged(QWebEnginePage::WebAction webAction, bool enabled);
    void favIconChanged(const QIcon &icon);
    void devToolsRequested(QWebEnginePage *source);
private slots:
    void handleCertificateError(QWebEngineCertificateError error);
    void handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth);
    void handlePermissionRequested(QWebEnginePermission permission);
    void handleProxyAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth,
                                           const QString &proxyHost);
    void handleRegisterProtocolHandlerRequested(QWebEngineRegisterProtocolHandlerRequest request);
#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0)
    void handleFileSystemAccessRequested(QWebEngineFileSystemAccessRequest request);
    void handleWebAuthUxRequested(QWebEngineWebAuthUxRequest *request);
#endif
    void handleImageAnimationPolicyChange(QWebEngineSettings::ImageAnimationPolicy policy);

private:
    void createWebActionTrigger(QWebEnginePage *page, QWebEnginePage::WebAction);
    void onStateChanged(QWebEngineWebAuthUxRequest::WebAuthUxState state);

private:
    int m_loadProgress = 100;
    WebAuthDialog *m_authDialog = nullptr;
    QActionGroup *m_imageAnimationGroup = nullptr;
};

上記のすべての場合において、適切なダイアログをユーザーに表示します。認証の場合、QAuthenticator オブジェクトに正しいクレデンシャル値を設定する必要があります:

void WebView::handleAuthenticationRequired(const QUrl &requestUrl, QAuthenticator *auth)
{
    QDialog dialog(window());
    dialog.setModal(true);
    dialog.setWindowFlags(dialog.windowFlags() & ~Qt::WindowContextHelpButtonHint);

    Ui::PasswordDialog passwordDialog;
    passwordDialog.setupUi(&dialog);

    passwordDialog.m_iconLabel->setText(QString());
    QIcon icon(window()->style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, window()));
    passwordDialog.m_iconLabel->setPixmap(icon.pixmap(32, 32));

    QString introMessage(tr("Enter username and password for \"%1\" at %2")
                                 .arg(auth->realm(),
                                      requestUrl.toString().toHtmlEscaped()));
    passwordDialog.m_infoLabel->setText(introMessage);
    passwordDialog.m_infoLabel->setWordWrap(true);

    if (dialog.exec() == QDialog::Accepted) {
        auth->setUser(passwordDialog.m_userNameLineEdit->text());
        auth->setPassword(passwordDialog.m_passwordLineEdit->text());
    } else {
        // Set authenticator null if dialog is cancelled
        *auth = QAuthenticator();
    }
}

handleProxyAuthenticationRequired シグナル・ハンドラは、HTTPプロキシの認証とまったく同じ手順を実装しています。

SSLエラーが発生した場合、メインフレームから発生したのか、ページ内のリソースから発生したのかを確認します。リソースのエラーは自動的に証明書拒否をトリガーします。それ以外のケースでは、ユーザが証明書を許可または拒否できるダイアログを表示します。

void WebPage::handleCertificateError(QWebEngineCertificateError error)
{
    // Automatically block certificate errors from page resources without prompting the user.
    // This mirrors the behavior found in other major browsers.
    if (!error.isMainFrame()) {
        error.rejectCertificate();
        return;
    }

    error.defer();
    QTimer::singleShot(0, this,
                       [this, error]() mutable { emit createCertificateErrorDialog(error); });
}

ウェブ・ページを開く

このセクションでは、新しいページを開くワークフローについて説明します。ユーザーがナビゲーション・バーに URL を入力し、Enter を押すと、QLineEdit::returnPressed シグナルが発信され、新しい URL がTabWidget::setUrl に引き渡される:

BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools)
{
    ...
        connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() {
            m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text()));
        });
    ...
}

呼び出しは現在選択されているタブに転送される:

void TabWidget::setUrl(const QUrl &url)
{
    if (WebView *view = currentWebView()) {
        view->setUrl(url);
        view->setFocus();
    }
}

WebViewsetUrl() メソッドは、url を関連するWebPage に転送するだけで、 はバックグラウンドでページのコンテンツのダウンロードを開始する。

プライベートブラウジングの実装

プライベートブラウジングインコグニートモード、または記録外モードは、多くのブラウザの機能で、クッキー、HTTP キャッシュ、または閲覧履歴のような、通常は永続的なデータがメモリ上にのみ保持され、ディスク上には痕跡を残しません。この例では、ウィンドウ・レベルでプライベート・ブラウジングを実装します。あるいは、タブレベルでプライベートブラウジングを実装し、ウィンドウ内のいくつかのタブを通常モードに、他のタブをプライベートモードにすることもできます。

プライベートブラウジングの実装は、Qt WebEngine を使えばとても簡単です。新しいQWebEngineProfile を作成し、デフォルトのプロファイルの代わりにQWebEnginePage で使用するだけです。この例では、この新しいプロファイルはBrowser オブジェクトが所有しています:

class Browser
{
public:
    ...
    BrowserWindow *createHiddenWindow(bool offTheRecord = false);
    BrowserWindow *createWindow(bool offTheRecord = false);
private:
    ...
    QScopedPointer<QWebEngineProfile> m_profile;
};

プライベートブラウジングに必要なプロファイルは、最初のウィンドウと一緒に作成されます。QWebEngineProfile のデフォルトのコンストラクタは、すでにそれをオフレコ・モードにしています。

BrowserWindow *Browser::createHiddenWindow(bool offTheRecord)
{
    if (!offTheRecord && !m_profile) {
        const QString name = u"simplebrowser."_s + QLatin1StringView(qWebEngineChromiumVersion());
        m_profile.reset(new QWebEngineProfile(name));
    ...

あとは適切なプロファイルを適切なQWebEnginePage オブジェクトに渡すだけです。Browser オブジェクトは、グローバル・デフォルト・プロファイル(QWebEngineProfile::defaultProfile を参照)か、共有のオフ・ザ・レコード・プロファイル・インスタンスのいずれかを、新しいBrowserWindow に渡します:

    ...
        QObject::connect(m_profile.get(), &QWebEngineProfile::downloadRequested,
                         &m_downloadManagerWidget, &DownloadManagerWidget::downloadRequested);
    }
    auto profile = !offTheRecord ? m_profile.get() : QWebEngineProfile::defaultProfile();
    auto mainWindow = new BrowserWindow(this, profile, false);
    return mainWindow;
}

BrowserWindowTabWidget オブジェクトは、ウィンドウに含まれるすべてのQWebEnginePage オブジェクトがこのプロファイルを使用するようにします。

ダウンロードの管理

ダウンロードはQWebEngineProfile に関連付けられます。ウェブページでダウンロードがトリガーされると、QWebEngineProfile::downloadRequested シグナルがQWebEngineDownloadRequest とともに発信され、この例ではDownloadManagerWidget::downloadRequested に転送されます:

Browser::Browser()
{
    // Quit application if the download manager window is the only remaining window
    m_downloadManagerWidget.setAttribute(Qt::WA_QuitOnClose, false);

    QObject::connect(
        QWebEngineProfile::defaultProfile(), &QWebEngineProfile::downloadRequested,
        &m_downloadManagerWidget, &DownloadManagerWidget::downloadRequested);
}

このメソッドは、ユーザーにファイル名の入力を促し(事前に入力された候補が表示されます)、ダウンロードを開始します(ユーザーがSave As ダイアログをキャンセルしない限り):

void DownloadManagerWidget::downloadRequested(QWebEngineDownloadRequest *download)
{
    Q_ASSERT(download && download->state() == QWebEngineDownloadRequest::DownloadRequested);

    QString path = QFileDialog::getSaveFileName(this, tr("Save as"), QDir(download->downloadDirectory()).filePath(download->downloadFileName()));
    if (path.isEmpty())
        return;

    download->setDownloadDirectory(QFileInfo(path).path());
    download->setDownloadFileName(QFileInfo(path).fileName());
    download->accept();
    add(new DownloadWidget(download));

    show();
}

QWebEngineDownloadRequest オブジェクトは、潜在的なオブザーバーにダウンロードの進行状況を通知するためにreceivedBytesChanged シグナルを定期的に発信し、ダウンロードが終了したときやエラーが発生したときにはstateChanged シグナルを発信する。これらのシグナルの処理方法の例については、downloadmanagerwidget.cpp を参照してください。

WebAuth/FIDO UXリクエストの管理

WebAuth UXリクエストはQWebEnginePage 。認証機関がユーザーとの対話を要求するたびに、QWebEnginePage で UX リクエストがトリガーされ、QWebEngineWebAuthUxRequestQWebEnginePage::webAuthUxRequested シグナルが発行されます。この例では、WebView::handleAuthenticatorRequired に転送されます:

    connect(page, &QWebEnginePage::webAuthUxRequested, this, &WebView::handleWebAuthUxRequested);

このメソッドは WebAuth UX ダイアログを生成し、UX リクエストフローを開始する。

void WebView::handleWebAuthUxRequested(QWebEngineWebAuthUxRequest *request)
{
    if (m_authDialog)
        delete m_authDialog;

    m_authDialog = new WebAuthDialog(request, window());
    m_authDialog->setModal(false);
    m_authDialog->setWindowFlags(m_authDialog->windowFlags() & ~Qt::WindowContextHelpButtonHint);

    connect(request, &QWebEngineWebAuthUxRequest::stateChanged, this, &WebView::onStateChanged);
    m_authDialog->show();
}

QWebEngineWebAuthUxRequest オブジェクトはstateChanged シグナルを定期的に発信し、潜在的なオブザーバに現在の WebAuth UX の状態を通知します。オブザーバはそれに応じて WebAuth ダイアログを更新する。これらのシグナルの処理方法の例については、webview.cppwebauthdialog.cpp を参照してください。

macOS の署名要件

macOS上でSimple Browserを動作させるときに、Webサイトが位置情報、カメラ、マイクにアクセスできるようにするには、アプリケーションに署名する必要があります。これはビルド時に自動的に行われますが、ビルド環境に有効な署名IDを設定する必要があります。

ファイルと属性

この例ではTango Icon Libraryのアイコンを使用しています:

Tangoアイコンライブラリパブリックドメイン

サンプルプロジェクト @ code.qt.io

©2024 The Qt Company Ltd. 本書に含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。