Chapter 30 web page interaction QWebEngineView

If you need to load and display web pages in the program, QWebEngineView is definitely the best choice. The control is based on the Chrome browser kernel engine, and the functions and methods provided are relatively powerful.

**Note: * * V5 QWebEngineView is not included in PyQt5 version 11 and later. Please download it separately:

pip install PyQtWebEngine

30.1 making a simple browser

In this chapter, we will understand the usage of QWebEngineView by making a simple browser as shown in the figure below:

After entering the web address in the input box and typing enter, the QWebEngineView control loads and displays the corresponding web address content. The three buttons on the top left allow us to move forward, backward and refresh. The two buttons on the top right can zoom in and out of the web page.

Let's implement it step by step. First, complete the appearance of the browser:

import sys
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QIcon
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QVBoxLayout, QHBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(1000, 600)                  # 1

        self.back_btn = QPushButton(self)       # 2
        self.forward_btn = QPushButton(self)
        self.refresh_btn = QPushButton(self)
        self.zoom_in_btn = QPushButton(self)
        self.zoom_out_btn = QPushButton(self)
        self.url_le = QLineEdit(self)

        self.browser = QWebEngineView(self)

        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.layout_init()
        self.btn_init()
        self.le_init()

    def layout_init(self):                       # 3
        self.h_layout.setSpacing(0)
        self.h_layout.addWidget(self.back_btn)
        self.h_layout.addWidget(self.forward_btn)
        self.h_layout.addWidget(self.refresh_btn)
        self.h_layout.addStretch(2)
        self.h_layout.addWidget(self.url_le)
        self.h_layout.addStretch(2)
        self.h_layout.addWidget(self.zoom_in_btn)
        self.h_layout.addWidget(self.zoom_out_btn)

        self.v_layout.addLayout(self.h_layout)
        self.v_layout.addWidget(self.browser)

        self.setLayout(self.v_layout)

    def btn_init(self):                           # 4
        self.back_btn.setIcon(QIcon('images/back.png'))
        self.forward_btn.setIcon(QIcon('images/forward.png'))
        self.refresh_btn.setIcon(QIcon('images/refresh.png'))
        self.zoom_in_btn.setIcon(QIcon('images/zoom_in.png'))
        self.zoom_out_btn.setIcon(QIcon('images/zoom_out.png'))

    def le_init(self):                            # 5
        self.url_le.setFixedWidth(400)
        self.url_le.setPlaceholderText('Search or enter website name')


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())
  1. Set the window size to 1000x600 through the resize() method;

  2. Instantiate button control, input box control and QWebEngineView control;

  3. After completing the layout, use setSpacing() to pass in the parameter 0, which means that there is no interval between the controls (mainly to make the buttons close), and then we use addStretch() where we want to, so as to separate the input box from the buttons and make the buttons close to each other.

  4. Add an icon to the button, and the picture download address is as follows:

  1. Set the width of the input box to 400 and set a placeholder to prompt the user to enter the web address here.

At this time, the screenshot is as follows. QWebEngine does not display any web pages:

Next, complete the following functions: after entering the website address in the input box and clicking enter, QWebEngineView loads and displays the corresponding website content:

def keyPressEvent(self, QKeyEvent):
    if QKeyEvent.key() == Qt.Key_Return or QKeyEvent.key() == Qt.Key_Enter:
        if self.url_le.hasFocus():
            self.browser.load(QUrl(self.url_le.text()))

Since the keyboard is involved, it must be handled with event functions.

The standard keyboard has two enter keys, Key_Return is a big return, Key_Enter is a small return (both are considered here), as shown in the figure below:

Add if self url_ le. Hasfocus(): it is judged that the web page will jump only when the input box is edited by clicking enter (readers can also use the browser on the market to see if it is).

If all the conditions are met, you can call the load() method and pass in a QUrl type parameter (you can't just pass in a string, you need to use QUrl() to turn the string into a QUrl object).

Although QWebEngineView has provided many useful methods, many aspects still need to be improved by our developers. For example, if the user only enters“ http://baidu.com "If so, QWebEngineView can't recognize it, so it can't load and display the web page (it will jump to a blank page).

Browsers on the market only enter“ http://baidu.com "In case of, it will automatically add" http: / / "or" https: / / "at the beginning. We will improve the following code:

def keyPressEvent(self, QKeyEvent):
    if QKeyEvent.key() == Qt.Key_Return or QKeyEvent.key() == Qt.Key_Enter:
        if self.url_le.hasFocus():
            if self.url_le.text().startswith('https://') or self.url_le.text().startswith('http://'):
                self.browser.load(QUrl(self.url_le.text()))
            else:
                self.browser.load(QUrl('https://'+self.url_le.text()))

Call the startswitch() method to determine whether the URL string entered by the user starts with "https: / /" or "http: / /". If so, the URL entered by the user will be used; if not, add "https: / /" before it. In this way, QWebEngineView can be displayed normally.

Next, complete the following functions: when running the program for the first time, QWebEngineView displays Baidu web page.

def browser_init(self):
    self.browser.load(QUrl('https://baidu.com'))

Very simple, just call the above functions in class initialization function.

So far, the program code is as follows:

import sys
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QIcon
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QVBoxLayout, QHBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(1000, 600)

        self.back_btn = QPushButton(self)
        self.forward_btn = QPushButton(self)
        self.refresh_btn = QPushButton(self)
        self.zoom_in_btn = QPushButton(self)
        self.zoom_out_btn = QPushButton(self)
        self.url_le = QLineEdit(self)

        self.browser = QWebEngineView()

        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.layout_init()
        self.btn_init()
        self.le_init()
        self.browser_init()

    def layout_init(self):
        self.h_layout.setSpacing(0)
        self.h_layout.addWidget(self.back_btn)
        self.h_layout.addWidget(self.forward_btn)
        self.h_layout.addWidget(self.refresh_btn)
        self.h_layout.addStretch(2)
        self.h_layout.addWidget(self.url_le)
        self.h_layout.addStretch(2)
        self.h_layout.addWidget(self.zoom_in_btn)
        self.h_layout.addWidget(self.zoom_out_btn)

        self.v_layout.addLayout(self.h_layout)
        self.v_layout.addWidget(self.browser)

        self.setLayout(self.v_layout)

    def browser_init(self):
        self.browser.load(QUrl('https://baidu.com'))

    def btn_init(self):
        self.back_btn.setIcon(QIcon('images/back.png'))
        self.forward_btn.setIcon(QIcon('images/forward.png'))
        self.refresh_btn.setIcon(QIcon('images/refresh.png'))
        self.zoom_in_btn.setIcon(QIcon('images/zoom_in.png'))
        self.zoom_out_btn.setIcon(QIcon('images/zoom_out.png'))

    def le_init(self):
        self.url_le.setFixedWidth(400)
        self.url_le.setPlaceholderText('Search or enter website name')

    def keyPressEvent(self, QKeyEvent):
        if QKeyEvent.key() == Qt.Key_Return or QKeyEvent.key() == Qt.Key_Enter:
            if self.url_le.hasFocus():
                if self.url_le.text().startswith('https://') or self.url_le.text().startswith('http://'):
                    self.browser.load(QUrl(self.url_le.text()))
                else:
                    self.browser.load(QUrl('https://'+self.url_le.text()))


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

Let's run it and find two problems:

  1. When the program runs for the first time, the baidu website is not displayed in the input box text.

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-9TFAIPHI-1641378754641)(data:image/svg+xml;utf8, )]

  1. When we enter in the input box“ http://python.org "After clicking enter, the web page can be loaded, but the input box does not display what should be displayed at present“ https://www.python.org/".

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-OVp4allY-1641378754641)(data:image/svg+xml;utf8, )]

Or after clicking "Downloads" in the page to jump to another page, the text in the input box should also change to“ https://www.python.org/downloads/".

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-WnP78O4s-1641378754642)(data:image/svg+xml;utf8, )]

According to the above questions, we know that we should set the text of the input box to the URL loaded by QWebEngineView. The QWebEngineView control has a signal urlChanged, which is emitted every time the URL to be loaded changes. In fact, we can connect this signal with the slot function. In the slot function, we can set the text of the input box to the URL to be loaded by QWebEngineView after the change (other signals such as loadStarted, loadFinished, etc. can also be used).

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-QDq7ENYC-1641378754642)(data:image/svg+xml;utf8, )]

We just need to be in browser_ Add a line of code connecting the signal and slot function to the init() function:

def browser_init(self):
    self.browser.load(QUrl('https://baidu.com'))
    self.browser.urlChanged.connect(lambda: self.url_le.setText(self.browser.url().toDisplayString()))

Call the url() method of QWebEngineView to obtain the QUrl object, but this is not a string type, so you also need to call the toDisplayString() method to obtain the url text string. Now run again and you will find that the text of the input box will change with the url currently loaded by QWebEngineView.

Next, we will improve the button functions, first of all, the back, forward and refresh in the upper left corner. Viewing the document, we can easily find that QWebEngineView has several slot functions to realize these three functions:

[the external link image transfer fails. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-cQ2AlZsI-1641378754643)(data:image/svg+xml;utf8, )]

The back() method implements the backward function, the forward() method implements the forward function, and the reload() method implements the refresh function. We just need to be on BTN next_ Add a few lines of code connecting the signal and slot function to the init() function:

def btn_init(self):
    self.back_btn.setIcon(QIcon('images/back.png'))
    self.forward_btn.setIcon(QIcon('images/forward.png'))
    self.refresh_btn.setIcon(QIcon('images/refresh.png'))
    self.zoom_in_btn.setIcon(QIcon('images/zoom_in.png'))
    self.zoom_out_btn.setIcon(QIcon('images/zoom_out.png'))

    self.back_btn.clicked.connect(self.browser.back)
    self.forward_btn.clicked.connect(self.browser.forward)
    self.refresh_btn.clicked.connect(self.browser.reload)

Run the program at this time, and you will find that the program can go back, forward and refresh like a real browser.

Finally, zoom in and out. To realize this function, we need to use the zoomFactor() method and setZoomFactor() method. The former obtains the current zoom value, and the latter sets the zoom value. That is, whenever the user clicks the zoom in or zoom out button, we only need to obtain the current zoom value first, and then increase the zoom value when zooming in, and decrease the zoom value when zooming out. First, implement the slot function. The code is as follows:

def zoom_in_func(self):
    self.browser.setZoomFactor(self.browser.zoomFactor()+0.1)

def zoom_out_func(self):
    self.browser.setZoomFactor(self.browser.zoomFactor()-0.1)

Then in BTN_ Add two lines of code connecting the signal and slot function to the init() function:

def btn_init(self):
    self.back_btn.setIcon(QIcon('images/back.png'))
    self.forward_btn.setIcon(QIcon('images/forward.png'))
    self.refresh_btn.setIcon(QIcon('images/refresh.png'))
    self.zoom_in_btn.setIcon(QIcon('images/zoom_in.png'))
    self.zoom_out_btn.setIcon(QIcon('images/zoom_out.png'))

    self.back_btn.clicked.connect(self.browser.back)
    self.forward_btn.clicked.connect(self.browser.forward)
    self.refresh_btn.clicked.connect(self.browser.reload)
    self.zoom_in_btn.clicked.connect(self.zoom_in_func)
    self.zoom_out_btn.clicked.connect(self.zoom_out_func)

Now run the next program, click the zoom in and zoom out button, and the page will zoom in and out accordingly:

However, the scope of enlargement and reduction is limited:

According to the document, we can know that the range is 0.25-5.0, and the default value is 1.0.

The complete code is as follows:

import sys
from PyQt5.QtCore import Qt, QUrl
from PyQt5.QtGui import QIcon
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit, QVBoxLayout, QHBoxLayout


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(1000, 600)

        self.back_btn = QPushButton(self)
        self.forward_btn = QPushButton(self)
        self.refresh_btn = QPushButton(self)
        self.zoom_in_btn = QPushButton(self)
        self.zoom_out_btn = QPushButton(self)
        self.url_le = QLineEdit(self)

        self.browser = QWebEngineView()

        self.h_layout = QHBoxLayout()
        self.v_layout = QVBoxLayout()

        self.layout_init()
        self.btn_init()
        self.le_init()
        self.browser_init()

    def layout_init(self):
        self.h_layout.setSpacing(0)
        self.h_layout.addWidget(self.back_btn)
        self.h_layout.addWidget(self.forward_btn)
        self.h_layout.addWidget(self.refresh_btn)
        self.h_layout.addStretch(2)
        self.h_layout.addWidget(self.url_le)
        self.h_layout.addStretch(2)
        self.h_layout.addWidget(self.zoom_in_btn)
        self.h_layout.addWidget(self.zoom_out_btn)

        self.v_layout.addLayout(self.h_layout)
        self.v_layout.addWidget(self.browser)

        self.setLayout(self.v_layout)

    def browser_init(self):
        self.browser.load(QUrl('https://baidu.com'))
        self.browser.urlChanged.connect(lambda: self.url_le.setText(self.browser.url().toDisplayString()))

    def btn_init(self):
        self.back_btn.setIcon(QIcon('images/back.png'))
        self.forward_btn.setIcon(QIcon('images/forward.png'))
        self.refresh_btn.setIcon(QIcon('images/refresh.png'))
        self.zoom_in_btn.setIcon(QIcon('images/zoom_in.png'))
        self.zoom_out_btn.setIcon(QIcon('images/zoom_out.png'))

        self.back_btn.clicked.connect(self.browser.back)
        self.forward_btn.clicked.connect(self.browser.forward)
        self.refresh_btn.clicked.connect(self.browser.reload)
        self.zoom_in_btn.clicked.connect(self.zoom_in_func)
        self.zoom_out_btn.clicked.connect(self.zoom_out_func)

    def le_init(self):
        self.url_le.setFixedWidth(400)
        self.url_le.setPlaceholderText('Search or enter website name')

    def keyPressEvent(self, QKeyEvent):
        if QKeyEvent.key() == Qt.Key_Return or QKeyEvent.key() == Qt.Key_Enter:
            if self.url_le.hasFocus():
                if self.url_le.text().startswith('https://') or self.url_le.text().startswith('http://'):
                    self.browser.load(QUrl(self.url_le.text()))
                else:
                    self.browser.load(QUrl('https://'+self.url_le.text()))

    def zoom_in_func(self):
        self.browser.setZoomFactor(self.browser.zoomFactor()+0.1)

    def zoom_out_func(self):
        self.browser.setZoomFactor(self.browser.zoomFactor()-0.1)


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

30.2 summary

  1. This simple browser can also add many functions or improve it to make it more like a real browser. For example, when the program runs for the first time, the forward and backward buttons should be set to unavailable, and they should also be set to unavailable when forward and backward are not possible (involving the history() method, which can be implemented by small partners themselves).

  2. Still that sentence - check the documents. If you have a function you want to implement in your mind, you can check the documentation to see if the control provides the corresponding method. Or your mind may be blank. In fact, you can also read the document first to see if there are any control methods you like, which may bring you inspiration.

Keywords: html chrome PyQt5

Added by suspect on Thu, 06 Jan 2022 03:57:51 +0200