- Qt 5.15
- Qt WebEngine
- Qt WebEngine Examples
- WebEngine Quick Nano Browser
- Qt 5.15.19 Reference Documentation

# WebEngine Quick Nano Browser

A web browser implemented using the WebEngineView QML type.

Quick Nano Browser demonstrates how to use the Qt WebEngine QML types to develop a small web browser application that consists of a browser window with a title bar, toolbar, tab view, and status bar. The web content is loaded in a web engine view within the tab view. If certificate errors occur, users are prompted for action in a message dialog. The status bar pops up to display the URL of a hovered link.

A web page can issue a request for being displayed in fullscreen mode. Users can allow full screen mode by using a toolbar button. They can leave fullscreen mode by using a keyboard shortcut. Additional toolbar buttons enable moving backwards and forwards in the browser history, reloading tab content, and opening a settings menu for enabling the following features: JavaScript, plugins, fullscreen mode, off the record, HTTP disk cache, autoloading images, and ignoring certificate errors.

#### Running the Example

To run the example from Qt Creator, open the Welcome mode and select the example from Examples. For more information, visit Building and Running an Example.

#### Creating the Main Browser Window

When the browser main window is loaded, it creates an empty tab using the default profile. Each tab is a web engine view that fills the main window.

We create the main window in the BrowserWindow.qml file using the ApplicationWindow type:

     ApplicationWindow {
         id: browserWindow
         property QtObject applicationRoot
         property Item currentWebView: tabs.currentIndex < tabs.count ? tabs.getTab(tabs.currentIndex).item : null
         ...
         width: 1300
         height: 900
         visible: true
         title: currentWebView && currentWebView.title

We use the TabView Qt Quick control to create an empty tab view that fills the main window. We set the tab active first, to make sure that the tab item is immediately instantiated:

         TabView {
             id: tabs
             function createEmptyTab(profile) {
                 var tab = addTab("", tabComponent);
                 // We must do this first to make sure that tab.active gets set so that tab.item gets instantiated immediately.
                 tab.active = true;
                 tab.title = Qt.binding(function() { return tab.item.title ? tab.item.title : 'New Tab' });
                 tab.item.profile = profile;
                 return tab;
             }

             function indexOfView(view) {
                 for (let i = 0; i < tabs.count; ++i)
                     if (tabs.getTab(i).item == view)
                         return i
                 return -1
             }

             function removeView(index) {
                 if (tabs.count > 1)
                     tabs.removeTab(index)
                 else
                     browserWindow.close();
             }

             anchors.top: parent.top
             anchors.bottom: devToolsView.top
             anchors.left: parent.left
             anchors.right: parent.right
             Component.onCompleted: createEmptyTab(defaultProfile)

The tab contains a web engine view that loads web content:

             // Add custom tab view style so we can customize the tabs to include a close button
             style: TabViewStyle {
                 property color frameColor: "#999"
                 property color fillColor: "#eee"
                 property color nonSelectedColor: "#ddd"
                 frameOverlap: 1
                 frame: Rectangle {
                     color: "#eee"
                     border.color: frameColor
                 }
                 tab: Rectangle {
                     id: tabRectangle
                     color: styleData.selected ? fillColor : nonSelectedColor
                     border.width: 1
                     border.color: frameColor
                     implicitWidth: Math.max(text.width + 30, 80)
                     implicitHeight: Math.max(text.height + 10, 20)
                     Rectangle { height: 1 ; width: parent.width ; color: frameColor}
                     Rectangle { height: parent.height ; width: 1; color: frameColor}
                     Rectangle { x: parent.width - 2; height: parent.height ; width: 1; color: frameColor}
                     Text {
                         id: text
                         anchors.left: parent.left
                         anchors.verticalCenter: parent.verticalCenter
                         anchors.leftMargin: 6
                         text: styleData.title
                         elide: Text.ElideRight
                         color: styleData.selected ? "black" : frameColor
                     }
                     Button {
                         anchors.right: parent.right
                         anchors.verticalCenter: parent.verticalCenter
                         anchors.rightMargin: 4
                         height: 12
                         style: ButtonStyle {
                             background: Rectangle {
                                 implicitWidth: 12
                                 implicitHeight: 12
                                 color: control.hovered ? "#ccc" : tabRectangle.color
                                 Text {text: "x" ; anchors.centerIn: parent ; color: "gray"}
                             }}
                         onClicked: tabs.removeView(styleData.index)
                     }
                 }
             }

             Component {
                 id: tabComponent
                 WebEngineView {
                     id: webEngineView
                     focus: true

We use the Action type to create new tabs:

         Action {
             shortcut: StandardKey.AddTab
             onTriggered: {
                 tabs.createEmptyTab(tabs.count != 0 ? currentWebView.profile : defaultProfile);
                 tabs.currentIndex = tabs.count - 1;
                 addressBar.forceActiveFocus();
                 addressBar.selectAll();
             }

We use the TextField Qt Quick Control within a ToolBar to create an address bar that shows the current URL and where users can enter another URL:

         toolBar: ToolBar {
             id: navigationBar
                 RowLayout {
                     anchors.fill: parent
         ...
                     TextField {
                         id: addressBar
         ...
                         focus: true
                         Layout.fillWidth: true
                         text: currentWebView && currentWebView.url
                         onAccepted: currentWebView.url = utils.fromUserInput(text)
                     }

#### Handling Certificate Errors

If the certificate of the site being loaded triggers a certificate error, we call the defer() QML method to pause the URL request and wait for user input:

                     onCertificateError: function(error) {
                         error.defer();
                         sslDialog.enqueue(error);
                     }

We use the MessageDialog type to prompt users to continue or cancel the loading of the web page. If users select Yes, we call the ignoreCertificateError() method to ignore the error and continue loading content from the URL. If users select No, we call the rejectCertificate() method to reject the request and stop loading content from the URL:

         MessageDialog {
             id: sslDialog

             property var certErrors: []
             icon: StandardIcon.Warning
             standardButtons: StandardButton.No | StandardButton.Yes
             title: "Server's certificate not trusted"
             text: "Do you wish to continue?"
             detailedText: "If you wish so, you may continue with an unverified certificate. " +
                           "Accepting an unverified certificate means " +
                           "you may not be connected with the host you tried to connect to.\n" +
                           "Do you wish to override the security check and continue?"
             onYes: {
                 certErrors.shift().ignoreCertificateError();
                 presentError();
             }
             onNo: reject()
             onRejected: reject()

             function reject(){
                 certErrors.shift().rejectCertificate();
                 presentError();
             }
             function enqueue(error){
                 certErrors.push(error);
                 presentError();
             }
             function presentError(){
                 visible = certErrors.length > 0
             }
         }

#### Entering and Leaving Fullscreen Mode

We create a menu item for allowing fullscreen mode in a settings menu that we place on the tool bar. Also, we create an action for leaving fullscreen mode by using a keyboard shortcut. We call the accept() method to accept the fullscreen request. The methdod sets the isFullScreen property to be equal to the toggleOn property.

                     onFullScreenRequested: function(request) {
                         if (request.toggleOn) {
                             webEngineView.state = "FullScreen";
                             browserWindow.previousVisibility = browserWindow.visibility;
                             browserWindow.showFullScreen();
                             fullScreenNotification.show();
                         } else {
                             webEngineView.state = "";
                             browserWindow.visibility = browserWindow.previousVisibility;
                             fullScreenNotification.hide();
                         }
                         request.accept();
                     }

When entering fullscreen mode, we display a notification using the FullScreenNotification custom type that we create in FullScreenNotification.qml.

We use the Action type in the settings menu to create a shortcut for leaving fullscreen mode by pressing the escape key:

         Settings {
             id : appSettings
             property alias fullScreenSupportEnabled: fullScreenSupportEnabled.checked
             property alias autoLoadIconsForPage: autoLoadIconsForPage.checked
             property alias touchIconsEnabled: touchIconsEnabled.checked
             property alias webRTCPublicInterfacesOnly : webRTCPublicInterfacesOnly.checked
             property alias devToolsEnabled: devToolsEnabled.checked
             property alias pdfViewerEnabled: pdfViewerEnabled.checked
         }

         Action {
             shortcut: "Escape"
             onTriggered: {
                 if (currentWebView.state == "FullScreen") {
                     browserWindow.visibility = browserWindow.previousVisibility;
                     fullScreenNotification.hide();
                     currentWebView.triggerWebAction(WebEngineView.ExitFullScreen);
                 }

                 if (findBar.visible)
                     findBar.visible = false;
             }
         }

#### Files and Attributions

The example uses icons from the Tango Icon Library:

Tango Icon Library | Public Domain

Example project @ code.qt.io