如何在PyQt5 Python浏览器中启用新标签与JavaScript window.open()功能
解决PyQt5浏览器中window.open()和新标签页失效的问题
我看了你的代码,问题主要出在JavaScript窗口权限设置和新窗口/标签页的处理逻辑上,下面一步步帮你修复:
首先,明确几个核心问题:
- 你在
Ui_MainWindow里写的createWindow方法不会被调用,因为这个类不是QWebEngineView或QWebEnginePage的子类,Qt无法识别这个重写方法。 - 你设置
JavascriptCanOpenWindows的方式完全错误,那不是有效的Python代码,应该通过浏览器视图的settings对象来配置。 newtab方法的实现逻辑不对,直接调用枚举值没有实际作用,需要创建新的浏览器实例。
修复方案1:让window.open()打开新窗口
我们需要自定义一个QWebEngineView子类,重写它的createWindow方法,同时正确开启JavaScript打开窗口的权限:
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtWebEngineWidgets from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineSettings # 自定义浏览器视图类,重写createWindow处理新窗口请求 class CustomWebEngineView(QtWebEngineWidgets.QWebEngineView): def createWindow(self, windowType): if windowType == QWebEnginePage.WebBrowserWindow or windowType == QWebEnginePage.WebBrowserTab: # 创建新的浏览器窗口 new_view = CustomWebEngineView() new_view.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) new_view.show() return new_view return super().createWindow(windowType) class Ui_MainWindow(object): def back(self): self.webView.back() def forward(self): self.webView.forward() def reload(self): self.webView.reload() def stop(self): self.webView.stop() def newtab(self): # 手动打开新窗口 new_view = CustomWebEngineView() new_view.load(QtCore.QUrl("about:blank")) new_view.setAttribute(QtCore.Qt.WA_DeleteOnClose, True) new_view.show() def home(self): self.webView.load(QtCore.QUrl("http://pyxisad.com")) def search(self): url = self.ln_addressbar.text() # 补全协议,避免输入网址不带http的问题 if not url.startswith(('http://', 'https://')): url = 'http://' + url self.webView.load(QtCore.QUrl(url)) def setupUi(self, MainWindow): MainWindow.setObjectName("PyxisAd") MainWindow.resize(800, 600) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") # 工具栏按钮(保留你的原有代码) self.tb_back = QtWidgets.QToolButton(self.centralwidget) self.tb_back.setGeometry(QtCore.QRect(10, 20, 41, 31)) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("icons/back.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_back.setIcon(icon) self.tb_back.setIconSize(QtCore.QSize(32, 32)) self.tb_back.setObjectName("tb_back") self.tb_back.clicked.connect(self.back) self.tb_reload = QtWidgets.QToolButton(self.centralwidget) self.tb_reload.setGeometry(QtCore.QRect(60, 20, 41, 31)) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("icons/reload.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_reload.setIcon(icon1) self.tb_reload.setIconSize(QtCore.QSize(32, 32)) self.tb_reload.setObjectName("tb_reload") self.tb_reload.clicked.connect(self.reload) self.tb_forward = QtWidgets.QToolButton(self.centralwidget) self.tb_forward.setGeometry(QtCore.QRect(110, 20, 41, 31)) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap("icons/forword.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_forward.setIcon(icon2) self.tb_forward.setIconSize(QtCore.QSize(32, 32)) self.tb_forward.setObjectName("tb_forward") self.tb_forward.clicked.connect(self.forward) self.tb_home = QtWidgets.QToolButton(self.centralwidget) self.tb_home.setGeometry(QtCore.QRect(160, 20, 41, 31)) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap("icons/home.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_home.setIcon(icon3) self.tb_home.setIconSize(QtCore.QSize(32, 32)) self.tb_home.setObjectName("tb_home") self.tb_home.clicked.connect(self.home) # 添加新标签页按钮 self.tb_newtab = QtWidgets.QToolButton(self.centralwidget) self.tb_newtab.setGeometry(QtCore.QRect(210, 20, 41, 31)) icon_newtab = QtGui.QIcon() icon_newtab.addPixmap(QtGui.QPixmap("icons/newtab.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_newtab.setIcon(icon_newtab) self.tb_newtab.setIconSize(QtCore.QSize(32, 32)) self.tb_newtab.setObjectName("tb_newtab") self.tb_newtab.clicked.connect(self.newtab) self.ln_addressbar = QtWidgets.QLineEdit(self.centralwidget) self.ln_addressbar.setGeometry(QtCore.QRect(260, 20, 441, 31)) self.ln_addressbar.setObjectName("ln_addressbar") self.ln_addressbar.setPlaceholderText("Enter URL..") # 支持回车搜索 self.ln_addressbar.returnPressed.connect(self.search) self.tb_search = QtWidgets.QToolButton(self.centralwidget) self.tb_search.setGeometry(QtCore.QRect(710, 20, 41, 31)) icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap("icons/search.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_search.setIcon(icon4) self.tb_search.setIconSize(QtCore.QSize(32, 32)) self.tb_search.setObjectName("tb_search") self.tb_search.clicked.connect(self.search) # 使用自定义的浏览器视图 self.webView = CustomWebEngineView(self.centralwidget) self.webView.setGeometry(QtCore.QRect(0, 60, 800, 540)) self.webView.setUrl(QtCore.QUrl("about:blank")) self.webView.setObjectName("webView") # 开启JavaScript允许打开窗口的权限 settings = self.webView.settings() settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True) settings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows, True) settings.setAttribute(QWebEngineSettings.PluginsEnabled, True) MainWindow.setCentralWidget(self.centralwidget) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("PyxisAd", "PyxisAd")) self.tb_back.setText(_translate("PyxisAd", "back")) self.tb_reload.setText(_translate("PyxisAd", "reload")) self.tb_forward.setText(_translate("PyxisAd", "forward")) self.tb_home.setText(_translate("PyxisAd", "home")) self.tb_newtab.setText(_translate("PyxisAd", "new tab")) self.tb_search.setText(_translate("PyxisAd", "search")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) MainWindow = QtWidgets.QMainWindow() ui = Ui_MainWindow() ui.setupUi(MainWindow) MainWindow.show() sys.exit(app.exec_())
修复方案2:让window.open()打开新标签页(更像现代浏览器)
如果想要在同一个窗口里用标签页展示新页面,需要把浏览器视图放在QTabWidget里,修改核心部分:
from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5 import QtWebEngineWidgets from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineSettings # 自定义浏览器视图类 class CustomWebEngineView(QtWebEngineWidgets.QWebEngineView): pass # 带标签栏的主浏览器窗口 class TabbedBrowser(QtWidgets.QMainWindow): def __init__(self): super().__init__() self.setObjectName("PyxisAd") self.resize(800, 600) self.centralwidget = QtWidgets.QWidget(self) self.setCentralWidget(self.centralwidget) # 初始化工具栏按钮 self._setup_toolbar() # 创建标签栏 self.tab_widget = QtWidgets.QTabWidget(self.centralwidget) self.tab_widget.setGeometry(QtCore.QRect(0, 60, 800, 540)) # 添加第一个标签页 self.add_new_tab(QtCore.QUrl("about:blank"), "New Tab") def _setup_toolbar(self): # 后退按钮 self.tb_back = QtWidgets.QToolButton(self.centralwidget) self.tb_back.setGeometry(QtCore.QRect(10, 20, 41, 31)) icon = QtGui.QIcon() icon.addPixmap(QtGui.QPixmap("icons/back.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_back.setIcon(icon) self.tb_back.setIconSize(QtCore.QSize(32, 32)) self.tb_back.clicked.connect(self.back) # 刷新按钮 self.tb_reload = QtWidgets.QToolButton(self.centralwidget) self.tb_reload.setGeometry(QtCore.QRect(60, 20, 41, 31)) icon1 = QtGui.QIcon() icon1.addPixmap(QtGui.QPixmap("icons/reload.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_reload.setIcon(icon1) self.tb_reload.setIconSize(QtCore.QSize(32, 32)) self.tb_reload.clicked.connect(self.reload) # 前进按钮 self.tb_forward = QtWidgets.QToolButton(self.centralwidget) self.tb_forward.setGeometry(QtCore.QRect(110, 20, 41, 31)) icon2 = QtGui.QIcon() icon2.addPixmap(QtGui.QPixmap("icons/forword.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_forward.setIcon(icon2) self.tb_forward.setIconSize(QtCore.QSize(32, 32)) self.tb_forward.clicked.connect(self.forward) # 主页按钮 self.tb_home = QtWidgets.QToolButton(self.centralwidget) self.tb_home.setGeometry(QtCore.QRect(160, 20, 41, 31)) icon3 = QtGui.QIcon() icon3.addPixmap(QtGui.QPixmap("icons/home.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_home.setIcon(icon3) self.tb_home.setIconSize(QtCore.QSize(32, 32)) self.tb_home.clicked.connect(self.home) # 新标签页按钮 self.tb_newtab = QtWidgets.QToolButton(self.centralwidget) self.tb_newtab.setGeometry(QtCore.QRect(210, 20, 41, 31)) icon_newtab = QtGui.QIcon() icon_newtab.addPixmap(QtGui.QPixmap("icons/newtab.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_newtab.setIcon(icon_newtab) self.tb_newtab.setIconSize(QtCore.QSize(32, 32)) self.tb_newtab.clicked.connect(self.add_new_tab) # 地址栏 self.ln_addressbar = QtWidgets.QLineEdit(self.centralwidget) self.ln_addressbar.setGeometry(QtCore.QRect(260, 20, 441, 31)) self.ln_addressbar.setPlaceholderText("Enter URL..") self.ln_addressbar.returnPressed.connect(self.search) # 搜索按钮 self.tb_search = QtWidgets.QToolButton(self.centralwidget) self.tb_search.setGeometry(QtCore.QRect(710, 20, 41, 31)) icon4 = QtGui.QIcon() icon4.addPixmap(QtGui.QPixmap("icons/search.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off) self.tb_search.setIcon(icon4) self.tb_search.setIconSize(QtCore.QSize(32, 32)) self.tb_search.clicked.connect(self.search) def add_new_tab(self, url=None, title="New Tab"): if url is None: url = QtCore.QUrl("about:blank") web_view = CustomWebEngineView() web_view.load(url) # 开启JavaScript权限 settings = web_view.settings() settings.setAttribute(QWebEngineSettings.JavascriptEnabled, True) settings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows, True) # 监听页面标题变化,更新标签文字 web_view.titleChanged.connect(lambda title, idx=self.tab_widget.count(): self.tab_widget.setTabText(idx, title)) # 处理window.open请求,在当前窗口添加新标签 web_view.page().createWindow = lambda windowType: self.handle_create_window(windowType) tab_idx = self.tab_widget.addTab(web_view, title) self.tab_widget.setCurrentIndex(tab_idx) def handle_create_window(self, windowType): if windowType == QWebEnginePage.WebBrowserTab: self.add_new_tab() return self.tab_widget.currentWidget() return super().createWindow(windowType) def back(self): current_view = self.tab_widget.currentWidget() if current_view: current_view.back() def forward(self): current_view = self.tab_widget.currentWidget() if current_view: current_view.forward() def reload(self): current_view = self.tab_widget.currentWidget() if current_view: current_view.reload() def home(self): current_view = self.tab_widget.currentWidget() if current_view: current_view.load(QtCore.QUrl("http://pyxisad.com")) def search(self): url = self.ln_addressbar.text() if not url.startswith(('http://', 'https://')): url = 'http://' + url current_view = self.tab_widget.currentWidget() if current_view: current_view.load(QtCore.QUrl(url)) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) browser = TabbedBrowser() browser.show() sys.exit(app.exec_())
关键修复点说明:
- 自定义WebEngineView:通过重写(或绑定)
createWindow方法,告诉Qt当网页请求新窗口时应该创建什么类型的视图。 - 正确设置权限:用
settings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows, True)开启JavaScript打开窗口的权限,同时确保JavascriptEnabled是开启的。 - 新标签页/窗口逻辑:方案1是打开独立窗口,方案2是在同一个窗口内添加标签页,你可以根据需求选择。
测试一下,现在window.open()应该能正常工作,手动点击新标签页按钮也能打开新页面了!
内容的提问来源于stack exchange,提问作者Muhammad Azeem
相关产品推荐
相关产品推荐

