Qt 5 C++ – QtWebEngine

Rate this post

Trong Qt có module QtWebEngine cung cấp các lớp C++ hỗ trợ dựng trang web từ mã HTML, XML, SVG, CSS, Javascript lên một chương trình Qt, dùng cho các hệ điều hành không có sẵn web engine. Đối với các hệ điều hành có sẵn web engine thì chúng ta có thể dùng module QtWebKit, tuy nhiên module này đã bị loại bỏ khỏi Qt 5.5, nên hầu như chúng ta sẽ dùng module QtWebEngine để làm việc với web.

Tổng quan về Qt WebEngine

Kiến trúc:

qtwebengine-architecture

Theo sơ đồ trên thì module QtWebEngine bao gồm những thành phần sau:

  • Qt WebEngine Widgets: cung cấp các thư viện tạo giao diện người dùng với Widget.
  • Qt WebEngine: cung cấp các lớp tạo giao diện người dùng với QtQuick.
  • Qt WebEngine Core: làm việc với Chromium.
  • Qt WebEngine Process: dựng trang, xử lý Javascript.

Module Qt WebEngine Core được xây dựng dựa trên Chromium. Các thành phần của Chromium chịu trách nhiệm trong việc xử lý kết nối mạng, xây dựng trang web, xử lý Javascript, HTML… Ngoài WebEngine thì Qt còn có module WebKit cũng có chức năng thao tác với trang web nhưng rất hạn chế, WebEngine nặng hơn, cung cấp nhiều chức năng thao tác trực tiếp với web hơn WebKit. Dù QtWebEngine được xây dựng trên Chromium nhưng không có nghĩa là module này có các dịch vụ hỗ trợ thêm như của trình duyệt Chrome do Google phát triển.

Cài đặt

Mặc định module QtWebEngine không có sẵn trong Qt Creator sử dụng trình biên dịch MinGW, bạn phải chuyển qua sử dụng Qt Creator dùng trình biên dịch MSVC hoặc sử dụng Add-In trong Visual Studio.

Capture Capture1

Hoặc có một cách khác là biên dịch lại toàn bộ mã nguồn Qt và Chromium sử dụng trình biên dịch MinGW, cách này rất phức tạp nên mình sẽ không đề cập ở đây.

Ngoài ra Visual Studio Add-In cũng không chấp nhận Visual Studio phiên bản Express (hoặc Community) nên cách này cũng khó khả thi (trừ khi bạn dùng crack). Nên tóm lại trong phần này mình sẽ sử dụng Qt Creator với trình biên dịch msvc từ Visual Studio 2015.

Lưu ý: tại thời điểm viết bài này trình biên dịch msvc đi kèm với Qt Creator khi download trên trang chủ không sử dụng được, mình phải cài Visual Studio 2015 Community rồi chỉ định Qt Creator sử dụng trình biên dịch của VS mới chạy được (khi cài Visual Studio 2015 bạn phải tích chọn cài 2 thành phần là Programming Languages→Visual C++Windows and Web Development→Universal Windows App Developments Tools vì đây là 2 thành phần cần thiết để biên dịch trong Qt nhưng không được cài mặc định).

Bây giờ chúng ta sẽ đi tìm hiểu một số chức năng có trong Qt WebEngine.

Mở trang web

Để mở một trang web và hiển thị thì chúng ta dùng lớp QWebEngineView. Chúng ta tạo một project mới.

...
QT += webenginewidgets
...

Trong file .pro chúng ta phải khai báo module QtWebEngine bằng dòng code trên.

#include <QMainWindow>

#include <QWebEngineView>

class Browser : public QMainWindow
{
    Q_OBJECT
public:
    explicit Browser(QWidget *parent = 0);

private:
    QWebEngineView *view;
};

Chúng ta định nghĩa lớp Browser kế thừa từ lớp QMainWindow, bên trong lớp này có một đối tượng QWebEngineView.

#include "browser.h"

Browser::Browser(QWidget *parent) : QMainWindow(parent)
{
    view = new QWebEngineView(this);
    view->load(QUrl("https://phocode.com"));
    setCentralWidget(view);
}

Để tải một trang web về thì chúng ta chỉ cần gọi phương thức load() và truyền vào một đối tượng QUrl. Phương thức setCentralWidget() sẽ thiết lập đối tượng QWebEngineView làm giao diện chính của cửa sổ.

#include "browser.h"
#include <QApplication>
#include <qtwebenginewidgetsglobal.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Browser browser;
    browser.show();

    return a.exec();
}

Trong file main.cpp chúng ta chỉ tạo đối tượng Browser rồi gọi phương thức show() như bình thường.

Capture

Một số tính năng của QWebEngineView

Lớp QWebEngineView có sẵn một số tính năng cơ bản của một trình duyệt web. Chúng ta sẽ tìm hiểu qua ví dụ dưới đây:

#include <QMainWindow>
#include <QWebEngineView>
#include <QLineEdit>
#include <QUrl>
#include <QToolBar>

class Browser : public QMainWindow
{
    Q_OBJECT
public:
    explicit Browser(QWidget *parent = 0);

signals:

public slots:
    void adjustLocation();
    void changeLocation();
    void adjustTitle();
    void setProgress(int p);
private:
    QWebEngineView *view;
    QLineEdit   *locationEdit;
    int progress;
};

Chúng ta định nghĩa lại lớp Browser. Lớp QWebEngineView có một số Signal đặc biệt được phát đi trong quá trình duyệt trang web nên chúng ta có thể định nghĩa một số phương thức Slot và thuộc tính để bắt và xử lý các signal đó.

#include "browser.h"

Browser::Browser(QWidget *parent) : QMainWindow(parent)
{
    view = new QWebEngineView(this);
    view->load(QUrl("http://google.com"));
    connect(view, SIGNAL(loadFinished(bool)), this, SLOT(adjustLocation()));
    connect(view, SIGNAL(titleChanged(QString)), this, SLOT(adjustTitle()));
    connect(view, SIGNAL(loadProgress(int)), this, SLOT(setProgress(int)));

    locationEdit = new QLineEdit(this);
    locationEdit->setSizePolicy(QSizePolicy::Expanding, locationEdit->sizePolicy().verticalPolicy());
    connect(locationEdit, SIGNAL(returnPressed()), SLOT(changeLocation()));

    QToolBar *toolBar = addToolBar(tr("Navigation"));
    toolBar->addAction(view->pageAction(QWebEnginePage::Back));
    toolBar->addAction(view->pageAction(QWebEnginePage::Forward));
    toolBar->addAction(view->pageAction(QWebEnginePage::Reload));
    toolBar->addAction(view->pageAction(QWebEnginePage::Stop));
    toolBar->addWidget(locationEdit);

    setCentralWidget(view);
}

void Browser::adjustLocation()
{    
    locationEdit->setText(view->url().toString());
}

void Browser::changeLocation()
{
    QUrl url = QUrl::fromUserInput(locationEdit->text());
    view->load(url);
    view->setFocus();
}

void Browser::adjustTitle()
{
    if(progress <= 0 || progress >= 100)
        setWindowTitle(view->title());
    else
        setWindowTitle(QString("%1 (%2%)").arg(view->title()).arg(progress));
}

void Browser::setProgress(int p)
{
    progress = p;
    adjustTitle();
}

Trong file browser.cpp chúng ta xây dựng lớp Browser thành một trình duyệt web đơn giản.

connect(view, SIGNAL(loadFinished(bool)), this, SLOT(adjustLocation()));
connect(view, SIGNAL(titleChanged(QString)), this, SLOT(adjustTitle()));
connect(view, SIGNAL(loadProgress(int)), this, SLOT(setProgress(int)));

Tín hiệu loadFinished() được phát đi khi QWebEngineView đã tải xong trang web. Chúng ta xử lý bằng phương thức adjustLocation(). 

Tín hiệu titleChanged() được phát đi khi tiêu đề của trang web thay đổi, tức là gần như mỗi lần loadFinished() được phát đi thì titleChanged() cũng được phát đi cùng luôn.

Tín hiệu loadProgress() được phát đi khi mỗi phần tử của trang web được tải xong, ví dụ một trang web mang theo rất nhiều file ảnh, file javascript, file css… mỗi lần những file này được tải xong thì tín hiệu này được phát đi, tín hiệu này mang theo một con số từ 0 đến 100 có nghĩa là trang web đang được tải bao nhiêu %.

locationEdit = new QLineEdit(this);
locationEdit->setSizePolicy(QSizePolicy::Expanding, locationEdit->sizePolicy().verticalPolicy());
connect(locationEdit, SIGNAL(returnPressed()), SLOT(changeLocation()));

Ở đây chúng ta định nghĩa một đối tượng QLineEdit dùng làm thanh địa chỉ của trình duyệt web. Phương thức setSizePolicy() sẽ quy định kích thước của QLineEdit. Tín hiệu returnPressed() được phát đi khi chúng ta gõ phím Enter trên QLineEdit, chúng ta bắt tín hiệu này bằng slot changeLocation().

QToolBar *toolBar = addToolBar(tr("Navigation"));
toolBar->addAction(view->pageAction(QWebEnginePage::Back));
toolBar->addAction(view->pageAction(QWebEnginePage::Forward));
toolBar->addAction(view->pageAction(QWebEnginePage::Reload));
toolBar->addAction(view->pageAction(QWebEnginePage::Stop));
toolBar->addWidget(locationEdit);

Ở đây chúng ta tạo thêm một thanh toolbar, ngoài việc dùng để chứa thanh địa chỉ ở trên, chúng ta còn dùng thêm các đối tượng Action có sẵn của lớp QWebEnginePage, lớp này có thuộc tính QWebEnginePage::WebAction cung cấp một số đối tượng Action có các chức năng cơ bản của một trình duyệt web và thậm chí là có cả icon sẵn. Ví dụ ở trên Back là nút quay lại trang vừa xem, Forward là nút đi tới trang vừa mở, Reload là nút refresh trình duyệt, Stop là nút dừng tải trang.

void Browser::adjustLocation()
{    
    locationEdit->setText(view->url().toString());
}

Phương thức adjustLocation() chỉ đơn giản là thiết lập lại đoạn text trong thanh địa chỉ.

void Browser::changeLocation()
{
    QUrl url = QUrl::fromUserInput(locationEdit->text());
    view->load(url);
    view->setFocus();
}

Phương thức changeLocation() sẽ được gọi khi chúng ta gõ phím Enter trên thanh địa chỉ, lúc này chúng ta tiến hành tải lại trang web.

void Browser::adjustTitle()
{
    if(progress <= 0 || progress >= 100)
        setWindowTitle(view->title());
    else
        setWindowTitle(QString("%1 (%2%)").arg(view->title()).arg(progress));
}

Phương thức adjustTitle() sẽ được gọi khi trang web được tải xong, hoặc một phần của trang web được tải xong, vì ở đây chúng ta chèn thêm số % trang web đã được tải là bao nhiêu.

void Browser::setProgress(int p)
{
    progress = p;
    adjustTitle();
}

Trong lớp Browser chúng ta định nghĩa thuộc tính progress dùng để lưu số % trang web đã được tải. Phương thức setProgress() sẽ được gọi khi QWebEngineView phát tín hiệu loadProgress(), lúc này chúng ta thiết lập thông số mới cho thuộc tính progress, đồng thời gọi lại phương thức adjustTitle().

#include "browser.h"
#include <QApplication>
#include <qtwebenginewidgetsglobal.h>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    Browser browser;
    browser.show();

    return a.exec();
}

Trong file main.cpp chúng ta chỉ tạo đối tượng Browser và gọi phương thức show().

Untitled

2 1 vote
Article Rating
Subscribe
Thông báo cho tôi qua email khi
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments