I'm having a bizarre issue where this simple QWebEngine code runs perfectly fine as a regular user on Windows 10 (loads the page fully), but when I elevate my own default user account it stops loading the page. The progress output will go from 0->100 and not call loadFinished on the browser or show any output on the page. I've tried running it as an elevated standard Administrator built-in account and it seemed to work oddly enough.
Here's the unloaded page:
and here's it working properly:
Running with os.environ["QT_DEBUG_PLUGINS"] = "1" doesn't show any discrepancies between the elevated and non-elevated processes.
import sys
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication, QMainWindow
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.browser = QWebEngineView()
self.browser.setUrl(QUrl('https://www.google.com'))
self.browser.loadProgress.connect(self.on_load_progress)
self.setCentralWidget(self.browser)
self.show()
def on_load_progress(self, progress: int):
print(f'loading progress:[{progress}]...')
app = QApplication(sys.argv)
main_win = MainWindow()
app.exec()
After trying many things and going through many logs, the only partial solution I've found to this problem is adding --no-sandbox to the QApplication argument list to make the Chromium webdriver work at all. For my app this is enough but running without sandboxing is less than ideal for a broader solution.
For those interested I found the answer thanks to this thread (has a lot more relevant info than my descriptions).
Related
I am making a web browser using PyQtWebEngine but how will I give the feature of incognito mode in it.
The answer is in the example that I already pointed out in a previous post: WebEngine Widgets Simple Browser Example. In the Implementing Private Browsing section they point out that it is enough to provide a QWebEngineProfile() different from QWebEngineProfile::defaultProfile() since the latter is shared by all pages by default, which is what is not searched for in a private browsing.
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
class WebView(QtWebEngineWidgets.QWebEngineView):
def __init__(self, off_the_record=False, parent=None):
super().__init__(parent)
profile = (
QtWebEngineWidgets.QWebEngineProfile()
if off_the_record
else QtWebEngineWidgets.QWebEngineProfile.defaultProfile()
)
page = QtWebEngineWidgets.QWebEnginePage(profile)
self.setPage(page)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
view = WebView(off_the_record=True)
view.load(QtCore.QUrl("https://www.qt.io"))
view.show()
sys.exit(app.exec_())
I am building a simple web app called from Python. I am using the below code. What is the easiest way to programatically grant access to the Cam & Mic when this page is loaded? I have only found C++ examples on the web and cannot find a way to do this within Python code.
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
app = QApplication([])
view = QWebEngineView()
view.load(QUrl("https://test.webrtc.org/"))
view.show()
app.exec_()
To give permission you must use the setFeaturePermission method of QWebEnginePage, but you must do it when the view asks you to do so when it emits the featurePermissionRequested signal, this will indicate the url and the feature.
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtCore import QUrl
class WebEnginePage(QWebEnginePage):
def __init__(self, *args, **kwargs):
QWebEnginePage.__init__(self, *args, **kwargs)
self.featurePermissionRequested.connect(self.onFeaturePermissionRequested)
def onFeaturePermissionRequested(self, url, feature):
if feature in (QWebEnginePage.MediaAudioCapture,
QWebEnginePage.MediaVideoCapture,
QWebEnginePage.MediaAudioVideoCapture):
self.setFeaturePermission(url, feature, QWebEnginePage.PermissionGrantedByUser)
else:
self.setFeaturePermission(url, feature, QWebEnginePage.PermissionDeniedByUser)
app = QApplication([])
view = QWebEngineView()
page = WebEnginePage()
view.setPage(page)
view.load(QUrl("https://test.webrtc.org/"))
view.show()
app.exec_()
So I found out that PyQt on the Raspberry Pi does not include support for the WebEngine capabilities. Therefore the WebEngineView class in PyQt cannot be used on the Pi. (I dont really understand why it works fine on Ubuntu but not on Raspbian, but anyway...).
I started down the path of using Qt itself, but then learned you can use the following approach
os.system('chromium-browser --use-fake-ui-for-media-stream %s' % URL)
to start Chrome with access to the microphone and camera pre-granted.
I have the following code snippet working in PySide and need to translate it to work in PySide2.
The purpose is to force all links to open in the system browser when clicked (rather than the widget trying to load them):
from PySide.QtWebKit import QWebView, QWebPage
class HtmlView(QWebView):
def __init__(self, parent=None):
super(HtmlView, self).__init__(parent)
self.page().setLinkDelegationPolicy(QWebPage.DelegateAllLinks) # not working in PySide2
self.linkClicked.connect(self.openWebsite) # not working in PySide2
This was my attempt of a translation:
from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
class HtmlView(QWebEngineView):
def __init__(self, parent=None):
super(HtmlView, self).__init__(parent)
self.page().setLinkDelegationPolicy(QWebEnginePage.DelegateAllLinks) # not working in PySide2
self.linkClicked.connect(self.openWebsite) # not working in PySide2
However, QWebEngineView.linkClicked does not exist and neither does QWebEngineView.setLinkDelegationPolicy or
QWebEnginePage.DelegateAllLinks.
What is the best way to achieve this in PySide2 without the above?
Edit: I checked the QEvents that are triggered but no event seems to be fired off when a link is clicked, so without the linkClicked event from PySide/Qt4.8 I have no idea how to hook into this.
Thanks,
frank
You have to use acceptNavigationRequest:
This function is called upon receiving a request to navigate to the
specified url by means of the specified navigation type type.
isMainFrame indicates whether the request corresponds to the main
frame or a child frame. If the function returns true, the navigation
request is accepted and url is loaded. The default implementation
accepts all navigation requests.
In your case you must reject and open the url when the type is QWebEnginePage::NavigationTypeLinkClicked.
from PySide2.QtCore import QUrl
from PySide2.QtGui import QDesktopServices
from PySide2.QtWidgets import QApplication
from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
class WebEnginePage(QWebEnginePage):
def acceptNavigationRequest(self, url, _type, isMainFrame):
if _type == QWebEnginePage.NavigationTypeLinkClicked:
QDesktopServices.openUrl(url);
return False
return True
class HtmlView(QWebEngineView):
def __init__(self, *args, **kwargs):
QWebEngineView.__init__(self, *args, **kwargs)
self.setPage(WebEnginePage(self))
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
w = HtmlView()
w.load(QUrl("https://stackoverflow.com/questions/47736408/pyside2-qwebview-how-to-open-links-in-system-browser"));
w.show()
sys.exit(app.exec_())
I'm trying to create an application that contains a web browser within it, but when I add the web browser my menu bar visually disappears but functionally remains in place. The following are two images, one showing the "self.centralWidget(self.web_widget)" commented out, and the other allows that line to run. If you run the example code, you will also see that while visually the entire web page appears as if the menu bar wasn't present, you have to click slightly below each entry field and button in order to activate it, behaving as if the menu bar was in fact present.
Web Widget Commented Out
Web Widget Active
Example Code
import os
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import *
class WebPage(QWebEngineView):
def __init__(self, parent=None):
QWebEngineView.__init__(self)
self.current_url = ''
self.load(QUrl("https://facebook.com"))
self.loadFinished.connect(self._on_load_finished)
def _on_load_finished(self):
print("Url Loaded")
class MainWindow(QMainWindow):
def __init__(self, parent=None):
# Initialize the Main Window
super(MainWindow, self).__init__(parent)
self.create_menu()
self.add_web_widet()
self.show()
def create_menu(self):
''' Creates the Main Menu '''
self.main_menu = self.menuBar()
self.main_menu_actions = {}
self.file_menu = self.main_menu.addMenu("Example File Menu")
self.file_menu.addAction(QAction("Testing Testing", self))
def add_web_widet(self):
self.web_widget = WebPage(self)
self.setCentralWidget(self.web_widget)
if __name__ == "__main__":
app = QApplication(sys.argv)
main_window = MainWindow()
main_window.showMaximized()
sys.exit(app.exec_()) # only need one app, one running event loop
Development Environment
Windows 10, PyQt5, pyqt5-5.9
EDIT
The problem doesn't seem to be directly related to the menu bar. Even removing the menu bar the issue still occurs. That said, changing from showMaximized() to showFullScreen() does seem to solve the problem.
I no longer believe this is an issue with PyQt5 specifically but rather a problem with the graphics driver. Specifically, if you look at Atlassian's HipChat application it has a similar problem which is documented here:
https://jira.atlassian.com/browse/HCPUB-3177
Some individuals were able to solve the problem by running the application from the command prompt with the addendum "--disable-gpu" but that didn't work for my python application. On the other hand, rolling back the Intel(R) HD Graphics Driver did solve my problem. Version 21.20.16.4627 is the one that seems to be causing problems.
I realize this is a bit of a vague question, but I'm not sure how to make it more specific.
The skeleton for my code is below:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
class FormWidget(QWidget):
def __init__(self, parent):
super(FormWidget, self).__init__(parent)
class MainWindow(QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
form = FormWidget(self)
self.setCentralWidget(form)
[do a bunch of stuff with form]
if __name__ == '__main__':
app = QApplication(sys.argv)
mainWindow = MainWindow()
mainWindow.show()
sys.exit(app.exec_())
Within the FormWidget class, there is a keyPressEvent() method that traps keyboard input, and on a specific key ('q'), calls this:
mainWindow.close()
Most of the time, that causes the app to exit, as desired. But occasionally (with no predictable pattern that I can discern), it causes a crash (dialog comes up that says 'python.exe has stopped working', with a 'Close program' button).
First question, I guess, is: Is this not the proper way to terminate a PyQt GUI app?
If it is, then second question is: Presumably, my code is misbehaving somewhere. But I'm not sure what sort of misbehavior to be looking for. What sort of mistake could I be making that would cause this?
Any thoughts appreciated.
/John