Solved Getting user confirmation before opening external links in a QTextBrowser
-
How is the best way to do this? I have a lot of internal and external links in my help files. The internal links should open immediately when clicked, but I would like to provide the user an option not to navigate outside the application if so desired. This will be a configuration element; if the user chooses, no confirmation will be required, and the link should open the standard browser and navigate to the page.
There is the signal
anchorClicked(const QUrl &)
to which I can connect a slot. But does this let me cancel navigation simply by querying the user and then callingsetSource()
, or how is this usually accomplished? If I callsetSource()
with an empty Url, I suppose the browser will still open with a blank page? (haven't tried this yet...).Here is the documentation for
anchorClicked
:
"This signal is emitted when the user clicks an anchor. The URL referred to by the anchor is passed in link.
Note that the browser will automatically handle navigation to the location specified by link unless the openLinks property is set to false or you call setSource() in a slot connected. This mechanism is used to override the default navigation features of the browser."I suppose that I could get the text browser's current
source()
URL and then callsetSource()
with that. Is this the best (or only) way to do it? -
I just noticed that the signal
anchorClicked()
is emitted twice when clicking on a link? I merely put a message box in the function body to test it. Also, the signalsourceChanged()
is emitted at least twice in some circumstances.This is going to be a mess, I think.
-
@robert-hairgrove
I don't think either of those should be happening twice, so check your code, or produce a cut-down example. -
Thanks, @jonb . In my test code, it works as expected. I'll have to investigate further.
FWIW, here is the test code:
FILE: test_anchorClicked.pro:
QT += core gui greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = test_anchorClicked TEMPLATE = app SOURCES += \ main.cpp \ MainWindow.cpp RESOURCES += \ test_anchorClicked.qrc HEADERS += \ MainWindow.hpp
FILE: Nirvana.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>Test signals and slots for QTextBrowser</title> </head> <body> <p><a href="path_to_Nirvana.html">Are we there yet?</a></p> </body></html>
FILE: path_to_Nirvana.html:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <html> <head> <meta http-equiv="content-type" content="text/html; charset=utf-8"/> <title>Test signals and slots for QTextBrowser</title> </head> <body> <p><a href="Nirvana.html">Click me!</a></p> </body></html>
FILE: MainWindow.hpp:
#ifndef MAINWINDOW_HPP #define MAINWINDOW_HPP #include <QMainWindow> class QUrl; class QTextBrowser; class MainWindow : public QMainWindow { Q_OBJECT public: explicit MainWindow(QWidget *parent = nullptr); public slots: void handleAnchorClicked(const QUrl &url); void handleSourceChanged(const QUrl &url); private: QTextBrowser *browser; }; #endif // MAINWINDOW_HPP
FILE: MainWindow.cpp:
#include "MainWindow.hpp" #include <QMessageBox> #include <QTextBrowser> #include <QUrl> static const QString TEXTBROWSER_TEST_HTML = "qrc:/html/path_to_Nirvana.html"; MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), browser(new QTextBrowser(this)) { setCentralWidget(browser); browser->setSource(QUrl(TEXTBROWSER_TEST_HTML)); connect(browser, &QTextBrowser::anchorClicked, this, &MainWindow::handleAnchorClicked); connect(browser, &QTextBrowser::sourceChanged, this, &MainWindow::handleSourceChanged); } void MainWindow::handleAnchorClicked(const QUrl &url) { QString msg = "new URL == "; msg.append(url.toDisplayString()); msg.append("\nold URL == "); msg.append(browser->source().toDisplayString()); QMessageBox::information(this, __FUNCTION__, msg); } void MainWindow::handleSourceChanged(const QUrl &url) { QString msg = "new URL == "; msg.append(url.toDisplayString()); msg.append("\nold URL == "); msg.append(browser->source().toDisplayString()); QMessageBox::information(this, __FUNCTION__, msg); }
FILE: test_anchorClicked.qrc:
<RCC> <qresource prefix="/html"> <file>path_to_Nirvana.html</file> <file>Nirvana.html</file> </qresource> </RCC>
FILE: main.cpp:
#include <QApplication> #include "MainWindow.hpp" int main(int argc, char *argv[]) { QApplication a(argc, argv); MainWindow w; w.show(); return a.exec(); }
-
SOLVED: I had another slot connected to the sourceChanged signal, and it was causing side-effects.
Thank you, @JonB for pointing me down the right path for fixing this!