I want to open self written html code in PyQt5 QWebEngineView. The html code should contain links, which are not url pages but have other information. Below a created a simple example. When clicking on the link named Link, python does not return the parameter inside the link. When I change the value of the link to a url, I get the QUrl as a result. Is there a way to get the content of the link (not a url) when clicked?
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
import sys
class MyWebEnginePage(QWebEnginePage):
def acceptNavigationRequest(self, url, _type, isMainFrame):
if _type == QWebEnginePage.NavigationTypeLinkClicked:
print(url)
return False
return super().acceptNavigationRequest(url, _type, isMainFrame)
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
browser = QWebEngineView()
browser.setPage(MyWebEnginePage(self))
link = "Hallo Welt"
text = f'<a style="text-decoration:none;" href="{link}">Link</a>'
browser.setHtml(text)
self.setCentralWidget(browser)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = App()
window.setGeometry(800, 100, 1000, 800)
window.show()
sys.exit(app.exec_())
You can use a url with the data: scheme to send the link value. When the url is received, you can then check that it has the correct scheme, and emit a signal with only the url's path (which does not include the scheme).
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
import sys
class MyWebEnginePage(QWebEnginePage):
dataLinkClicked = pyqtSignal(str)
def acceptNavigationRequest(self, url, _type, isMainFrame):
if (_type == QWebEnginePage.NavigationTypeLinkClicked and
url.scheme() == 'data'):
# send only the url path
self.dataLinkClicked.emit(url.path())
return False
return super().acceptNavigationRequest(url, _type, isMainFrame)
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
browser = QWebEngineView()
page = MyWebEnginePage(self)
# connect to the signal
page.dataLinkClicked.connect(self.handleDataLink)
browser.setPage(page)
# use a data-url
link = "data:Hallo Welt"
text = f'<a style="text-decoration:none;" href="{link}">Link</a>'
browser.setHtml(text)
self.setCentralWidget(browser)
def handleDataLink(self, text):
print(text) # prints "Hallo Welt"
if __name__ == '__main__':
app = QApplication(sys.argv)
window = App()
window.setGeometry(800, 100, 1000, 800)
window.show()
sys.exit(app.exec_())
Related
I have a custom QWebEngineView named MyWebWidget, where I set html code, that contains links. When I click one link, a QDialog opens. In the dialog Window there is another MyWebWidget. But in the PopUpWindow no text is shown in MyWebWidget and I have no idea why. When I use QTextEdit instead of MyWebWidget or QWebEngineView the text is shown. Below is a minimal example to reproduce the error.
from PyQt5.QtWidgets import *
import sys
from MyWidgets import MyWebWidget
class App(QMainWindow):
def __init__(self):
super(App, self).__init__()
self.widget = MyWebWidget()
self.widget.setHtml('<a style="text-decoration:none;" href="data:link">link</a>')
self.widget.link.connect(self.function)
self.setCentralWidget(self.widget)
def function(self, link):
dialog = MyPopUpWindow(link, ["abcd"])
dialog.exec_()
class MyPopUpWindow(QDialog):
def __init__(self, title, inputList):
super().__init__()
layout = QVBoxLayout()
labelWiget = QLabel()
labelWiget.setText(title)
webWidget = MyWebWidget()
text = ""
for i in inputList:
text += str(i)
webWidget.setHtml(text)
layout.addWidget(labelWiget)
layout.addWidget(webWidget)
self.setLayout(layout)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = App()
window.show()
sys.exit(app.exec_())
MyWebWidget looks like this:
from PyQt5.QtCore import *
from PyQt5.QtWebEngineWidgets import QWebEngineView
from MyWidgets import MyWebEnginePage
from bs4 import BeautifulSoup
class MyWebWidget(QWebEngineView):
link = pyqtSignal(str)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
page = MyWebEnginePage(self)
self.loaded = False
self.content = ""
# connect to the signal
page.dataLinkClicked.connect(self.handleDataLink)
self.setPage(page)
# use a data-url
self.loadFinished.connect(self.on_load_finished)
def on_load_finished(self):
self.page().runJavaScript("document.documentElement.outerHTML", self.callback)
def callback(self, r):
soup = BeautifulSoup(r, "html.parser")
if not self.loaded:
self.content = soup.text.strip()
self.loaded = True
def handleDataLink(self, text):
self.link.emit(text)
MyWebEnginePage looks like this:
from PyQt5.QtWebEngineWidgets import QWebEnginePage
from PyQt5.QtCore import *
class MyWebEnginePage(QWebEnginePage):
dataLinkClicked = pyqtSignal(str)
def acceptNavigationRequest(self, url, _type, isMainFrame):
if (_type == QWebEnginePage.NavigationTypeLinkClicked and
url.scheme() == 'data'):
# send only the url path
self.dataLinkClicked.emit(url.path())
return False
return super().acceptNavigationRequest(url, _type, isMainFrame)
When I try to set my icon from url which contain favicon.ico it work fine, but when I try to set my icon from url which contain **.jpg or .png ** format it does not work and return none. Kindly help me to solve the problem.
you can check the following code.
# url = "http://www.google.com/favicon.icon
url = 'http://www.geo.tv/assets/front/images/gn-icons/256x256.jpg'
self.nam.finished.connect(self.finishRequest)
self.nam.get(QNetworkRequest(QUrl(url)))
def finishRequest(self,reply):
img = QImage()
img.loadFromData(reply.readAll())
self.setWindowIcon(QIcon(img))
I want to get url of image(png,jpg) mean url of icon of a website. and set to a label, windowIcon etc.
but it works only with image(.ico) format and does not work with other format and return nothing.
Analyzing the url I have seen that redirection from http to https so the reply does not have the bytes of the image but the following url. One possible solution is to have Qt handle redirects using request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True).
import sys
from functools import cached_property
from PySide2.QtCore import Signal, QObject, Qt, QUrl
from PySide2.QtGui import QImage, QPixmap, QIcon
from PySide2.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest
from PySide2.QtWidgets import QApplication, QWidget
class ImageDownloader(QObject):
finished = Signal(QImage)
def __init__(self, parent=None):
super().__init__(parent)
self.manager.finished.connect(self.handle_finished)
#cached_property
def manager(self):
return QNetworkAccessManager()
def start_download(self, url):
request = QNetworkRequest(url)
request.setAttribute(QNetworkRequest.FollowRedirectsAttribute, True)
self.manager.get(request)
def handle_finished(self, reply):
if reply.error() != QNetworkReply.NoError:
print("error: ", reply.errorString())
return
image = QImage()
ok = image.loadFromData(reply.readAll())
if not ok:
print("error")
return
self.finished.emit(image)
class Widget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.downloader = ImageDownloader()
self.downloader.finished.connect(self.handle_finished)
url = QUrl("http://www.geo.tv/assets/front/images/gn-icons/256x256.jpg")
self.downloader.start_download(url)
self.resize(640, 480)
def handle_finished(self, image):
pixmap = QPixmap.fromImage(image)
self.setWindowIcon(QIcon(pixmap))
def main():
app = QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
from PyQt5 import Qt
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import *
from sys import argv
class Window(QMainWindow):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
self.browser = QWebEngineView()
self.browser.setUrl(QUrl('https://www.duckduckgo.com'))
self.browser.urlChanged.connect(self.update_AddressBar)
self.setCentralWidget(self.browser)
self.navigation_bar = QToolBar('Navigation Toolbar')
self.addToolBar(self.navigation_bar)
self.navigation_bar.setAttribute(Qt.Qt.WA_StyledBackground, True)
self.navigation_bar.setStyleSheet('background-color: white;')
self.navigation_bar.setMinimumSize(0, 75)
self.navigation_bar.setMovable(False)
back_button = QAction("←", self)
back_button.setStatusTip('Go to previous page you visited')
back_button.triggered.connect(self.browser.back)
self.navigation_bar.addAction(back_button)
next_button = QAction("→", self)
next_button.setStatusTip('Go to next page')
next_button.triggered.connect(self.browser.forward)
self.navigation_bar.addAction(next_button)
refresh_button = QAction("⟳", self)
refresh_button.setStatusTip('Refresh this page')
refresh_button.triggered.connect(self.browser.reload)
self.navigation_bar.addAction(refresh_button)
home_button = QAction("⌂", self)
home_button.setStatusTip('Go to home page (Google page)')
home_button.triggered.connect(self.go_to_home)
self.navigation_bar.addAction(home_button)
#self.navigation_bar.addSeparator()
self.URLBar = QLineEdit()
self.URLBar.returnPressed.connect(lambda: self.go_to_URL(QUrl(self.URLBar.text()))) # This specifies what to do when enter is pressed in the Entry field
self.navigation_bar.addWidget(self.URLBar)
self.addToolBarBreak()
self.show()
def go_to_home(self):
self.browser.setUrl(QUrl('https://www.duckduckgo.com/'))
def go_to_URL(self, url: QUrl):
if url.scheme() == '':
url.setScheme('http://')
self.browser.setUrl(url)
self.update_AddressBar(url)
def update_AddressBar(self, url):
self.URLBar.setText(url.toString())
self.URLBar.setCursorPosition(0)
app = QApplication(argv)
app.setApplicationName('Libertatem Browser')
window = Window()
app.exec_()
As you can see in my code, I have 4 QActions. I want to make these bigger. How can I do that? I have seen others using back_button.geometry(), but you can't do that with QActions.
I would prefer to keep them as QActions, because it took me a long while to set them up. As a side note, would changing the font size make the button bigger?
If you change the size of the button associated with the QAction it would not make a big difference, you could do it in the following way:
button = toolbar.widgetForAction(action)
button.setFixedSize(100, 100)
But in this case it is better to change the font size since the size of the button (and the height of the QToolBar) depends on it.
import sys
from PyQt5.QtCore import Qt, QUrl, QSize
from PyQt5.QtGui import QFont
from PyQt5.QtWidgets import QAction, QApplication, QLineEdit, QMainWindow, QToolBar
from PyQt5.QtWebEngineWidgets import QWebEngineView
class Window(QMainWindow):
def __init__(self, *args, **kwargs):
super(Window, self).__init__(*args, **kwargs)
self.browser = QWebEngineView()
self.browser.setUrl(QUrl("https://www.duckduckgo.com"))
self.browser.urlChanged.connect(self.update_AddressBar)
self.setCentralWidget(self.browser)
self.navigation_bar = QToolBar("Navigation Toolbar", movable=False)
self.addToolBar(self.navigation_bar)
self.navigation_bar.setAttribute(Qt.WA_StyledBackground, True)
self.navigation_bar.setStyleSheet("background-color: white;")
font = QFont()
font.setPixelSize(40)
back_action = QAction("←", self)
back_action.setStatusTip("Go to previous page you visited")
back_action.triggered.connect(self.browser.back)
back_action.setFont(font)
self.navigation_bar.addAction(back_action)
next_action = QAction("→", self)
next_action.setStatusTip("Go to next page")
next_action.triggered.connect(self.browser.forward)
next_action.setFont(font)
self.navigation_bar.addAction(next_action)
refresh_action = QAction("⟳", self)
refresh_action.setStatusTip("Refresh this page")
refresh_action.triggered.connect(self.browser.reload)
refresh_action.setFont(font)
self.navigation_bar.addAction(refresh_action)
home_action = QAction("⌂", self)
home_action.setStatusTip("Go to home page (Google page)")
home_action.setFont(font)
home_action.triggered.connect(self.go_to_home)
self.navigation_bar.addAction(home_action)
self.URLBar = QLineEdit()
self.URLBar.returnPressed.connect(self.handle_return_pressed)
self.navigation_bar.addWidget(self.URLBar)
def go_to_home(self):
self.browser.setUrl(QUrl("https://www.duckduckgo.com/"))
def go_to_URL(self, url: QUrl):
if url.scheme() == "":
url.setScheme("http://")
self.browser.setUrl(url)
self.update_AddressBar(url)
def update_AddressBar(self, url):
self.URLBar.setText(url.toString())
self.URLBar.setCursorPosition(0)
def handle_return_pressed(self):
url = QUrl.fromUserInput(self.URLBar.text())
self.go_to_URL(url)
def main():
app = QApplication(sys.argv)
app.setApplicationName("Libertatem Browser")
window = Window()
window.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
I'm trying to create a print preview of a QWebEngineView but I can't get it to work.
Here's my code:
...
self.view = QWebEngineView()
...
def handle_preview(self):
dialog = QPrintPreviewDialog()
dialog.paintRequested.connect(self.view.print_)
dialog.exec_()
The code gives me this error:
AttributeError: 'QWebEngineView' object has no attribute 'print_'
The code works perfectly when I use QTextEdit. But that's not what I want. I want to use QWebEngineView.
Based on the official example: WebEngine Widgets PrintMe Example you can implement the preview using the following code.
from PyQt5.QtCore import (QCoreApplication, QEventLoop, QObject, QPointF, Qt,
QUrl, pyqtSlot)
from PyQt5.QtGui import QKeySequence, QPainter
from PyQt5.QtPrintSupport import QPrintDialog, QPrinter, QPrintPreviewDialog
from PyQt5.QtWebEngineWidgets import QWebEnginePage, QWebEngineView
from PyQt5.QtWidgets import QApplication, QDialog, QLabel, QProgressBar, QProgressDialog, QShortcut
class PrintHandler(QObject):
def __init__(self, parent = None):
super().__init__(parent)
self.m_page = None
self.m_inPrintPreview = False
def setPage(self, page):
assert not self.m_page
self.m_page = page
self.m_page.printRequested.connect(self.printPreview)
#pyqtSlot()
def print(self):
printer = QPrinter(QPrinter.HighResolution)
dialog = QPrintDialog(printer, self.m_page.view())
if dialog.exec_() != QDialog.Accepted:
return
self.printDocument(printer)
#pyqtSlot()
def printPreview(self):
if not self.m_page:
return
if self.m_inPrintPreview:
return
self.m_inPrintPreview = True
printer = QPrinter()
preview = QPrintPreviewDialog(printer, self.m_page.view())
preview.paintRequested.connect(self.printDocument)
preview.exec()
self.m_inPrintPreview = False
#pyqtSlot(QPrinter)
def printDocument(self, printer):
loop = QEventLoop()
result = False
def printPreview(success):
nonlocal result
result = success
loop.quit()
progressbar = QProgressDialog(self.m_page.view())
progressbar.findChild(QProgressBar).setTextVisible(False)
progressbar.setLabelText("Wait please...")
progressbar.setRange(0, 0)
progressbar.show()
progressbar.canceled.connect(loop.quit)
self.m_page.print(printer, printPreview)
loop.exec_()
progressbar.close()
if not result:
painter = QPainter()
if painter.begin(printer):
font = painter.font()
font.setPixelSize(20)
painter.setFont(font)
painter.drawText(QPointF(10, 25), "Could not generate print preview.")
painter.end()
def main():
import sys
QCoreApplication.setAttribute(Qt.AA_EnableHighDpiScaling)
app = QApplication(sys.argv)
app.setApplicationName("Previewer")
view = QWebEngineView()
view.setUrl(QUrl("https://stackoverflow.com/questions/59438021"))
view.resize(1024, 750)
view.show()
handler = PrintHandler()
handler.setPage(view.page())
printPreviewShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.Key_P), view)
printShortCut = QShortcut(QKeySequence(Qt.CTRL + Qt.SHIFT + Qt.Key_P), view)
printPreviewShortCut.activated.connect(handler.printPreview)
printShortCut.activated.connect(handler.print)
sys.exit(app.exec_())
if __name__ == "__main__":
main()
Note: For PySide2 you only have to change pyqtSlot to Slot.
I want to set different QWebEngineProfiles to different QWebEngineViews meaning each view will have its own cookie store. I cant find any documentation on it therefore all help would be greatly appreciated.
Any suggestion of another method of setting independent cookie stores to independent webviews will also help. Cheers.
Code is below (connecting the signal did not format properly here but rest assured it is correct in the real code):
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtWebEngineWidgets import *
import sys
class MainWindow(QMainWindow):
def __init__(self, *args, **kwargs):
super(MainWindow, self).__init__(*args,**kwargs)
self.browser={}
self.cookiestore={}
self.page={}
No = input("No: ")
for i in range(int(No)):
self.browser[str(i)] = QWebEngineView()
storagename = str(i)
self.cookiestore[str(i)] = QWebEngineProfile(storagename, self.browser[str(i)])
self.page[str(i)] = QWebEnginePage(self.cookiestore[str(i)], self.browser[str(i)])
self.browser[str(i)].setPage(self.page[str(i)])
self.browser[str(i)].load(QUrl("https://www.google.com"))
self.browser[str(i)].loadFinished.connect(lambda:self._loaded(str(i)))
def _loaded(self, No):
self.browser[No].page().toHtml(self._callable)
def _callable(self, data):
self.html = data
if "" in self.html:
print("Done")
else:
print("wait")
app = QApplication(sys.argv)
window = MainWindow()
app.exec_()
If you want to establish a QWebEngineProfile to a QWebEngineView you must do it through a QWebEnginePage as I show below:
webview = QWebEngineView()
profile = QWebEngineProfile("somestorage", webview)
webpage = QWebEnginePage(profile, webview)
webview.setPage(webpage)
Example:
from PyQt5.QtCore import QUrl
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEngineProfile, QWebEnginePage
from PyQt5.QtWidgets import QApplication
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
views = []
for i in range(5):
webview = QWebEngineView()
profile = QWebEngineProfile(f"storage-{i}", webview)
webpage = QWebEnginePage(profile, webview)
webview.setPage(webpage)
webview.load(QUrl("https://stackoverflow.com/questions/48142341/how-to-set-a-qwebengineprofile-to-a-qwebengineview"))
webview.show()
views.append(webview)
sys.exit(app.exec_())