I am trying to load a google font to my pyqt5 QtWebEngine app.
The app loads a local html file with css stying. I used font face to load the ttf file as below:
#font-face {
font-family: "Work Sans";
src: url("C:\Users\Godwin\TIAT\fonts\WorkSans-Regular.ttf") format('truetype');
}
body {
font-family: "Work Sans";
background-color: #eef0f2;
}
the font seem to be ignored when loading the html file.
Can someone please assist.
Editstrong text
Here is my full html
#font-face {
font-family: Work Sans;
src: url("Work_Sans/WorkSans-Regular.ttf")
}
div {
font-family: Work Sans;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link rel="stylesheet" type="text/css" href="style.css"/>
<title>Document</title>
</head>
<style>
</style>
<body>
<div>
Hello World
</div>
</body>
</html>
These works on chrome, firefox and chrome but if i use qtwebengine like this
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
if __name__ == "__main__":
import sys
sys.argv.append("--disable-web-security")
app = QtWidgets.QApplication(sys.argv)
wnd = QtWidgets.QWidget()
genVLayout = QtWidgets.QVBoxLayout(wnd)
verticalLayout_7 = QtWidgets.QVBoxLayout()
webEngineViewGen = QtWebEngineWidgets.QWebEngineView(wnd)
webEngineViewGen.setUrl(QtCore.QUrl("about:blank"))
fh = open('main.html','r')
html = fh.read()
webEngineViewGen.setHtml(html)
verticalLayout_7.addWidget(webEngineViewGen)
genVLayout.addLayout(verticalLayout_7)
wnd.show()
sys.exit(app.exec_())
it font does not work
If you are using setHtml() then as indicated by the docs the external resources will be relative to the url that you pass as second parameters:
void QWebEngineView::setHtml(const QString &html, const QUrl &baseUrl = QUrl())
[...]
External objects, such as stylesheets or images referenced in the HTML document, are located relative to baseUrl.
[...]
So in your case the solution is:
import os
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
if __name__ == "__main__":
import sys
sys.argv.append("--disable-web-security")
app = QtWidgets.QApplication(sys.argv)
wnd = QtWidgets.QWidget()
genVLayout = QtWidgets.QVBoxLayout(wnd)
verticalLayout_7 = QtWidgets.QVBoxLayout()
webEngineViewGen = QtWebEngineWidgets.QWebEngineView(wnd)
webEngineViewGen.setUrl(QtCore.QUrl("about:blank"))
with open('main.html','r') as fh:
html = fh.read()
current_dir = os.path.dirname(os.path.abspath(__file__))
url = QtCore.QUrl.fromLocalFile(os.path.join(current_dir, "main.html"))
webEngineViewGen.setHtml(html, url)
verticalLayout_7.addWidget(webEngineViewGen)
genVLayout.addLayout(verticalLayout_7)
wnd.show()
sys.exit(app.exec_())
Or simply use the load() method:
import os
from PyQt5 import QtCore, QtGui, QtWidgets, QtWebEngineWidgets
if __name__ == "__main__":
import sys
sys.argv.append("--disable-web-security")
app = QtWidgets.QApplication(sys.argv)
wnd = QtWidgets.QWidget()
genVLayout = QtWidgets.QVBoxLayout(wnd)
verticalLayout_7 = QtWidgets.QVBoxLayout()
webEngineViewGen = QtWebEngineWidgets.QWebEngineView(wnd)
webEngineViewGen.setUrl(QtCore.QUrl("about:blank"))
current_dir = os.path.dirname(os.path.abspath(__file__))
url = QtCore.QUrl.fromLocalFile(os.path.join(current_dir, "main.html"))
webEngineViewGen.load(url)
verticalLayout_7.addWidget(webEngineViewGen)
genVLayout.addLayout(verticalLayout_7)
wnd.show()
sys.exit(app.exec_())
Related
Following this post and the mathjax 3 documentation, I am trying to render a simple html with Mathjax content in PyQt5 using a local copy of the mathjax repo.
The main directory contains the notebook from which the following code is executed, a "mathjax" folder containing the content of the repo (especially the es5 folder). Notice that I tried with 2 paths to the js (comment toward the top) :
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtCore import QUrl
import os
# <script type="text/javascript" src="file:///Users/mocquin/.../mathjax/es5/tex-chtml-full.js">
pageSource = """
<html><head>
<script type="text/javascript" src="./mathjax/es5/tex-chtml-full.js">
</script></head>
<body>
<p><mathjax style="font-size:2.3em">$$u = \int_{-\infty}^{\infty}(awesome)\cdot du$$</mathjax></p>
</body></html>
"""
app = QApplication(sys.argv)
webView = QWebEngineView()
webView.setHtml(pageSource, baseUrl=QUrl(os.path.abspath('')))
webView.show()
sys.exit(app.exec_())
But this only renders the content without the "latex parsing"
What am I missing so that the mathjax is indeed linked to the html ?
The problem with your example is that you aren't using the correct format for the src path and base url. The src path must be a plain relative path, and the base url should be a backslash-terminated absolute path to the directory containing the mathjax directory.
Assuming the mathjax directory is in the same directory as the python script, the following should work correctly (at least, it does for me):
import sys, os
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication
from PyQt5.QtWebEngineWidgets import QWebEngineView
pageSource = """
<html><head>
<script type="text/javascript" async src="mathjax/es5/tex-chtml-full.js"></script>
</head><body>
<p><mathjax style="font-size:2.3em">$$u = \int_{-\infty}^{\infty}(awesome)\cdot du$$</mathjax></p>
</body></html>
"""
baseurl = QUrl.fromLocalFile(os.path.dirname(os.path.abspath(__file__)) + '/')
print(f'BASEURL: {baseurl.toString()!r}') # BASEURL: 'file:///home/tmp/test/'
app = QApplication(sys.argv)
webView = QWebEngineView()
webView.setHtml(pageSource, baseUrl=baseurl)
webView.show()
sys.exit(app.exec_())
This question already has answers here:
Transparent Background in QWebEnginePage
(2 answers)
Closed 1 year ago.
I am trying to display some html in PyQT5 with QWebEngine. The problem is that the background (body) of the html is set to 'transparent', but QT won't display it as transparent.
I have been able to make the window frameless, and have been able to make the white part around the html that QT adds transparent, but no where on the internet can I find a way to have QT correctly render the transparent body background as actually transparent (instead of white).
If anyone can help, I would really appreciate it!
import os
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
from PyQt5.QtWebChannel import QWebChannel
my_html = """<!DOCTYPE html>
<html lang="en">
<head>
<style>
body {
background-color: transparent;
}
#square {
width: 200px;
height: 200px;
background-color: red;
position: absolute;
top: 100px;
left: 100px;
}
</style>
</head>
<body>
<div id="square"></div>
</body>
</html>
"""
class Browser(QtWebEngineWidgets.QWebEngineView):
def __init__(self, html):
super().__init__()
self.url = QtCore.QUrl.fromLocalFile(os.getcwd() + os.path.sep)
self.page().setHtml(html, baseUrl=self.url)
class Window(QtWidgets.QMainWindow):
def __init__(self, html):
super().__init__()
self.html = html
self.init_widgets()
self.init_layout()
self.setFixedSize(400, 400)
# these make the border QT adds transparent, and removes the title bar
# but doesn't affect the body background of the html which is set to transparent
self.setStyleSheet("background: transparent; border: transparent;")
self.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint | QtCore.Qt.FramelessWindowHint)
self.setAttribute(QtCore.Qt.WA_TranslucentBackground)
self.setAutoFillBackground(True) # don't know what this does, as far as I know, nothing
def init_widgets(self):
self.browser = Browser(self.html)
def init_layout(self):
layout = QtWidgets.QVBoxLayout()
layout.addWidget(self.browser)
central_widget = QtWidgets.QWidget()
central_widget.setLayout(layout)
self.setCentralWidget(central_widget)
def start():
app = QtWidgets.QApplication(sys.argv)
window = Window(my_html)
window.show()
app.exec_()
if __name__ == '__main__':
start()
Picture for the result of the code above
I found answer in old question for Qt and C/C++:
Transparent Background in QWebEnginePage
page has default background white and you have to change it
page = self.page()
page.setBackgroundColor(QtCore.Qt.transparent)
page.setHtml(html, baseUrl=self.url)
How can I render a markdown file in my PyQt5 application?
Here I read that I should use a QWebEngineView instead of a QTextEdit because the QTextEdit can't render external images.
In a comment someone references this example. It is however a complete markdown texteditor and additionally written in c++. I tried to translate the needed parts into Python but I don't quite get how what works. I just need a minimal example.
What I have right now is the following:
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
import sys
app = QApplication(sys.argv)
web_widget = QWebEngineView()
webChannel = QWebChannel() # ?
page = QWebEnginePage() # ?
web_widget.setPage(page) # ?
my_url = QUrl("/index.html")
web_widget.load(my_url)
# now somehow replace the placeholder in the loaded html page with file contents?
file_url = QUrl("file.md")
# help
web_widget.show()
app.exec_()
QTextEdit since Qt 5.14 can render markdown but as the OP points out it has a limitation: it cannot render remote images. So an alternative is to use QWebEngineView + js libraries like markdown.js and marked.js as the official example shows. You can also use QNetworkAccessManager to download remote .md files.
import os.path
import sys
from PyQt5.QtCore import pyqtProperty, pyqtSignal, QObject, QTextCodec, QUrl
from PyQt5.QtNetwork import QNetworkAccessManager, QNetworkReply, QNetworkRequest
from PyQt5.QtWebChannel import QWebChannel
from PyQt5.QtWebEngineWidgets import QWebEngineView, QWebEnginePage
from PyQt5.QtWidgets import QApplication
CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))
class Document(QObject):
textChanged = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self.m_text = ""
def get_text(self):
return self.m_text
def set_text(self, text):
if self.m_text == text:
return
self.m_text = text
self.textChanged.emit(self.m_text)
text = pyqtProperty(str, fget=get_text, fset=set_text, notify=textChanged)
class DownloadManager(QObject):
finished = pyqtSignal(str)
def __init__(self, parent=None):
super().__init__(parent)
self._manager = QNetworkAccessManager()
self.manager.finished.connect(self.handle_finished)
#property
def manager(self):
return self._manager
def start_download(self, url):
self.manager.get(QNetworkRequest(url))
def handle_finished(self, reply):
if reply.error() != QNetworkReply.NoError:
print("error: ", reply.errorString())
return
codec = QTextCodec.codecForName("UTF-8")
raw_data = codec.toUnicode(reply.readAll())
self.finished.emit(raw_data)
def main():
app = QApplication(sys.argv)
filename = os.path.join(CURRENT_DIR, "index.html")
document = Document()
download_manager = DownloadManager()
channel = QWebChannel()
channel.registerObject("content", document)
# remote file
markdown_url = QUrl.fromUserInput(
"https://raw.githubusercontent.com/eyllanesc/stackoverflow/master/README.md"
)
# local file
# markdown_url = QUrl.fromUserInput(/path/of/markdown.md)
download_manager.finished.connect(document.set_text)
download_manager.start_download(markdown_url)
view = QWebEngineView()
view.page().setWebChannel(channel)
url = QUrl.fromLocalFile(filename)
view.load(url)
view.resize(640, 480)
view.show()
sys.exit(app.exec_())
if __name__ == "__main__":
main()
index.html
<!doctype html>
<html lang="en">
<meta charset="utf-8">
<head>
<link rel="stylesheet" type="text/css" href="3rdparty/markdown.css">
<script src="3rdparty/marked.js"></script>
<script src="qrc:/qtwebchannel/qwebchannel.js"></script>
</head>
<body>
<div id="placeholder"></div>
<script>
'use strict';
var placeholder = document.getElementById('placeholder');
var updateText = function(text) {
placeholder.innerHTML = marked(text);
}
new QWebChannel(qt.webChannelTransport,
function(channel) {
var content = channel.objects.content;
updateText(content.text);
content.textChanged.connect(updateText);
}
);
</script>
</body>
</html>
├── 3rdparty
│ ├── markdown.css
│ ├── MARKDOWN-LICENSE.txt
│ ├── marked.js
│ ├── MARKED-LICENSE.txt
│ └── qt_attribution.json
├── index.html
└── main.py
Note: the files in the 3rdparty folder are in the official Qt repository.
I am trying to display a video file inside a PySide2 app I'm writing. That app uses a QWebEngineView and loads a local html file that contains a <video> tag, pointing to a local mov or mp4 file. Somehow I can see the player, but it doesn't load the file.
I've put this little html test page together which loads fine in Chrome, but not in my app. Note that in this file I'm using an online mp4 file, but I've tried both, local and online files, mov and mp4.
<!doctype html>
<html lang="en">
<head>
</head>
<body>
<video width="320" height="240" controls>
<source src="https://archive.org/download/VideoTestFiles/1280X72025FpsPhotoJpeg75.mp4" type="video/mp4" >
</video>
</body>
In my PySide2 app, I'm loading the page like follows:
import os, sys
from PySide2 import QtWidgets
from PySide2.QtWebEngineWidgets import QWebEngineView, QWebEngineSettings
from PySide2.QtCore import QUrl
app = QtWidgets.QApplication(sys.argv)
view = QWebEngineView()
path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "test.html")
view.load(QUrl.fromLocalFile(path))
view.show()
sys.exit(app.exec_())
I have also tried the following settings, none of which seem to help:
view.settings().setAttribute(QWebEngineSettings.PluginsEnabled, True)
view.settings().setAttribute(QWebEngineSettings.JavascriptEnabled, True)
view.settings().setAttribute(QWebEngineSettings.AllowRunningInsecureContent, True)
view.settings().setAttribute(QWebEngineSettings.LocalContentCanAccessFileUrls, True)
view.settings().setAttribute(QWebEngineSettings.LocalContentCanAccessRemoteUrls, True)
Any help appreciated!
Edit:
I just realized: while there is no error in Chrome console, there is an error being displayed in the Python console after closing the app:
[9476:13164:1017/182854.157:ERROR:media_internals.cc(102)] Cannot get RenderProcessHost
Python 3.6 PYQT 5.12.1
I am ready to show the style I need by pyqt5 and I knew that the QTextEdit in pyqt5 can display the html code pretty good (I have some experience in web development), so I decided to use html/css to show my style . However , it may have some problem in showing the code in css . What can I do to let it can show the css/javascript ? If it can‘t , can recommend other methods to modify the style?
It can show some style like width = "100" height = "100" when I code it in the html but not css and some can't display like border-radius:50%;. It won't get any effect when I code the style in css . By the way , I've imported CSS code.
The CSS code do nothing in QTextEdit (but it is ok in html)
.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
class WINDOW(QMainWindow):
def __init__(self):
super().__init__()
self.init()
def init(self):
w_width,w_height,w_x,w_y = 700,640,700,200
self.set_size_pos(w_width,w_height,w_x,w_y);
self.set_message_textedit()
self.message_textedit.setHtml(self.get_html())
self.show()
def set_size_pos(self,width,height,x,y):
'''
set window's width , height and position
'''
self.resize(width,height)
self.move(x,y)
def set_message_textedit(self):
self.message_textedit = QTextEdit(self)
self.message_textedit.setFont(QFont("Microsoft YaHei",12))
self.message_textedit.resize(680,420)
self.message_textedit.move(10,50)
self.message_textedit.setReadOnly(True)
def get_html(self):
html = ""
with open("./chat-style/chat.html","r",encoding = "utf-8") as f:
html = f.read()
return html
if __name__ == '__main__':
app = QApplication(sys.argv)
test = WINDOW()
sys.exit(app.exec_())
.html
<!doctype html>
<html lange="zh-CN">
<head>
<meta charset="utf-8">
<link rel="stylesheet" type="text/css" href="./chat.css">
<script src = "chat.js"></script>
</head>
<body>
<img class = "tx" src="E:\study\assiataant\picture\icon.jpg">
<div>Welcome ~ Don!</div>
</body>
</html>
.css
.tx
{
border-radius:50%;
width: 30;
height: 30;
}
QTextEdit only supports CSS 2.1 as indicated by the docs:
All CSS 2.1 selector classes are supported except pseudo-class selectors such as :first-child, :visited and :hover.
But border-radius was introduced in CSS3. So you can not use it unfortunately. I recommend you read the following link so that you know the allowed tags.
Another alternative is to use QWebEngineView that supports these tags:
*.py
#!/usr/bin/python3
# -*- coding: utf-8 -*-
import os
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(MainWindow, self).__init__(parent)
view = QtWebEngineWidgets.QWebEngineView()
file = os.path.join(
os.path.dirname(os.path.realpath(__file__)),
"chat-style/chat.html"
)
view.load(QtCore.QUrl.fromLocalFile(file))
self.setCentralWidget(view)
self.resize(640, 480)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec_())
If you do not have QWebEngineView installed, you must install it with the following command:
python -m pip install PyQtWebEngine