应用PyQt5的QWebEngineView组件打造一款简略的浏览器
QWebEngineView是PyQt中的一个能够显示网页的组件,该组件封装了谷歌浏览器内核,功能强大。老手试着实现一下,锤炼本人的编码能力。
成品图片
1界面图片
2界面图片
首先重写一下QWebEngineView类的createWindow函数
这个函数在QWebEngineView中点击跳转关上新页面的时候会被调用,如果不重写的话,页面链接跳转到新页面的时候就会没有反馈。
class MyWebView(QWebEngineView): def __init__(self, my, *args): super(MyWebView, self).__init__(*args) self.my = my # self.view = None def createWindow(self, QWebEnginePage_WebWindowType): #如果是要在本页面显示的页面则return self return self.my.create_view() #创立一个新的容器显示新的页面
写一个用来装页面以及后退和后退刷新的界面
class Webbox(QWidget): def __init__(self, my, *args): super(Webbox, self).__init__(*args) self.my = my self.setGUI() def setGUI(self): self.webview = MyWebView(self.my, self) self.buttons = [] self.url_input = QLineEdit(self) self.function_group = QButtonGroup(self) self.function_group.setExclusive(True) self.url_input.setStyleSheet(MyStyle.getInputStyle()) self.homepage() self.webview.loadFinished.connect(self.update_view) icon = ['back.png', 'forward.png', 'reload.png', 'home.png'] for i in icon: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[1].clicked.connect(lambda: self.webview.forward()) self.buttons[0].clicked.connect(lambda: self.webview.back()) self.buttons[2].clicked.connect(lambda: self.webview.reload()) self.buttons[3].clicked.connect(self.homepage) self.url_input.returnPressed.connect(self.init) def homepage(self): self.webview.load(QUrl('https://www.baidu.com')) self.url_input.setText('https://www.baidu.com') def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.buttons[0].setGeometry(5, 5, 45, 30) self.buttons[1].setGeometry(50 * 1 + 5, 5, 45, 30) self.buttons[2].setGeometry(50 * 2 + 5, 5, 45, 30) self.buttons[3].setGeometry(50 * 3 + 5, 5, 45, 30) self.url_input.setGeometry(50 * 4 + 5, 5, self.width() - 4 * 50 + 10 - 3 * 35 - 80, 30) self.webview.setGeometry(0, 40, self.width(), self.height() - 35) def init(self): if 'http' in self.url_input.text(): self.webview.load(QUrl(self.url_input.text())) elif self.url_input.text() == '': self.zhuye() else: self.webview.load(QUrl(r'http://' + self.url_input.text())) self.url_input.setText(self.webview.url().toString()) def update_view(self): self.url_input.setText(self.webview.url().toString()) self.url_input.setCursorPosition(0) self.my.update_title(self) def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path)
创立一个装整个界面的窗口
class WebView(QWidget): def __init__(self, *args): super(WebView, self).__init__(*args) self.windows = [] self.buttons = [] self.setUI() def setUI(self): self.tabbar = QTabWidget(self) self.tabbar.setTabsClosable(True) self.tabbar.setStyleSheet(MyStyle.getQTabWidgetStyle()) self.tabbar.tabCloseRequested.connect(self.close_tab) self.setStyleSheet(MyStyle.getQwidgetStyle2()) # self.tabbar.setAttribute(Qt.WA_StyledBackground) self.proxies = QCheckBox('启用代理', self) self.proxies.clicked.connect(self.IsProxies) self.proxies.setStyleSheet(MyStyle.getCheckBoxStyle()) view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.buttonsname = ['shouchang1.png', 'shouchang2.png', 'more.png', 'add.png'] for i in self.buttonsname: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[3].setStyleSheet(MyStyle.getButtonStyle2()) self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) self.buttons[3].clicked.connect(self.create_view) # 创立一个新的Webobox容器来装新的页面 def create_view(self): try: view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.tabbar.setCurrentWidget(view) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) return view.webview except Exception as e: print(e) def close_tab(self, currentIndex): currentQWidget = self.tabbar.widget(currentIndex) currentQWidget.deleteLater() self.windows.remove(currentQWidget) self.tabbar.removeTab(currentIndex) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.proxies.move(self.width() - 160, 41) self.buttons[0].setGeometry(self.width() - 40 * 3 -80, 7 + 30, 26, 26) self.buttons[1].setGeometry(self.width() - 35 * 2, 5 + 30, 30, 30) self.buttons[2].setGeometry(self.width() - 40, 5 + 30, 30, 30) self.tabbar.setGeometry(0, 0, self.width(), self.height()) def update_title(self, view): self.tabbar.setTabText(self.tabbar.indexOf(view), view.webview.title()) #这一块代码用于获取代码运行的门路 def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path) # 这一块代码只是用于测试,具体性能没有实现 def IsProxies(self): if self.proxies.isChecked(): proxy = QtNetwork.QNetworkProxy() # Http拜访代理 proxy.setType = QtNetwork.QNetworkProxy.HttpProxy # 代理ip地址HttpProxy proxy.setHostName("127.0.0.1") # 端口号 proxy.setPort(8888) proxy.setUser("4") proxy.setPassword("1") QtNetwork.QNetworkProxy.setApplicationProxy(proxy)
代码中所用到的图片以及其余类
一个用来寄存QSS款式的类
因为不想从其余文件夹读取qss文件,所以间接写了一个款式类寄存qss款式,如果你只写了一个很简略的窗口,qss款式很少的时候能够应用这种办法,在打包exe的时候能够不必额定打包款式文件。
class MyStyle(): @staticmethod def getIconButtonStyle(): return ''' QPushButton{ background-color:rgba(0,0,0,0); border-radius:3px; boder:none; } QPushButton:hover{ background-color:rgb(230,230,230); } QPushButton:pressed{ background-color:rgb(210,210,210); } ''' @staticmethod def getButtonStyle2(): return ''' QPushButton{ background-color:rgb(236,245,255); font-family:"SimSun"; funt-size:18px; } QPushButton:hover{ background-color:rgb(64,158,255); color:white; } QPushButton:pressed{ background-color:rgb(58,142,230); } ''' @staticmethod def getInputStyle(): return ''' QLineEdit{ border-radius:3px; border-style:solid; border-width:1px; font-size: 16px; padding-right:40px; font-family:"Microsoft YaHei"; border-color:rgb(200,200,200); background-color:white; } QLineEdit:hover{ border-color:rgb(150,150,150); } QLineEdit:focus{ border-color:rgb(102,177,255); } ''' @staticmethod def getQTabWidgetStyle(): return ''' QTabWidget{ background-color:rgb(240,240,240); } QTabBar::tab { background-color:rgb(236,245,255); height:30px; padding-left:10px; padding-right:10px; margin-top:0px; min-width:150px; max-width:150px; } QTabBar::tab:hover{ color:rgb(64,158,255); } QTabBar::tab:selected{ color:white; background:rgb(64,158,255); } QTabBar::close-button{ image: url(static/close.png); background-color:rgba(0,0,0,0); } QTabBar::close-button:hover { image: url(static/close2.png); } ''' @staticmethod def getQwidgetStyle2(): return''' QWidget{ background-color:rgb(250,250,250); border:none; } ''' @staticmethod def getCheckBoxStyle(): return ''' QCheckBox{ color:rgb(150,150,150); Background-color:rgba(0,0,0,0); } QCheckBox:hover{ Color:rgb(149,216,255); } QCheckBox:checked{ color:rgb(64,158,255); } '''
代码中用到的按钮图标
下载窗口中用到的按钮图标文件请点击这里
整体代码
##!/usr/bin/python3# -*- coding: utf-8 -*-# @Author : Tang Shimengimport osimport sysfrom PyQt5.QtWebEngineWidgets import QWebEngineViewfrom PyQt5 import QtNetwork, QtGuifrom PyQt5.QtCore import QUrlfrom PyQt5.QtGui import QPixmap, QIconfrom PyQt5.QtWidgets import QWidget, QTabWidget, QApplication, QButtonGroup, QLineEdit, QPushButton, QCheckBoxclass MyStyle(): @staticmethod def getIconButtonStyle(): return ''' QPushButton{ background-color:rgba(0,0,0,0); border-radius:3px; boder:none; } QPushButton:hover{ background-color:rgb(230,230,230); } QPushButton:pressed{ background-color:rgb(210,210,210); } ''' @staticmethod def getButtonStyle2(): return ''' QPushButton{ background-color:rgb(236,245,255); font-family:"SimSun"; funt-size:18px; } QPushButton:hover{ background-color:rgb(64,158,255); color:white; } QPushButton:pressed{ background-color:rgb(58,142,230); } ''' @staticmethod def getInputStyle(): return ''' QLineEdit{ border-radius:3px; border-style:solid; border-width:1px; font-size: 16px; padding-right:40px; font-family:"Microsoft YaHei"; border-color:rgb(200,200,200); background-color:white; } QLineEdit:hover{ border-color:rgb(150,150,150); } QLineEdit:focus{ border-color:rgb(102,177,255); } ''' @staticmethod def getQTabWidgetStyle(): return ''' QTabWidget{ background-color:rgb(240,240,240); } QTabBar::tab { background-color:rgb(236,245,255); height:30px; padding-left:10px; padding-right:10px; margin-top:0px; min-width:150px; max-width:150px; } QTabBar::tab:hover{ color:rgb(64,158,255); } QTabBar::tab:selected{ color:white; background:rgb(64,158,255); } QTabBar::close-button{ image: url(static/close.png); background-color:rgba(0,0,0,0); } QTabBar::close-button:hover { image: url(static/close2.png); } ''' @staticmethod def getQwidgetStyle2(): return''' QWidget{ background-color:rgb(250,250,250); border:none; } ''' @staticmethod def getCheckBoxStyle(): return ''' QCheckBox{ color:rgb(150,150,150); Background-color:rgba(0,0,0,0); } QCheckBox:hover{ Color:rgb(149,216,255); } QCheckBox:checked{ color:rgb(64,158,255); } '''class MyWebView(QWebEngineView): def __init__(self, my, *args): super(MyWebView, self).__init__(*args) self.my = my # self.view = None def createWindow(self, QWebEnginePage_WebWindowType): return self.my.create_view()class Webbox(QWidget): def __init__(self, my, *args): super(Webbox, self).__init__(*args) self.my = my self.setGUI() def setGUI(self): self.webview = MyWebView(self.my, self) self.buttons = [] self.url_input = QLineEdit(self) self.function_group = QButtonGroup(self) self.function_group.setExclusive(True) self.url_input.setStyleSheet(MyStyle.getInputStyle()) self.homepage() self.webview.loadFinished.connect(self.update_view) icon = ['back.png', 'forward.png', 'reload.png', 'home.png'] for i in icon: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[1].clicked.connect(lambda: self.webview.forward()) self.buttons[0].clicked.connect(lambda: self.webview.back()) self.buttons[2].clicked.connect(lambda: self.webview.reload()) self.buttons[3].clicked.connect(self.homepage) self.url_input.returnPressed.connect(self.init) def homepage(self): self.webview.load(QUrl('https://www.baidu.com')) self.url_input.setText('https://www.baidu.com') def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.buttons[0].setGeometry(5, 5, 45, 30) self.buttons[1].setGeometry(50 * 1 + 5, 5, 45, 30) self.buttons[2].setGeometry(50 * 2 + 5, 5, 45, 30) self.buttons[3].setGeometry(50 * 3 + 5, 5, 45, 30) self.url_input.setGeometry(50 * 4 + 5, 5, self.width() - 4 * 50 + 10 - 3 * 35 - 80, 30) self.webview.setGeometry(0, 40, self.width(), self.height() - 35) def init(self): if 'http' in self.url_input.text(): self.webview.load(QUrl(self.url_input.text())) elif self.url_input.text() == '': self.zhuye() else: self.webview.load(QUrl(r'http://' + self.url_input.text())) self.url_input.setText(self.webview.url().toString()) def update_view(self): self.url_input.setText(self.webview.url().toString()) self.url_input.setCursorPosition(0) self.my.update_title(self) def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path)class WebView(QWidget): def __init__(self, *args): super(WebView, self).__init__(*args) self.windows = [] self.buttons = [] self.setUI() def setUI(self): self.tabbar = QTabWidget(self) self.tabbar.setTabsClosable(True) self.tabbar.setStyleSheet(MyStyle.getQTabWidgetStyle()) self.tabbar.tabCloseRequested.connect(self.close_tab) self.setStyleSheet(MyStyle.getQwidgetStyle2()) # self.tabbar.setAttribute(Qt.WA_StyledBackground) self.proxies = QCheckBox('启用代理', self) self.proxies.clicked.connect(self.IsProxies) self.proxies.setStyleSheet(MyStyle.getCheckBoxStyle()) view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.buttonsname = ['shouchang1.png', 'shouchang2.png', 'more.png', 'add.png'] for i in self.buttonsname: button = QPushButton(self) button.setIcon(QIcon(QPixmap(self.get_resource_path('static/' + i)))) button.setStyleSheet(MyStyle.getIconButtonStyle()) self.buttons.append(button) self.buttons[3].setStyleSheet(MyStyle.getButtonStyle2()) self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) self.buttons[3].clicked.connect(self.create_view) # 创立一个新的Webobox容器来装新的页面 def create_view(self): try: view = Webbox(self) self.windows.append(view) self.tabbar.addTab(view, view.webview.title()) self.tabbar.setCurrentWidget(view) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) return view.webview except Exception as e: print(e) def close_tab(self, currentIndex): currentQWidget = self.tabbar.widget(currentIndex) currentQWidget.deleteLater() self.windows.remove(currentQWidget) self.tabbar.removeTab(currentIndex) if self.tabbar.count() * 150 > self.width(): self.buttons[3].setGeometry(self.width()-40, 0, 30, 30) else: self.buttons[3].setGeometry(self.tabbar.count() * 170, 0, 30, 30) def resizeEvent(self, a0: QtGui.QResizeEvent) -> None: self.proxies.move(self.width() - 160, 41) self.buttons[0].setGeometry(self.width() - 40 * 3 -80, 7 + 30, 26, 26) self.buttons[1].setGeometry(self.width() - 35 * 2, 5 + 30, 30, 30) self.buttons[2].setGeometry(self.width() - 40, 5 + 30, 30, 30) self.tabbar.setGeometry(0, 0, self.width(), self.height()) def update_title(self, view): self.tabbar.setTabText(self.tabbar.indexOf(view), view.webview.title()) def get_resource_path(self, relative_path): if hasattr(sys, '_MEIPASS'): return os.path.join(sys._MEIPASS, relative_path) return os.path.join(os.path.abspath("."), relative_path) def IsProxies(self): if self.proxies.isChecked(): proxy = QtNetwork.QNetworkProxy() # Http拜访代理 proxy.setType = QtNetwork.QNetworkProxy.HttpProxy # 代理ip地址HttpProxy proxy.setHostName("127.0.0.1") # 端口号 proxy.setPort(8888) proxy.setUser("4") proxy.setPassword("1") QtNetwork.QNetworkProxy.setApplicationProxy(proxy)if __name__ == '__main__': app = QApplication(sys.argv) window = WebView() window.resize(800, 500) window.setMinimumWidth(800) window.setWindowTitle('Browser') window.setWindowIcon(QIcon(window.get_resource_path("static/ico.png"))) window.show() sys.exit(app.exec_())
代码逻辑不难,重在参加。