如何从 Python 的 PyQt5 小部件中嵌入的 youtube 视频打开 youtube link?

How to open the youtube link from a youtube video embed in a PyQt5 Widget in Python?

环境:

Python 3.7 PyQT5 5.15.2

我有一个 GUI,在 QWidget 中嵌入了一些 links 和 Youtube 视频。

GUI 是一种用户界面。我已经使用 Python PyQT5 为我的软件完成了我的工作。 我想在我的 GUI 中显示一些来自 YOutube 的视频教程。

所以我将 youtube iframe HTML 代码合并到 Qwidget 中(vlayout 和 webview,请参见下面的代码)。

GUI 加载正常,视频播放良好。但是它们太小了。所以我的用户会在视频上点击 youtube link:

当我在播放视频时单击此 Youtube link 时,它应该会从我的浏览器打开一个 youtube 视频页面。直接从 youtube 观看它而不是从我的 GUI 观看它很有用。 但是 link 不起作用。它没有做任何事情。出了点问题。

所以我尝试使用 'setOpenExternalLinks' & 'centralwid',但它不起作用。我的 youtube 的小部件没有这个属性。

AttributeError: 'QWidget' object has no attribute 'setOpenExternalLinks'

为什么?

以下是一些 youtube 视频和标签的代码:

# Code for 1 Youtube video and its QtWidget
# ======================================================================================
self.centralwid = QtWidgets.QWidget(self.tab_run)
self.centralwid.setGeometry(QtCore.QRect(60, 40, 410, 258))
self.centralwid.setObjectName("centralwid")
self.label_loading_browsers = QtWidgets.QLabel(self.centralwid)
# ===================== HERE IS THE CODE FOR IFRAM YOUTUBE ============================
self.vlayout = QtWidgets.QVBoxLayout()
self.webview = QtWebEngineWidgets.QWebEngineView()
self.webview.settings().setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True)
self.webview.page().fullScreenRequested.connect(lambda request: request.accept())
baseUrl = "local"
htmlString = """
                <iframe width="350" height="212" src="https://www.youtube.com/embed/g8NVwN0_mks?rel=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>
                        """

self.webview.setHtml(htmlString, QUrl(baseUrl))
self.vlayout.addWidget(self.webview)
self.centralwid.setLayout(self.vlayout)

我搜索我的对象 qwidget 的所有属性和方法。 我添加了这两行,但没有任何改变:

self.webview.settings().setAttribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls, True)
self.webview.settings().setAttribute(QWebEngineSettings.AllowRunningInsecureContent, True)

这是 MiniMum Reproductable COde(只需复制粘贴到 py 文件中并执行,您可能需要调整 window 的 gui 大小才能观看视频)

import sys
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow
from PyQt5.QtCore import QUrl, Qt
from PyQt5 import QtWebEngineWidgets
from PyQt5.QtWebEngineWidgets import QWebEngineSettings

# Subclass QMainWindow to customise your application's main window
class MainWindow(QMainWindow):

    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.setWindowTitle("My Awesome App")

        label = QLabel("This is a PyQt5 window!")

        # The `Qt` namespace has a lot of attributes to customise
        # widgets. See: http://doc.qt.io/qt-5/qt.html
        label.setAlignment(Qt.AlignCenter)

        # Set the central widget of the Window. Widget will expand
        # to take up all the space in the window by default.
        self.setCentralWidget(label)

        # Code for 1 Youtube video and its QtWidget
        # ======================================================================================

        self.centralwid = QtWidgets.QWidget(self)
        self.centralwid.setGeometry(QtCore.QRect(60, 40, 410, 258))
        self.centralwid.setObjectName("centralwid")
        self.label_loading_browsers = QtWidgets.QLabel(self.centralwid)
        # ===================== HERE IS THE CODE FOR IFRAM YOUTUBE ============================
        self.vlayout = QtWidgets.QVBoxLayout()
        self.webview = QtWebEngineWidgets.QWebEngineView()
        self.webview.settings().setAttribute(QWebEngineSettings.FullScreenSupportEnabled, True)        
        self.webview.settings().setAttribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls, True)
        self.webview.settings().setAttribute(QWebEngineSettings.AllowRunningInsecureContent, True)
        self.webview.page().fullScreenRequested.connect(lambda request: request.accept())
        baseUrl = "local"
        htmlString = """
                        <iframe width="350" height="212" src="https://www.youtube.com/embed/g8NVwN0_mks?rel=0&amp;showinfo=0" frameborder="0" allowfullscreen></iframe>
                                """

        self.webview.setHtml(htmlString, QUrl(baseUrl))
        self.vlayout.addWidget(self.webview)
        self.centralwid.setLayout(self.vlayout)


app = QApplication(sys.argv)

window = MainWindow()
window.show()

app.exec_()

问题是,根据标准,单击 link 时有几种类型的操作: 在同一页面的另一个选项卡中打开 link,window等。因此,在您的情况下,您还没有实现该逻辑(例如,在 Google Chrome 中,我会将其放在另一个选项卡中)。解决方法是覆盖createWindow方法。

import sys

from PyQt5.QtCore import QUrl, Qt, pyqtSlot
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QVBoxLayout, QWidget
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineSettings, QWebEngineView


popups = []


class Widget(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.view = QWebEngineView()
        lay = QVBoxLayout(self)
        lay.addWidget(self.view)
        self.resize(640, 480)


class WebEnginePage(QWebEnginePage):
    def createWindow(self, _type):
        w = Widget()
        w.show()
        popups.append(w)
        return w.view.page()


class MainWindow(QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent=None)

        self.setWindowTitle("My Awesome App")

        central_widget = QWidget()
        self.setCentralWidget(central_widget)

        label = QLabel("This is a PyQt5 window!", alignment=Qt.AlignCenter)

        self.webview = QWebEngineView()
        self.page = WebEnginePage()
        self.webview.setPage(self.page)
        self.webview.settings().setAttribute(
            QWebEngineSettings.FullScreenSupportEnabled, True
        )

        self.webview.load(
            QUrl("https://www.youtube.com/embed/g8NVwN0_mks?rel=0&amp;showinfo=0")
        )

        lay = QVBoxLayout(central_widget)
        lay.addWidget(label)
        lay.addWidget(self.webview)


def main():
    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec_()


if __name__ == "__main__":
    main()