I am trying to create my own browser using Python QWebEngineView . I have followed a tutorial that worked on an previous version of PyQt5 (around 2015), but due to its recent updates, some parts of the previous code no longer work.
I have fixed most errors but I am unable to perform html file opening/saving. I always receive a system error when I click on the save button. The following is my code for file saving:
(QMainWindow class)
save_file_action = QAction(QIcon("disk--pencil.png"), "Save Page As...", self)
save_file_action.setStatusTip("Save current page to file")
file_menu.addAction(save_file_action)
(save_file function)
def save_file(self):
filename, _ = QFileDialog.getSaveFilename(self, "Save Page As", "",
"Hypertext Markup Language (*.htm *.html);;"
"All files(*.*)")
if filename:
html = self.browser.page().mainFrame().toHtml()
with open(filename, 'w') as f:
f.write(html)
Thank you.
the toHtml() function of QtWebEngine is asynchronous, so it does not return anything directly, but you have to pass it a callback so that in that function returns the html, to convert that process asynchronous to synchronous we use a QEventLoop with the help of a signal :
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
class Browser(QMainWindow):
htmlFinished = pyqtSignal()
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.mHtml = ""
self.view = QWebEngineView()
self.setCentralWidget(self.view)
self.view.setUrl(QUrl("http://www.google.com/"))
file_menu = QMenu(self.menuBar())
file_menu.setTitle("File")
save_file_action = QAction(QIcon("disk--pencil.png"), "Save Page As...",self)
file_menu.addAction(save_file_action)
self.menuBar().addAction(file_menu.menuAction())
save_file_action.triggered.connect(self.save_file)
def callback(self, html):
self.mHtml = html
self.htmlFinished.emit()
def save_file(self):
filename, _ = QFileDialog.getSaveFileName(self, "Save Page As", "", "Hypertext Markup Language (*.htm *.html);;" "All files(*.*)")
if filename:
self.view.page().toHtml(self.callback)
loop = QEventLoop()
self.htmlFinished.connect(loop.quit)
loop.exec_()
with open(filename, 'w') as f:
f.write(self.mHtml)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Browser()
w.show()
sys.exit(app.exec_())
Related
I'm trying to add a default name to QFileDialog() the images below illustrate.
This is what I get (no filename)
and this is what I want to achieve without having to input it manually, I want to pass the file_name threw a function and have that name show up there.
This is the code im trying to make to work:
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5 import *
import sys
class mainwindowUI(QMainWindow):
def __init__(self):
super(mainwindowUI, self).__init__()
self.exportFiles('test.mp3')
def exportFiles(self,file_name):
filename, _ = QFileDialog.getSaveFileName(self, "Save audio file", "", "Audio Files (*.mp3)")
if filename:
print(filename)
if __name__ == '__main__':
app = QApplication(sys.argv)
window = mainwindowUI()
app.exec_()
I tried to add options:
filename, _ = QFileDialog.getSaveFileName(self, "Save audio file", "", "Audio Files (*.mp3)", options=QFileDialog.setLabelText(file_name))
But this is incorrect and i have no idea how to make it work...
Anyone know how to add a file name to save file dialog?
The third argument indicates the initial name:
def exportFiles(self, file_name):
default_dir ="/home/qt_user/Documents"
default_filename = os.path.join(default_dir, file_name)
filename, _ = QFileDialog.getSaveFileName(
self, "Save audio file", default_filename, "Audio Files (*.mp3)"
)
if filename:
print(filename)
First create a save-as action
self.saveas=QAction(QtGui.QIcon('saveas.png'),'save-as')
Add the save-as action to toolbar
toolbar=self.addToolbar('toolbar');
toolbar.addAction(self.saveas);
Sub this for your QFileDialog code
Fn, _=QFileDialog.getSaveFileName(self,'export pdf',file_name,'Pdf files(.pdf);;All files()');
when connecting the signal to the slot do this
Self.Saveas.toggled.connect(self.exportfiles('name of default file');
I have troubles with saving note(text from QPlainTextEdit). I need only saving in txt format. After typing text and clicking button program displays error 'expected string or bytes-like object not nonetype'.Notepad's program starts from class fileeki till class fileush. I use Python 3.7, PyQt5 and QtDesigner for creating interface.Opening works well, but not saving.Please download all elements of my project. Also there is modules, which you must install.Thanks for trying.
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5 import uic
from PyQt5.QtWidgets import QApplication, QWidget, QMainWindow, QPlainTextEdit
from PyQt5.QtWidgets import QLabel, QPushButton, QMessageBox, QFileDialog
from PyQt5.QtGui import QPixmap
class fileeki(QWidget):
def __init__(self, *args, **kwargs):
super().__init__()
uic.loadUi('uineweki.ui', self)
self.path = None
self.pushButton.clicked.connect(self.opening_run)
self.pushButton_2.clicked.connect(self.saving_run)
self.pushButton_3.clicked.connect(self.saveac)
self.pushButton_5.clicked.connect(self.new_run)
def dialog_critical(self, s):
dlg = QMessageBox(self)
dlg.setText(s)
dlg.setIcon(QMessageBox.Critical)
dlg.show()
def opening_run(self):
path, _ = QFileDialog.getOpenFileName(self, "Open file", "", "Text files (*.txt)")
if path:
try:
with open(path, 'rU') as f:
text = f.read()
except Exception as e:
self.dialog_critical(str(e))
else:
self.path = path
self.plainTextEdit.setPlainText(text)
def saving_run(self):
if self.path is None:
return self.saveac()
self._save_to_path(self.path)
def saveac(self):
path = QFileDialog.getSaveFileName(self, "Save file", "", "Text files (*.txt)")
if not path:
return
self._save_to_path(self.path)
def _save_to_path(self, path):
text = self.plainTextEdit.toPlainText()
try:
with open(path, 'w') as f:
f.write(text)
except Exception as e:
self.dialog_critical(str(e))
else:
self.path = path
def new_run(self):
self.plainTextEdit.clear()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = fileeki()
ex.show()
sys.exit(app.exec())
Link to my project on github: https://github.com/iMAGA07/notepadd
The error is because you are not actually using the returned data from the file dialog:
def saveac(self):
path = QFileDialog.getSaveFileName(self, "Save file", "", "Text files (*.txt)")
if not path:
return
self._save_to_path(self.path) # <-- here!
Also, the getSaveFileName static returns a tuple composed of file path and selected filter strings, and both of them could be empty if the dialog is cancelled, so if not path would always fail.
Check the returned data and call the _save_to_path accordingly:
def saveac(self):
path, filter = QFileDialog.getSaveFileName(self, "Save file", "", "Text files (*.txt)")
if not path:
return
self._save_to_path(path)
I am trying to create my own browser using Python QWebEngineView . I have followed a tutorial that worked on an previous version of PyQt5 (around 2015), but due to its recent updates, some parts of the previous code no longer work.
I have fixed most errors but I am unable to perform html file opening/saving. I always receive a system error when I click on the save button. The following is my code for file saving:
(QMainWindow class)
save_file_action = QAction(QIcon("disk--pencil.png"), "Save Page As...", self)
save_file_action.setStatusTip("Save current page to file")
file_menu.addAction(save_file_action)
(save_file function)
def save_file(self):
filename, _ = QFileDialog.getSaveFilename(self, "Save Page As", "",
"Hypertext Markup Language (*.htm *.html);;"
"All files(*.*)")
if filename:
html = self.browser.page().mainFrame().toHtml()
with open(filename, 'w') as f:
f.write(html)
Thank you.
the toHtml() function of QtWebEngine is asynchronous, so it does not return anything directly, but you have to pass it a callback so that in that function returns the html, to convert that process asynchronous to synchronous we use a QEventLoop with the help of a signal :
import sys
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtWebEngineWidgets import *
class Browser(QMainWindow):
htmlFinished = pyqtSignal()
def __init__(self, *args, **kwargs):
QMainWindow.__init__(self, *args, **kwargs)
self.mHtml = ""
self.view = QWebEngineView()
self.setCentralWidget(self.view)
self.view.setUrl(QUrl("http://www.google.com/"))
file_menu = QMenu(self.menuBar())
file_menu.setTitle("File")
save_file_action = QAction(QIcon("disk--pencil.png"), "Save Page As...",self)
file_menu.addAction(save_file_action)
self.menuBar().addAction(file_menu.menuAction())
save_file_action.triggered.connect(self.save_file)
def callback(self, html):
self.mHtml = html
self.htmlFinished.emit()
def save_file(self):
filename, _ = QFileDialog.getSaveFileName(self, "Save Page As", "", "Hypertext Markup Language (*.htm *.html);;" "All files(*.*)")
if filename:
self.view.page().toHtml(self.callback)
loop = QEventLoop()
self.htmlFinished.connect(loop.quit)
loop.exec_()
with open(filename, 'w') as f:
f.write(self.mHtml)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = Browser()
w.show()
sys.exit(app.exec_())
how to send an opened file inside the main application to a page in QWebEngineView and handle it by javascript FileReader() function , as it was opened by an html5 file input inside the QWebEngineView
here is a part of my code
# -*- coding: utf-8 -*-
import sys, os
from PyQt5.QtWidgets import ( QApplication, QMainWindow)
from PyQt5.QtCore import QUrl
import PyQt5.QtWebEngineWidgets as QtWebEngineWidgets
import interface
class MyWindow(QMainWindow):
def __init__(self, parent=None):
QMainWindow.__init__(self, parent)
self.ui = interface.Ui_MainWindow()
self.ui.setupUi(self)
web_view = QtWebEngineWidgets.QWebEngineView()
self.web_view = web_view
self.ui.verticalLayout_navigateur.addWidget(web_view)
url = self.local_url("src/index.html")
self.web_view.load(url)
f = open('myfile.json', 'r')
#send f to self.web_view and handle it by javascript FileReader() function
def local_url(self, relativePath):
absolutePath = os.path.abspath(relativePath)
url = QUrl.fromLocalFile(absolutePath)
return url
if __name__ == '__main__':
app = QApplication(sys.argv)
window = MyWindow()
window.show()
sys.exit(app.exec_())
thanks
i found an alternative solution, it's quite simple, instead of sending object file to read with javascript, i have just to read it in the main application and inject the content via a QWebChannel
What's the best and simplest way to save a webpage displayed with QWebView() to file?
from PyQt4.QtCore import *
from PyQt4.QtWebKit import *
from PyQt4.QtGui import *
from PyQt4.QtScript import *
import sys
import time
currentfile = "test.htm"
app = QApplication(sys.argv)
web = QWebView()
web.load(QUrl("http://news.google.com"))
web.show()
data = web.page().currentFrame().documentElement().toInnerXml()
open(currentfile,"w").write(data)
sys.exit(app.exec_())
As the page loading is asynchronous, you have to wait for the loadFinished signal before trying to save it.
Then you can retrieve the page content with web.page().currentFrame().toHtml() which returns a python unicode string, which you can write to a file with the codecs module:
from PySide.QtCore import *
from PySide.QtGui import *
from PySide.QtWebKit import *
import sys
import codecs
class Downloader(QObject):
# To be emitted when every items are downloaded
done = Signal()
def __init__(self, urlList, parent = None):
super(Downloader, self).__init__(parent)
self.urlList = urlList
self.counter = 0
# As you probably don't need to display the page
# you can use QWebPage instead of QWebView
self.page = QWebPage(self)
self.page.loadFinished.connect(self.save)
self.startNext()
def currentUrl(self):
return self.urlList[self.counter][0]
def currentFilename(self):
return self.urlList[self.counter][1]
def startNext(self):
print "Downloading %s..."%self.currentUrl()
self.page.mainFrame().load(self.currentUrl())
def save(self, ok):
if ok:
data = self.page.mainFrame().toHtml()
with codecs.open(self.currentFilename(), encoding="utf-8", mode="w") as f:
f.write(data)
print "Saving %s to %s."%(self.currentUrl(), self.currentFilename())
else:
print "Error while downloading %s\nSkipping."%self.currentUrl()
self.counter += 1
if self.counter < len(self.urlList):
self.startNext()
else:
self.done.emit()
urlList = [("http://news.google.com", "google.html"),
("http://www.stackoverflow.com","stack.html"),
("http://www.imdb.com", "imdb.html")]
app = QApplication(sys.argv)
downloader = Downloader(urlList)
# Quit when done
downloader.done.connect(app.quit)
# To view the pages
web = QWebView()
# To prevent user action that would interrupt the current page loading
web.setDisabled(True)
web.setPage(downloader.page)
web.show()
sys.exit(app.exec_())
Is there a reason that the page needs to be loaded with QtWebKit first? Simply using the command-line utility wget, or curl, would do the job.