WebEngine Widgets Einfacher Browser Beispiel
Ein einfacher Browser, der auf Qt WebEngine Widgets basiert.
Simple Browser demonstriert, wie man mit der Qt WebEngine C++ classes um eine kleine Webbrowser-Anwendung zu entwickeln, die die folgenden Elemente enthält:
- Menüleiste zum Öffnen gespeicherter Seiten und zur Verwaltung von Fenstern und Registerkarten.
- Navigationsleiste zur Eingabe einer URL und zum Zurück- und Vorwärtsbewegen in der Webseiten-Browsing-Historie.
- Multi-Tab-Bereich für die Anzeige von Webinhalten innerhalb von Tabs.
- Statusleiste für die Anzeige von Links, über die man den Mauszeiger bewegt.
- Ein einfacher Download-Manager.
Der Webinhalt kann in neuen Tabs oder separaten Fenstern geöffnet werden. HTTP und Proxy-Authentifizierung können für den Zugriff auf Webseiten verwendet werden.
Ausführen des Beispiels
Zum Ausführen des Beispiels von Qt Creatorzu starten, öffnen Sie den Modus Welcome und wählen Sie das Beispiel unter Examples aus. Weitere Informationen finden Sie unter Erstellen und Ausführen eines Beispiels.
Klassenhierarchie
Wir beginnen mit der Skizzierung eines Diagramms der wichtigsten Klassen, die wir implementieren werden:
Browser
ist eine Klasse, die die Anwendungsfenster verwaltet.BrowserWindow
ist eine QMainWindow, die das Menü, eine Navigationsleiste,TabWidget
und eine Statusleiste enthält.TabWidget
ist eine QTabWidget und enthält eine oder mehrere Browser-Registerkarten.WebView
ist eine QWebEngineView, bietet eine Ansicht fürWebPage
und wird als Registerkarte inTabWidget
hinzugefügt.WebPage
ist eine QWebEnginePage, die den Inhalt der Website darstellt.
Zusätzlich werden wir einige Hilfsklassen implementieren:
WebPopupWindow
ist eine QWidget für die Anzeige von Popup-Fenstern.DownloadManagerWidget
ist eine QWidget, die die Liste der Downloads implementiert.
Erstellen des Browser-Hauptfensters
Dieses Beispiel unterstützt mehrere Hauptfenster, die im Besitz eines Browser
Objekts sind. Diese Klasse besitzt auch die DownloadManagerWidget
und kann für weitere Funktionen wie Lesezeichen und Verlaufsmanager verwendet werden.
In main.cpp
erstellen wir die erste Instanz BrowserWindow
und fügen sie dem Objekt Browser
hinzu. Wenn keine Argumente auf der Kommandozeile übergeben werden, öffnen wir die Qt Homepage:
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(); }
Um ein Flackern beim Umschalten des Fensters auf OpenGL-Rendering zu unterdrücken, rufen wir show auf, nachdem der erste Browser-Tab hinzugefügt wurde.
Tabs erstellen
Der BrowserWindow
Konstruktor initialisiert alle notwendigen Objekte der Benutzeroberfläche. Das centralWidget
von BrowserWindow
enthält eine Instanz von TabWidget
. Das TabWidget
enthält eine oder mehrere Instanzen von WebView
als Tabs und delegiert seine Signale und Slots an den aktuell ausgewählten Tab:
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); ... };
Jede Registerkarte enthält eine Instanz von 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; }
In TabWidget::setupView()
sorgen wir dafür, dass TabWidget
immer die Signale des aktuell ausgewählten WebView
weiterleitet:
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); }); }
Schließen von Tabs
Wenn der Benutzer eine Registerkarte schließt, lösen wir zunächst die RequestClose Web-Aktion auf der entsprechenden WebView
aus:
connect(tabBar, &QTabBar::tabCloseRequested, [this](int index) { if (WebView *view = webView(index)) view->page()->triggerAction(QWebEnginePage::WebAction::RequestClose); });
Dies ermöglicht das Auslösen von JavaScript beforeunload
Event-Listenern, die den Benutzer mit einem Dialog auffordern können, zu bestätigen, dass er die Seite schließen möchte. In diesem Fall kann der Benutzer die Aufforderung zum Schließen ablehnen und die Registerkarte offen lassen, andernfalls wird das Signal windowCloseRequested ausgelöst und die Registerkarte geschlossen:
connect(webPage, &QWebEnginePage::windowCloseRequested, [this, webView]() { int index = indexOf(webView); if (webView->page()->inspectedPage()) window()->close(); else if (index >= 0) closeTab(index); });
WebView-Funktionalität implementieren
WebView
wird von QWebEngineView abgeleitet, um die folgenden Funktionen zu unterstützen:
- Anzeige von Fehlermeldungen, falls
renderProcess
abstürzt - Behandlung von
createWindow
Anfragen - Hinzufügen von benutzerdefinierten Menüpunkten zu Kontextmenüs
Zuerst erstellen wir WebView mit den notwendigen Methoden und Signalen:
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); ... };
Anzeige von Fehlermeldungen
Wenn der Rendervorgang abgebrochen wird, zeigen wir eine QMessageBox mit einem Fehlercode an und laden dann die Seite neu:
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 verwalten
Die geladene Seite kann Fenster des Typs QWebEnginePage::WebWindowType erzeugen, z. B. wenn ein JavaScript-Programm ein Dokument in einem neuen Fenster oder Dialog öffnen möchte. Dies wird durch Überschreiben von QWebView::createWindow()
gehandhabt:
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(); }
Im Fall von QWebEnginePage::WebDialog
erstellen wir eine Instanz einer benutzerdefinierten Klasse 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; };
Hinzufügen von Kontextmenüpunkten
Wir fügen dem Kontextmenü einen Menüpunkt hinzu, so dass die Benutzer mit der rechten Maustaste einen Inspektor in einem neuen Fenster öffnen können. Wir überschreiben QWebEngineView::contextMenuEvent und verwenden QWebEnginePage::createStandardContextMenu um ein Standard QMenu mit einer Standardliste von QWebEnginePage::WebAction Aktionen zu erstellen.
Der Standardname für die Aktion QWebEnginePage::InspectElement ist Inspect. Der Übersichtlichkeit halber benennen wir sie in Open Inspector In New Window um, wenn noch kein Inspektor vorhanden ist, und in Inspect Element, wenn sie bereits erstellt wurde.
Wir prüfen auch, ob die Aktion QWebEnginePage::ViewSource im Menü enthalten ist, denn wenn dies nicht der Fall ist, müssen wir auch ein Trennzeichen hinzufügen.
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()); }
Implementierung der WebPage- und WebView-Funktionalität
Wir implementieren WebPage
als Unterklasse von QWebEnginePage und WebView
als Unterklasse von QWebEngineView, um HTTP, Proxy-Authentifizierung und das Ignorieren von SSL-Zertifikatsfehlern beim Zugriff auf Webseiten zu ermöglichen:
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; };
In allen oben genannten Fällen zeigen wir dem Benutzer den entsprechenden Dialog an. Im Falle der Authentifizierung müssen wir die richtigen Werte für die Anmeldeinformationen auf dem QAuthenticator Objekt setzen:
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(); } }
Der handleProxyAuthenticationRequired
signal handler implementiert die gleichen Schritte für die Authentifizierung von HTTP-Proxys.
Bei SSL-Fehlern wird geprüft, ob sie vom Hauptrahmen oder von einer Ressource innerhalb der Seite stammen. Ressourcenfehler lösen automatisch eine Zertifikatsablehnung aus, da der Benutzer nicht genügend Kontext hat, um eine Entscheidung zu treffen. In allen anderen Fällen lösen wir einen Dialog aus, in dem der Benutzer das Zertifikat zulassen oder ablehnen kann.
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); }); }
Öffnen einer Web-Seite
In diesem Abschnitt wird der Arbeitsablauf für das Öffnen einer neuen Seite beschrieben. Wenn der Benutzer eine URL in die Navigationsleiste eingibt und Enter drückt, wird das Signal QLineEdit::returnPressed
ausgelöst und die neue URL an TabWidget::setUrl
übergeben:
BrowserWindow::BrowserWindow(Browser *browser, QWebEngineProfile *profile, bool forDevTools) { ... connect(m_urlLineEdit, &QLineEdit::returnPressed, [this]() { m_tabWidget->setUrl(QUrl::fromUserInput(m_urlLineEdit->text())); }); ... }
Der Aufruf wird an die aktuell ausgewählte Registerkarte weitergeleitet:
void TabWidget::setUrl(const QUrl &url) { if (WebView *view = currentWebView()) { view->setUrl(url); view->setFocus(); } }
Die setUrl()
-Methode von WebView
leitet lediglich das url
an das zugehörige WebPage
weiter, das wiederum im Hintergrund mit dem Herunterladen des Seiteninhalts beginnt.
Implementierung von Private Browsing
Private Browsing, Inkognito-Modus oder Off-the-Record-Modus ist eine Funktion vieler Browser, bei der normalerweise dauerhafte Daten wie Cookies, der HTTP-Cache oder der Browserverlauf nur im Speicher gehalten werden und keine Spuren auf der Festplatte hinterlassen. In diesem Beispiel wird das private Browsing auf Fensterebene implementiert, wobei sich alle Registerkarten in einem Fenster entweder im normalen oder im privaten Modus befinden. Alternativ könnten wir das private Browsing auf der Ebene der Registerkarten implementieren, wobei einige Registerkarten in einem Fenster im normalen Modus, andere im privaten Modus sind.
Die Implementierung von Private Browsing ist mit Qt WebEngine recht einfach. Alles, was man tun muss, ist, ein neues QWebEngineProfile zu erstellen und es in QWebEnginePage anstelle des Standardprofils zu verwenden. In diesem Beispiel gehört dieses neue Profil dem Objekt Browser
:
class Browser { public: ... BrowserWindow *createHiddenWindow(bool offTheRecord = false); BrowserWindow *createWindow(bool offTheRecord = false); private: ... QScopedPointer<QWebEngineProfile> m_profile; };
Das erforderliche Profil für das private Browsing wird zusammen mit seinem ersten Fenster erstellt. Der Standardkonstruktor für QWebEngineProfile versetzt es bereits in den Off-the-Record-Modus.
BrowserWindow *Browser::createHiddenWindow(bool offTheRecord) { if (!offTheRecord && !m_profile) { const QString name = u"simplebrowser."_s + QLatin1StringView(qWebEngineChromiumVersion()); m_profile.reset(new QWebEngineProfile(name)); ...
Alles, was noch zu tun ist, ist, das entsprechende Profil an die entsprechenden QWebEnginePage Objekte weiterzugeben. Das Objekt Browser
übergibt an jedes neue BrowserWindow
entweder das globale Standardprofil (siehe QWebEngineProfile::defaultProfile) oder eine gemeinsame Instanz des Off-the-Record-Profils:
... 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; }
Die Objekte BrowserWindow
und TabWidget
sorgen dann dafür, dass alle in einem Fenster enthaltenen QWebEnginePage Objekte dieses Profil verwenden.
Verwaltung von Downloads
Downloads sind mit einem QWebEngineProfile verbunden. Immer wenn ein Download auf einer Webseite ausgelöst wird, wird das Signal QWebEngineProfile::downloadRequested mit einem QWebEngineDownloadRequest ausgegeben, das in diesem Beispiel an DownloadManagerWidget::downloadRequested
weitergeleitet wird:
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); }
Diese Methode fordert den Benutzer zur Eingabe eines Dateinamens auf (mit einem vorausgefüllten Vorschlag) und startet den Download (sofern der Benutzer den Save As Dialog nicht abbricht):
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(); }
Das Objekt QWebEngineDownloadRequest sendet in regelmäßigen Abständen das Signal receivedBytesChanged, um potenzielle Beobachter über den Fortschritt des Downloads zu informieren, und das Signal stateChanged, wenn der Download beendet ist oder ein Fehler auftritt. Siehe downloadmanagerwidget.cpp
für ein Beispiel, wie diese Signale gehandhabt werden können.
Verwalten von WebAuth/FIDO UX-Anfragen
WebAuth UX-Anfragen sind mit QWebEnginePage verbunden. Wann immer ein Authentifikator eine Benutzerinteraktion erfordert, wird eine UX-Anfrage auf QWebEnginePage ausgelöst und das Signal QWebEnginePage::webAuthUxRequested mit QWebEngineWebAuthUxRequest ausgegeben, das in diesem Beispiel an WebView::handleAuthenticatorRequired
weitergeleitet wird:
connect(page, &QWebEnginePage::webAuthUxRequested, this, &WebView::handleWebAuthUxRequested);
Diese Methode erstellt einen WebAuth UX-Dialog und initiiert den UX-Anfragefluss.
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(); }
Das QWebEngineWebAuthUxRequest Objekt sendet in regelmäßigen Abständen das stateChanged Signal aus, um potentielle Beobachter über den aktuellen WebAuth UX Status zu informieren. Die Beobachter aktualisieren den WebAuth-Dialog entsprechend. Siehe webview.cpp
und webauthdialog.cpp
für ein Beispiel, wie diese Signale gehandhabt werden können.
Signieranforderung für macOS
Um Websites den Zugriff auf den Standort, die Kamera und das Mikrofon zu ermöglichen, wenn Simple Browser auf macOS ausgeführt wird, muss die Anwendung signiert werden. Dies geschieht automatisch bei der Erstellung, aber Sie müssen eine gültige Signieridentität für die Erstellungsumgebung einrichten.
Dateien und Attribute
Das Beispiel verwendet Icons aus der Tango Icon Library:
Tango-Symbolbibliothek | Öffentlicher Bereich |
© 2025 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.