WebKit w PyQt - renderowanie stron www

Wydanie Qt 4.4 przyniosło integrację silnika renderowania stron www - WebKit. Z silnika można korzystać zarówno w samym Qt, czy w API dostępnych dla innych języków, w tym PyQt4. W przypadku Linuksa i pokrewnych systemów należy upewnić się czy posiadamy zainstalowany pakiet qt-webkit (jeżeli Qt jest rozbijana na oddzielne moduły). W Qt Designer powinniśmy widzieć widżet "QWebView" w zakładce "Display Widgets".

Najprostszy przykład wykorzystania widgeta QWebView do wyświetlenia podanej strony wyglądałby tak:

#!/usr/bin/env python

import sys
from PyQt4.QtCore import *
from PyQt4.QtGui import *
from PyQt4.QtWebKit import *

app = QApplication(sys.argv)

web = QWebView()
web.load(QUrl("http://google.pl"))
web.show()

sys.exit(app.exec_())
Efekt będzie np taki:
qtwebkit0

Funkcjonalność jak na razie niewielka, lecz moduł WebKit dostarcza kilka rozbudowanych klas. Załadowana strona www staje się obiektem QWebPage, a obiekt ten ma własną historię URLi - QWebHistory. Do tego klasa QWebView może wysyłać różne sygnały - jak stan ładowania strony, kliknięcie na link znajdujący się na stronie www, czy też wiele innych możliwości.

Zajmiemy się teraz stworzeniem bardziej rozbudowanej przeglądarki internetowej. Zaczniemy od stworzenia interfejsu w QtDesignerze - składającego się z przycisków: wstecz, dalej, zatrzymaj, odśwież, paska na adres oraz oczywiście widżeta QtWebView. Oto jak mógłby wyglądać (zapisałem pod nazwą httpWidget.ui):

qtwebkit

Tworzymy teraz odpowiadającą interfejsowi klasę Pythona:
pyuic4 httpWidget.ui > httpWidget.py
I możemy przystąpić do jego oprogramowania:
  • Połączyć sygnały z odpowiednimi slotami
    • Sygnały pochodzące z QWebView (stan ładowania strony, tytuł strony itp.)
    • Sygnały pochodzące z przycisków i wpływające na zachowanie QWebView (zatrzymanie ładowania strony, historia, podanie URLa)
  • Ustawić wygląd interfejsu
Oto gotowy kod:
# -*- coding: utf-8 -*-
import sys

from PyQt4 import QtCore, QtGui
from httpWidget import Ui_HttpWidget

class httpWidget(QtGui.QWidget):
	def __init__(self, parent=None):
		super(httpWidget, self).__init__(parent)
		self.ui = Ui_HttpWidget()
		self.ui.setupUi(self)
		
		# set margins
		l = self.layout()
		l.setMargin(0)
		self.ui.horizontalLayout.setMargin(5)
		
		# set the default page
		url = 'http://google.pl'
		self.ui.url.setText(url)
		
		# load page
		self.ui.webView.setUrl(QtCore.QUrl(url))
		
		# history buttons:
		self.ui.back.setEnabled(False)
		self.ui.next.setEnabled(False)
		
		QtCore.QObject.connect(self.ui.back,QtCore.SIGNAL("clicked()"), self.back)
		QtCore.QObject.connect(self.ui.next,QtCore.SIGNAL("clicked()"), self.next)
		QtCore.QObject.connect(self.ui.url,QtCore.SIGNAL("returnPressed()"), self.url_changed)
		QtCore.QObject.connect(self.ui.webView,QtCore.SIGNAL("linkClicked (const QUrl&)"), self.link_clicked)
		QtCore.QObject.connect(self.ui.webView,QtCore.SIGNAL("urlChanged (const QUrl&)"), self.link_clicked)
		QtCore.QObject.connect(self.ui.webView,QtCore.SIGNAL("loadProgress (int)"), self.load_progress)
		QtCore.QObject.connect(self.ui.webView,QtCore.SIGNAL("titleChanged (const QString&)"), self.title_changed)
		QtCore.QObject.connect(self.ui.reload,QtCore.SIGNAL("clicked()"), self.reload_page)
		QtCore.QObject.connect(self.ui.stop,QtCore.SIGNAL("clicked()"), self.stop_page)
		
		QtCore.QMetaObject.connectSlotsByName(self)
	
	def url_changed(self):
		"""
		Url have been changed by user
		"""
		page = self.ui.webView.page()
		history = page.history()
		if history.canGoBack():
			self.ui.back.setEnabled(True)
		else:
			self.ui.back.setEnabled(False)
		if history.canGoForward():
			self.ui.next.setEnabled(True)
		else:
			self.ui.next.setEnabled(False)
		
		url = self.ui.url.text()
		self.ui.webView.setUrl(QtCore.QUrl(url))
		
	def stop_page(self):
		"""
		Stop loading the page
		"""
		self.ui.webView.stop()
	
	def title_changed(self, title):
		"""
		Web page title changed - change the tab name
		"""
		self.setWindowTitle(title)
	
	def reload_page(self):
		"""
		Reload the web page
		"""
		self.ui.webView.setUrl(QtCore.QUrl(self.ui.url.text()))
	
	def link_clicked(self, url):
		"""
		Update the URL if a link on a web page is clicked
		"""
		page = self.ui.webView.page()
		history = page.history()
		if history.canGoBack():
			self.ui.back.setEnabled(True)
		else:
			self.ui.back.setEnabled(False)
		if history.canGoForward():
			self.ui.next.setEnabled(True)
		else:
			self.ui.next.setEnabled(False)
		
		self.ui.url.setText(url.toString())
	
	def load_progress(self, load):
		"""
		Page load progress
		"""
		if load == 100:
			self.ui.stop.setEnabled(False)
		else:
			self.ui.stop.setEnabled(True)
		
	def back(self):
		"""
		Back button clicked, go one page back
		"""
		page = self.ui.webView.page()
		history = page.history()
		history.back()
		if history.canGoBack():
			self.ui.back.setEnabled(True)
		else:
			self.ui.back.setEnabled(False)
	
	def next(self):
		"""
		Next button clicked, go to next page
		"""
		page = self.ui.webView.page()
		history = page.history()
		history.forward()
		if history.canGoForward():
			self.ui.next.setEnabled(True)
		else:
			self.ui.next.setEnabled(False)

if __name__ == "__main__":
	app = QtGui.QApplication(sys.argv)
	myapp = httpWidget()
	myapp.show()
	sys.exit(app.exec_())
Zapisz powyższy kod do pliku znajdującego się w tym samym katalogu co projekt interfejsu i uruchom (ja użyłem run.py):
python run.py
Przykładowy efekt to:
qtwebkit1
W konstruktorze podajemy adres startowej strony, a także m.in. zmniejszamy marginesy między poszczególnymi widgetami. Następnie definiujemy wszystkie sloty:
  • url_changed - użytkownik zmienił URL w QLineEdit, pobieramy go i próbujemy utworzyć podaną stronę (przydałoby się sprawdzanie poprawności, dodawanie http itp.)
  • stop_page - kliknięto przycisk stop - kończymy ładowanie strony
  • title_changed - QWebView wysyła tytuł załadowanej strony, gdy ją pobierze - wykorzystujemy by ustawić tytuł okna aplikacji
  • reload_page - kliknięto przycisk odświeżenia - ponownie ładujemy stronę
  • link_clicked - użytkownik kliknął w link na załadowanej stronie. Aktualizujemy URL w QLineEdit
  • load_progress - obserwujemy postęp ładowania strony i wyłączamy przycisk stop po zakończeniu pobierania strony
  • back - kliknięto przycisk wstecz - ładujemy poprzedni URL
  • next - kliknięto przycisk dalej - ładujemy następny URL z historii przeglądania
Powyższa aplikacja posiada już bazową funkcjonalność i prosty działający interfejs, lecz możliwości klas qt-webkit są znacznie większe - chętnym polecam odwiedzenie dokumentacji. Należy też zwrócić uwagę że qt-webkit w Qt 4.4 nie obsługuje jeszcze wtyczek przeglądarek. Funkcjonalność ta została dodana do Qt 4.5 (jak i kilka innych).

Kod źródłowy

Pobierz kod przeglądarki zaprezentowanej w artykule.
RkBlog

PyQt, 6 December 2008

Comment article
Comment article RkBlog main page Search RSS Contact