You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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_())

关键修复点说明:

  1. 自定义WebEngineView:通过重写(或绑定)createWindow方法,告诉Qt当网页请求新窗口时应该创建什么类型的视图。
  2. 正确设置权限:用settings.setAttribute(QWebEngineSettings.JavascriptCanOpenWindows, True)开启JavaScript打开窗口的权限,同时确保JavascriptEnabled是开启的。
  3. 新标签页/窗口逻辑:方案1是打开独立窗口,方案2是在同一个窗口内添加标签页,你可以根据需求选择。

测试一下,现在window.open()应该能正常工作,手动点击新标签页按钮也能打开新页面了!

内容的提问来源于stack exchange,提问作者Muhammad Azeem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:01:18