Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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 calling setSource(), or how is this usually accomplished? If I call setSource() 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 call setSource() 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 signal sourceChanged() 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!


Log in to reply