Read the free tutorial below or

Get the Video

Creating additional windows
Opening new windows for your application

Getting started with PyQt5 course

In an earlier tutorial we've already covered how to open dialog windows. These are special windows which (by default) grab the focus of the user, and run their own event loop, effectively blocking the execution of the rest of your app.

However, quite often you will want to open a second window in an application, without interrupting the main window -- for example, to show the output of some long-running process, or display graphs or other visualizations. Alternatively, you may want to create an application that allows you to work on multiple documents at once, in their own windows.

It's relatively straightforward to open new windows but there are a few things to keep in mind to make sure they work well. In this tutorial we'll step through how to create a new window, and how to show and hide external windows on demand.

Creating a new window

In Qt any widget without a parent is a window. This means, to show a new window you just need to create a new instance of a widget. This can be any widget type (technically any subclass of QWidget) including another QMainWindow if you prefer.

There is no restriction on the number of QMainWindow instances you can have. If you need toolbars or menus on your second window you will have to use a QMainWindow to achieve this. This can get confusing for users however, so make sure it's necessary.

As with your main window, creating a window is not sufficient, you must also show it.

python
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget

import sys


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent, it
    will appear as a free-floating window as we want.
    """
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window")
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.show_new_window)
        self.setCentralWidget(self.button)

    def show_new_window(self, checked):
        w = AnotherWindow()
        w.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

A main window with a button to launch a child window, A main window with a button to launch a child window,

If you run this, you'll see the main window. Clicking the button may show the second window, but if you see it it will only be visible for a fraction of a second. What's happening?

python
    def show_new_window(self, checked):
        w = AnotherWindow()
        w.show()

Inside this method, we are creating our window (widget) object, storing it in the variable w and showing it. However, once we leave the method we no longer have a reference to the w variable (it is a local variable) and so it will be cleaned up – and the window destroyed. To fix this we need to keep a reference to the window somewhere, for example on the self object.

python
    def show_new_window(self, checked):
        self.w = AnotherWindow()
        self.w.show()

Now, when you click the button to show the new window, it will persist.

However, what happens if you click the button again? The window will be re-created! This new window will replace the old in the self.w variable, and – because there is now no reference to it – the previous window will be destroyed.

You can see this in action if you change the window definition to show a random number in the label each time it is created.

python
from random import randint


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent, it
    will appear as a free-floating window as we want.
    """
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0,100))
        layout.addWidget(self.label)
        self.setLayout(layout)

The __init__ block is only run when creating the window. If you keep clicking the button the number will change, showing that the window is being re-created.

One solution is to simply check whether the window has already being created before creating it. The example below shows this in action.

python
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget

import sys

from random import randint


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent, it
    will appear as a free-floating window as we want.
    """
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0,100))
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.w = None  # No external window yet.
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.show_new_window)
        self.setCentralWidget(self.button)

    def show_new_window(self, checked):
        if self.w is None:
            self.w = AnotherWindow()
        self.w.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

Child window with a label randomly generated on creation. Child window with a label randomly generated on creation.

Using the button you can pop up the window, and use the window controls to close it. If you click the button again, the same window will re-appear.

This approach is fine for windows that you create temporarily – for example if you want to pop up a window to show a particular plot, or log output. However, for many applications you have a number of standard windows that you want to be able to show/hide them on demand.

In the next part we'll look at how to work with these types of windows.

Toggling a window

Often you'll want to toggle the display of a window using an action on a toolbar or in a menu. As we previously saw, if no reference to a window is kept, it will be discarded (and closed). We can use this behaviour to close a window, replacing the show_new_window method from the previous example with –

python
    def show_new_window(self, checked):
        if self.w is None:
            self.w = AnotherWindow()
            self.w.show()

        else:
            self.w = None  # Discard reference, close window.

By setting self.w to None the reference to the window will be lost, and the window will close.

If we set it to any other value that None the window will still close, but the if self.w is None test will not pass the next time we click the button and so we will not be able to recreate a window.

This will only work if you have not kept a reference to this window somewhere else. To make sure the window closes regardless, you may want to explicitly call .close() on it. The full example is shown below.

python
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget

import sys

from random import randint


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent, it
    will appear as a free-floating window as we want.
    """
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0,100))
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.w = None  # No external window yet.
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.show_new_window)
        self.setCentralWidget(self.button)

    def show_new_window(self, checked):
        if self.w is None:
            self.w = AnotherWindow()
            self.w.show()

        else:
            self.w.close()  # Close window.
            self.w = None  # Discard reference.


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

Create GUI Applications with Python & Qt6
The easy way to create desktop applications

My complete guide, updated for 2021 & PyQt6. Everything you need build real apps.

Downloadable ebook (PDF, ePub) & Complete Source code

To support developers in [[ countryRegion ]] I give a [[ localizedDiscount[couponCode] ]]% discount with the code [[ couponCode ]] — Enjoy!

For [[ activeDiscount.description ]] I'm giving a [[ activeDiscount.discount ]]% discount with the code [[ couponCode ]] — Enjoy!

Persistent windows

So far we've looked at how to create new windows on demand. However, sometimes you have a number of standard application windows. In this case rather than create the windows when you want to show them, it can often make more sense to create them at start-up, then use .show() to display them when needed.

In the following example we create our external window in the __init__ block for the main window, and then our show_new_window method simply calls self.w.show() to display it.

python
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget

import sys

from random import randint


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent, it
    will appear as a free-floating window as we want.
    """
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0,100))
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.w = AnotherWindow()
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.show_new_window)
        self.setCentralWidget(self.button)

    def show_new_window(self, checked):
        self.w.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

If you run this, clicking on the button will show the window as before. However, note that the window is only created once and calling .show() on an already visible window has no effect.

Showing & hiding persistent windows

Once you have created a persistent window you can show and hide it without recreating it. Once hidden the window still exists, but will not be visible and accept mouse/other input. However you can continue to call methods on the window and update it's state -- including changing it's appearance. Once re-shown any changes will be visible.

Below we update our main window to create a toggle_window method which checks, using .isVisible() to see if the window is currently visible. If it is not, it is shown using .show() , if it is already visible we hide it with .hide().

python
class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.w = AnotherWindow()
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.toggle_window)
        self.setCentralWidget(self.button)

    def toggle_window(self, checked):
        if self.w.isVisible():
            self.w.hide()

        else:
            self.w.show()

The complete working example of this persistent window and toggling the show/hide state is shown below.

python
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QLabel, QVBoxLayout, QWidget

import sys

from random import randint


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent, it
    will appear as a free-floating window as we want.
    """
    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0,100))
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.w = AnotherWindow()
        self.button = QPushButton("Push for Window")
        self.button.clicked.connect(self.toggle_window)
        self.setCentralWidget(self.button)

    def toggle_window(self, checked):
        if self.w.isVisible():
            self.w.hide()

        else:
            self.w.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

Note that, again, the window is only created once -- the window's __init__ block is not re-run (so the number in the label does not change) each time the window is re-shown.

Multiple windows

You can use the same principle for creating multiple windows -- as long as you keep a reference to the window, things will work as expected. The simplest approach is to create a separate method to toggle the display of each of the windows.

python
import sys
from random import randint

from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
)


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent,
    it will appear as a free-floating window.
    """

    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0, 100))
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.window1 = AnotherWindow()
        self.window2 = AnotherWindow()

        l = QVBoxLayout()
        button1 = QPushButton("Push for Window 1")
        button1.clicked.connect(self.toggle_window1)
        l.addWidget(button1)

        button2 = QPushButton("Push for Window 2")
        button2.clicked.connect(self.toggle_window2)
        l.addWidget(button2)

        w = QWidget()
        w.setLayout(l)
        self.setCentralWidget(w)

    def toggle_window1(self, checked):
        if self.window1.isVisible():
            self.window1.hide()

        else:
            self.window1.show()

    def toggle_window2(self, checked):
        if self.window2.isVisible():
            self.window2.hide()

        else:
            self.window2.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()

A mainwindow with two child windows. A mainwindow with two child windows.

However, you can also create a generic method which handles toggling for all windows -- see transmitting extra data with Qt signals for a detailed explanation of how this works. The example below shows that in action, using a lambda function to intercept the signal from each button and pass through the appropriate window. We can also discard the checked value since we aren't using it.

python
import sys
from random import randint

from PyQt5.QtWidgets import (
    QApplication,
    QLabel,
    QMainWindow,
    QPushButton,
    QVBoxLayout,
    QWidget,
)


class AnotherWindow(QWidget):
    """
    This "window" is a QWidget. If it has no parent,
    it will appear as a free-floating window.
    """

    def __init__(self):
        super().__init__()
        layout = QVBoxLayout()
        self.label = QLabel("Another Window % d" % randint(0, 100))
        layout.addWidget(self.label)
        self.setLayout(layout)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.window1 = AnotherWindow()
        self.window2 = AnotherWindow()

        l = QVBoxLayout()
        button1 = QPushButton("Push for Window 1")
        button1.clicked.connect(
            lambda checked: self.toggle_window(self.window1)
        )
        l.addWidget(button1)

        button2 = QPushButton("Push for Window 2")
        button2.clicked.connect(
            lambda checked: self.toggle_window(self.window2)
        )
        l.addWidget(button2)

        w = QWidget()
        w.setLayout(l)
        self.setCentralWidget(w)

    def toggle_window(self, window):
        if window.isVisible():
            window.hide()

        else:
            window.show()


app = QApplication(sys.argv)
w = MainWindow()
w.show()
app.exec()
Complete Mark As Complete Finish

Continue reading

Opening links in a new window with QWebEngineView  pyqt

It's quite a common practice to use QWebEngineView as a documentation (or document) browser in PyQt5 applications as it allows the documentation to be created using familiar tools. You can build HTML documentation and bundle it with your application (or host them remotely) then allow your users to browse them within the app. However, this raises an issue when the document contains links to external resources -- how should these links be handled? It's a weird user experience if your users, through clicking a series of links, can end up on Google or Facebook inside your application. One way to avoid this is to enforce opening of certain links in external windows or browsers, ensuring your documentation browser remains just that. In this quick tutorial we'll look at how to implement custom link handling in your Qt browser and use this to redirect clicked links to different windows or the user's desktop browser. The skeleton web browser code is shown below. We'll modify this to add the open in new window behavior. PyQt5 PySide2 python from PyQt5.QtCore import QUrl from PyQt5.QtWidgets import QMainWindow, QApplication from PyQt5.QtWebEngineWidgets import QWebEngineView import os import sys class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() python from PySide2.QtCore import QUrl from PySide2.QtWidgets import QMainWindow, QApplication from PySide2.QtWebEngineWidgets import QWebEngineView import os import sys class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() This creates our basic browser window and navigates to the LearnPyQt homepage. All links will open within the same browser window (normal browser behavior). The basic browser window. Popping up a new window for each link To override the default navigation behavior we need to create a customized QWebEnginePage class. This is the Qt class which handles viewing (and editing) of web documents, such as web pages within the QWebEngineView. By creating a custom QWebEnginePage class we are able to intercept the .acceptNavigationRequest signal and implement custom behavior. For example, we can decline links to block navigation, alter the links to navigate somewhere else, or (as we're doing here) open up custom viewers. In our specific case we will both decline the default behavior, by returning Falseand implement our own, by opening a new window. For our new windows, we create a custom web engine view (the same type we have in the main window), set the URL and then display the window. Note that we need to keep a reference to the created window (in the external_windows list) so it isn’t destroyed on exiting this method. For everything else, we pass through to the handler on the parent class with super().acceptNavigationRequest(). python from PyQt5.QtWebEngineWidgets import QWebEnginePage class CustomWebEnginePage(QWebEnginePage): """ Custom WebEnginePage to customize how we handle link navigation """ # Store external windows. external_windows = [] def acceptNavigationRequest(self, url, _type, isMainFrame): if _type == QWebEnginePage.NavigationTypeLinkClicked: w = QWebEngineView() w.setUrl(url) w.show() # Keep reference to external window, so it isn't cleared up. self.external_windows.append(w) return False return super().acceptNavigationRequest(url, _type, isMainFrame) To use our custom page class we need to set it on the browser with .setPage(). After this, any navigation is sent through the custom page instance and our acceptNavigationRequest handler. python self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("http://google.com")) The full working example is shown below. PyQt5 PySide2 python from PyQt5.QtCore import QUrl from PyQt5.QtWidgets import QMainWindow, QApplication from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage import os import sys class CustomWebEnginePage(QWebEnginePage): """ Custom WebEnginePage to customize how we handle link navigation """ # Store external windows. external_windows = [] def acceptNavigationRequest(self, url, _type, isMainFrame): if _type == QWebEnginePage.NavigationTypeLinkClicked: w = QWebEngineView() w.setUrl(url) w.show() # Keep reference to external window, so it isn't cleared up. self.external_windows.append(w) return False return super().acceptNavigationRequest(url, _type, isMainFrame) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() python from PySide2.QtCore import QUrl from PySide2.QtWidgets import QMainWindow, QApplication from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEnginePage import os import sys class CustomWebEnginePage(QWebEnginePage): """ Custom WebEnginePage to customize how we handle link navigation """ # Store external windows. external_windows = [] def acceptNavigationRequest(self, url, _type, isMainFrame): if _type == QWebEnginePage.NavigationTypeLinkClicked: w = QWebEngineView() w.setUrl(url) w.show() # Keep reference to external window, so it isn't cleared up. self.external_windows.append(w) return False return super().acceptNavigationRequest(url, _type, isMainFrame) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() If you run this example and click on a link in the page, a new window will be opened for every link you click. You can continue to navigate within those external windows as normal -- they use the standard QWebEnginePage class, so don't have our open in new window behavior. Links are opened in a new window. Conditionally popping up a new window Sometimes you only want "external" links to be popped up into a separate window -- navigation within your documentation should stay within the documentation browser window, and only external links (not from your documentation) popped up into a separate window. Since we have access to the URL being navigated this is pretty straightforward. We can just compare that URL to some pattern (here we're using the hostname via url.host()), and choose to either pop a new window, or pass it to the default handler. python class CustomWebEnginePage(QWebEnginePage): """ Custom WebEnginePage to customize how we handle link navigation """ # Store external windows. external_windows = [] def acceptNavigationRequest(self, url, _type, isMainFrame): if (_type == QWebEnginePage.NavigationTypeLinkClicked and url.host() != 'www.mfitzp.com'): # Pop up external links into a new window. w = QWebEngineView() w.setUrl(url) w.show() # Keep reference to external window, so it isn't cleared up. self.external_windows.append(w) return False return super().acceptNavigationRequest(url, _type, isMainFrame) Navigating around the LearnPyQt site now stays within the main browser, but external links (such as to the forum) are popped out into a separate window. The external window is popped up for external links only. Reusing an external window In this first example we're creating a new window for every link, rather than creating a new window if none exists and then sending all subsequent link clicks to that same window. To get this second behavior we just need to hold a single reference to the external window and check if it exists before creating a new one. python class WebEnginePage(QWebEnginePage): # Store second window. external_window = None def acceptNavigationRequest(self, url, _type, isMainFrame): print(url, _type, isMainFrame) if _type == QWebEnginePage.NavigationTypeLinkClicked: if not self.external_window: self.external_window = QWebEngineView() self.external_window.setUrl(url) self.external_window.show() return False return super().acceptNavigationRequest(url, _type, isMainFrame) Putting this into our example gives us the following complete example. PyQt5 PySide2 python from PyQt5.QtCore import QUrl from PyQt5.QtWidgets import QMainWindow, QApplication from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage import sys class CustomWebEnginePage(QWebEnginePage): # Store second window. external_window = None def acceptNavigationRequest(self, url, _type, isMainFrame): print(url, _type, isMainFrame) if _type == QWebEnginePage.NavigationTypeLinkClicked: if not self.external_window: self.external_window = QWebEngineView() self.external_window.setUrl(url) self.external_window.show() return False return super().acceptNavigationRequest(url, _type, isMainFrame) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() python from PySide2.QtCore import QUrl from PySide2.QtWidgets import QMainWindow, QApplication from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEnginePage import sys class CustomWebEnginePage(QWebEnginePage): # Store second window. external_window = None def acceptNavigationRequest(self, url, _type, isMainFrame): print(url, _type, isMainFrame) if _type == QWebEnginePage.NavigationTypeLinkClicked: if not self.external_window: self.external_window = QWebEngineView() self.external_window.setUrl(url) self.external_window.show() return False return super().acceptNavigationRequest(url, _type, isMainFrame) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() When clicking on a link in the browser window a new window is created. You can browse in that window as normal, but if you click a new link in the parent window, the current page will be replaced with that link. Opening links in the user's default browser You might also want to consider popping up external links in the users default browser. This allows them to bookmark the links, or browse as normally, rather than in the restricted browser view your app provides. For this we don't need to create a window, we can just send the url to the system default handler. This is accomplished by passing the url to the QDesktopServices.openUrl() method. The full working example is shown below. PyQt5 PySide2 python from PyQt5.QtCore import QUrl from PyQt5.QtWidgets import QMainWindow, QApplication from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage from PyQt5.QtGui import QDesktopServices import os import sys class CustomWebEnginePage(QWebEnginePage): """ Custom WebEnginePage to customize how we handle link navigation """ # Store external windows. external_windows = [] def acceptNavigationRequest(self, url, _type, isMainFrame): if (_type == QWebEnginePage.NavigationTypeLinkClicked and url.host() != 'www.mfitzp.com'): # Send the URL to the system default URL handler. QDesktopServices.openUrl(url) return False return super().acceptNavigationRequest(url, _type, isMainFrame) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() python from PySide2.QtCore import QUrl from PySide2.QtWidgets import QMainWindow, QApplication from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEnginePage from PySide2.QtGui import QDesktopServices import os import sys class CustomWebEnginePage(QWebEnginePage): """ Custom WebEnginePage to customize how we handle link navigation """ # Store external windows. external_windows = [] def acceptNavigationRequest(self, url, _type, isMainFrame): if (_type == QWebEnginePage.NavigationTypeLinkClicked and url.host() != 'www.mfitzp.com'): # Send the URL to the system default URL handler. QDesktopServices.openUrl(url) return False return super().acceptNavigationRequest(url, _type, isMainFrame) class MainWindow(QMainWindow): def __init__(self, *args, **kwargs): super(MainWindow, self).__init__(*args, **kwargs) self.browser = QWebEngineView() self.browser.setPage(CustomWebEnginePage(self)) self.browser.setUrl(QUrl("https://www.mfitzp.com")) self.setCentralWidget(self.browser) app = QApplication(sys.argv) window = MainWindow() window.show() app.exec_() If you run this and click on any external links, you'll see them open in your system's default browser window (here showing Chrome). More