After many fail attempts I found fbs module tutorial for building python desktop app on github. It provided a sample script and how to integrate the script with fbs module.
How do you merge class from Sample App into My code ?
Sample App code :
from fbs_runtime.application_context import ApplicationContext, \
cached_property
from PyQt5.QtWidgets import QApplication, QMainWindow
class AppContext(ApplicationContext):
def run(self):
self.main_window.show()
return self.app.exec_()
#cached_property
def main_window(self):
result = QMainWindow()
result.setWindowTitle('Hello World!')
result.resize(250, 150)
return result
My code :
from PySide2 import QtCore, QtGui, QtWidgets
from PySide2.QtWidgets import QMessageBox, QAction, QPlainTextEdit, QPushButton
class Ui_Form(QtWidgets.QMainWindow):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(846, 794)
self.central_widget = QtWidgets.QWidget()
Form.setCentralWidget(self.central_widget)
self.gridLayout_2 = QtWidgets.QGridLayout(self.central_widget)
self.gridLayout_2.setObjectName("gridLayout_2")
......
if __name__ == '__main__':
import sys
# ~ app = QtWidgets.QApplication(sys.argv)
# ~ Form = QtWidgets.QWidget()
# ~ ui = Ui_Form()
# ~ ui.setupUi(Form)
# ~ Form.show()
# ~ sys.exit(app.exec_())
app = QtWidgets.QApplication(sys.argv)
win = Ui_Form()
app.exec_()
FBS repo : https://github.com/mherrmann/fbs-tutorial
Merge Classes? can you elaborate more?
If you want to use class from Sample App you can extends it
class AppContext(ApplicationContext):
...
class MyNewClass(AppContext):
# All atributes from AppContext will be in your MyNewClass
*EDIT**
After reading the docs from github about this project, you just need implement class AppContext because in this example he already inherit from external class from lib ApplicationContext
from fbs_runtime.application_context import ApplicationContext, \
cached_property
from PyQt5.QtWidgets import QApplication, QMainWindow
class AppContext(ApplicationContext):
...
def run(self):
# Here you can change or add your own logic
self.main_window.show()
return self.app.exec_()
#cached_property
def main_window(self):
# Here you can change or add your own logic
result = QMainWindow() # Probabily you should manipulate this instance adding whatever you want following lib docs at github
result.setWindowTitle('Hello World!')
result.resize(250, 150)
return result
Related
I am trying to use qt creator and python to generate flowcharts with values. I want to save the generated flowchart as an image after, but I cannot figure out how to do it. Here is my attempt:
import sys
from PyQt5 import QtWidgets, uic
from PyQt5.QtGui import *
from mainwindow import Ui_MainWindow
class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self, *args, obj=None, **kwargs):
super(MainWindow, self).__init__(*args, **kwargs)
self.setupUi(self)
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
screen = app.primaryScreen()
screenshot = screen.grabWindow(window)
screen.save('screenshot.png', 'png')
The fact that the show method is called does not imply that it is shown instantly, but rather that this method notifies the OS so that the window is created. A possible solution is to use a QTimer, on the other hand the grabWindow method grabs a window using the associated WID, in this case it is better to use the grab method:
from functools import partial
def take_screenshot(widget):
pixmap = widget.grab()
if not pixmap.isNull():
pixmap.save("/fullpath/of/screenshot.png", "PNG")
QApplication.quit()
def main():
app = QtWidgets.QApplication(sys.argv)
window = MainWindow()
window.show()
QTimer.singleShot(500, partial(take_screenshot, window))
app.exec_()
if __name__ == "__main__":
main()
I am making a web browser using PyQt5. I am using the following code:
import PyQt5
from PyQt5.QtCore import QUrl
from PyQt5.QtWidgets import QApplication, QWidget
from PyQt5.QtWebKitWidgets import QWebView , QWebPage
from PyQt5.QtWebKit import QWebSettings
from PyQt5.QtNetwork import *
import sys
from optparse import OptionParser
class Browser(QWebView):
def __init__(self):
# QWebView
self.view = QWebView.__init__(self)
#self.view.setPage(MyBrowser())
self.setWindowTitle('Loading...')
self.titleChanged.connect(self.adjustTitle)
#super(Browser).connect(self.ui.webView,QtCore.SIGNAL("titleChanged (const QString&)"), self.adjustTitle)
def load(self,url):
self.setUrl(QUrl(url))
def adjustTitle(self):
self.setWindowTitle(self.title())
app = QApplication(sys.argv)
view = Browser()
view.showMaximized()
view.load("https://duckduckgo.com")
app.exec_()
However, this is what I get:
Can someone please tell me where I am going wrong? Note that it is not a problem of the website. I have tried it with Wikipedia, Stack Overflow and Google. I am using PyQt5 version 5.10.1.
In case you want fullscreen, you have to use:
class Browser(QWebView):
def __init__(self):
# QWebView
self.view = QWebView.__init__(self)
#self.view.setPage(MyBrowser())
self.setWindowTitle('Loading...')
self.titleChanged.connect(self.adjustTitle)
self.showFullScreen()
class Browser(QWebView):
def __init__(self):
super().__init__()
def load(self, url):
self.setUrl(QUrl(url))
def adjustTitle(self):
self.setWindowTitle(self.title())
if __name__ == '__main__':
app = QApplication(sys.argv)
window = Browser()
window.setWindowTitle('Loading...')
window.titleChanged.connect(window.adjustTitle)
window.load("https://duckduckgo.com")
window.showMaximized()
sys.exit(app.exec_())
The program does not know the real sizes of your device so it creates a maximum on its assumed geometry.
You should provide the actual geometry by resize then call showMaximized. So that your geometry will be reachable by the program and a true maximized window will be displayed.
self.resize(998, 878)
self.showMaximized()
I have a multi-windowed PyQt5 (Python 3.6.2 with Qt 5.9.0) application which works perfectly when run in a standard desktop (i.e. window managed) environment. My target platform is an embedded device (Raspberry Pi, i.MX6, etc. for example), where I won't be using the X11 window system. I'm currently testing the embedded device with the eglfs platform, which doesn't support multiple windows. I'm considering either using the QtWayland platform, or modifying my approach to use a QtStackedWidget to contain the 'windows' as individual pages within the stack.
How can I modify the below high-level windowed application to leverage a QStackedWidget arrangement, to facilitate a multi-paged application in a windowless environment?
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
from ui_Main import Ui_Main
from ui_Window1 import Ui_Window1
from ui_Window2 import Ui_Window2
class Main(QMainWindow, Ui_Main):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
#Initialisation functions
self.PushButton1.clicked.connect(self.OpenWindow1)
self.PushButton2.clicked.connect(self.OpenWindow2)
def OpenWindow1(self):
showWindow1.show()
def OpenWindow2(self):
showWindow2.show()
class Window1(QMainWindow, Ui_Window1):
def __init__(self, parent=None):
super(Window1, self).__init__(parent)
self.setupUi(self)
class Window2(QMainWindow, Ui_Window2):
def __init__(self, parent=None):
super(Window2, self).__init__(parent)
self.setupUi(self)
if __name__ == '__main__':
app = QApplication(sys.argv)
showMain = Main()
showWindow1 = Window1()
showWindow2 = Window2()
showMain.show()
app.exec_()
I've used a QStackedLayout to nest each of the 'windows' within a single page, and then consolidated each of the setupUI() functions of the external .py files into a single external file. The below files reflect this approach, using the sample multi-window example posted in my question.
ui_Main.py:
from PyQt5 import QtCore, QtGui, QtWidgets
import sys
class Ui_Main(QtWidgets.QWidget):
def setupUi(self, Main):
Main.setObjectName("Main")
Main.resize(800, 480)
self.QtStack = QtWidgets.QStackedLayout()
self.stack1 = QtWidgets.QWidget()
self.stack2 = QtWidgets.QWidget()
self.stack3 = QtWidgets.QWidget()
self.Window1UI()
self.Window2UI()
self.Window3UI()
self.QtStack.addWidget(self.stack1)
self.QtStack.addWidget(self.stack2)
self.QtStack.addWidget(self.stack3)
def Window1UI(self):
self.stack1.resize(800, 480)
#PushButton1#
self.PushButton1 = QtWidgets.QPushButton(self.stack1)
self.PushButton1.setText("BUTTON 1")
self.PushButton1.setGeometry(QtCore.QRect(10, 10, 100, 100))
#PushButton2#
self.PushButton2 = QtWidgets.QPushButton(self.stack1)
self.PushButton2.setText("BUTTON 2")
self.PushButton2.setGeometry(QtCore.QRect(150, 150, 100, 100))
def Window2UI(self):
self.stack2.resize(800, 480)
self.stack2.setStyleSheet("background: red")
def Window3UI(self):
self.stack3.resize(800, 480)
self.stack3.setStyleSheet("background: blue")
Main.py:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QApplication, QMainWindow
import sys
from ui_Main import Ui_Main
class Main(QMainWindow, Ui_Main):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.setupUi(self)
self.PushButton1.clicked.connect(self.OpenWindow1)
self.PushButton2.clicked.connect(self.OpenWindow2)
def OpenWindow1(self):
self.QtStack.setCurrentIndex(1)
def OpenWindow2(self):
self.QtStack.setCurrentIndex(2)
if __name__ == '__main__':
app = QApplication(sys.argv)
showMain = Main()
sys.exit(app.exec_())
I have created a form using PyQt4 which has a push button. On this push button I want to call another python script which looks like this:
File1.py:
import sys
from PyQt4 import QtCore, QtGui
from file1_ui import Ui_Form
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
File1_ui.py
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(400, 300)
self.pushButton = QtGui.QPushButton(Form)
self.pushButton.setGeometry(QtCore.QRect(120, 200, 95, 20))
self.pushButton.setObjectName(_fromUtf8("pushButton"))
self.retranslateUi(Form)
QtCore.QObject.connect(self.pushButton, QtCore.SIGNAL(_fromUtf8("clicked()")), Form.close)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("Form", "Form", None, QtGui.QApplication.UnicodeUTF8))
self.pushButton.setText(QtGui.QApplication.translate("Form", "Close", None, QtGui.QApplication.UnicodeUTF8))
File2.py
import sys
from PyQt4 import Qt
from taurus.qt.qtgui.application import TaurusApplication
app = TaurusApplication(sys.argv)
panel = Qt.QWidget()
layout = Qt.QHBoxLayout()
panel.setLayout(layout)
from taurus.qt.qtgui.panel import TaurusForm
panel = TaurusForm()
model = [ 'test/i1/1/%s' % p for p in props ]
panel.setModel(model)
panel.show()
sys.exit(app.exec_())
File1_ui.py is created from the Qtdesigner and then I am using File1.py to execute it.So File2.py when executed alone opens up a panel and displays few attributes.I want this script to be called on the button click in the first form(file1.py) which I created using Qtdesigner.Could you let me know how I could achieve this functionality.Thanks.
You will need to make some modifications to File2.py to make the appropriate calls depending on whether it is running standalone or not. When you are launching the script via File1.py there will already be a QApplication instance with event loop running, so trying to create another and run its event loop will cause problems.
Firstly, move the core part of your script into its own function. This will allow you to easily call it from File1.py. You can then handle the case where the script is running standalone and needs to create a QApplication instance and start its event loop. (I am not familiar the the taurus library you are using, but you can probably substitute TaurusApplication for QtGui.QApplication)
File2.py:
import sys
from PyQt4 import QtCore, QtGui
def runscript():
panel = QtGui.QWidget()
layout = QtGui.QHBoxLayout(panel)
return panel # Must return reference or panel will be deleted upon return
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
panel = runscript()
panel.show()
sys.exit(app.exec_())
Assuming your files are in the same directory you can simply write import File2 and use File2.runscript() to run your code. You then just need to connect the function to your pushbuttons clicked() signal to run it. The only problem here is that the reference to the QWidget returned from the runscript() function will be lost (and the object deleted) if you connect directly to runscript(). For this reason I created a method launch_script() which saves a reference in MyForm.
File1.py:
import sys
from PyQt4 import QtCore, QtGui
from file1_ui import Ui_Form
import File2
class MyForm(QtGui.QMainWindow):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
self.ui = Ui_Form()
self.ui.setupUi(self)
# This is a bit of a hack.
self.ui.pushButton.clicked.connect(self.launch_script)
def launch_script(self):
self.panel = File2.runscript()
self.panel.show()
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
myapp = MyForm()
myapp.show()
sys.exit(app.exec_())
I don't use Qt Designer, so I don't know the correct way to go about connecting the signal to launch_script(). The code I have written should work, but obviously violates OOP principles and is dependent on the name of the pushbutton widget assigned by the software.
I have tried adding the pdf.js viewer files in my project and it works in browsers like Chrome, Mozilla, Safari, etc, but it's not loading some pages in node-webkit and PyQt webkit.
I am trying to load the file using an iframe, like this:
<iframe src="/test/?file=/assets/pdf/example.pdf#page=3"> </iframe>
Below are some more up-to-date demo scripts for using pdf.js with PyQt4/QtWebKit or PyQt5/QtWebEngine. To try these, first download the latest stable version of pdf.js and unpack the zip file into a suitable location. (NB: if you're on Linux your distro may already have a pdf.js package, so that could be installed instead).
UPDATE:
As of Qt-5.13.0, it is also possible to use the built-in Chromium PDF Viewer with QWebEngineView:
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
PDF = 'file://path/to/my/sample.pdf'
class Window(QtWebEngineWidgets.QWebEngineView):
def __init__(self):
super().__init__()
self.settings().setAttribute(
QtWebEngineWidgets.QWebEngineSettings.PluginsEnabled, True)
self.settings().setAttribute(
QtWebEngineWidgets.QWebEngineSettings.PdfViewerEnabled, True)
self.load(QtCore.QUrl.fromUserInput(PDF))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 50, 800, 600)
window.show()
sys.exit(app.exec_())
PyQt5/QtWebEngine pdfjs script:
UPDATE:
NB: as of Aug 2022, it may be necessary to use the legacy build of pdfjs (i.e. the build for "older browsers" on the download page) to keep things working with PyQt5. The stable build should work okay with PyQt6, though.
import sys
from PyQt5 import QtCore, QtWidgets, QtWebEngineWidgets
PDFJS = 'file:///path/to/pdfjs-1.9.426-dist/web/viewer.html'
# PDFJS = 'file:///usr/share/pdf.js/web/viewer.html'
PDF = 'file:///path/to/my/sample.pdf'
class Window(QtWebEngineWidgets.QWebEngineView):
def __init__(self):
super().__init__()
self.load(QtCore.QUrl.fromUserInput('%s?file=%s' % (PDFJS, PDF)))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 50, 800, 600)
window.show()
sys.exit(app.exec_())
PyQt4/QtWebKit pdfjs script:
import sys
from PyQt4 import QtCore, QtGui, QtWebKit
PDFJS = 'file:///path/to/pdfjs-1.9.426-dist/web/viewer.html'
# PDFJS = 'file:///usr/share/pdf.js/web/viewer.html'
PDF = 'file:///path/to/my/sample.pdf'
class Window(QtWebKit.QWebView):
def __init__(self):
super().__init__()
self.load(QtCore.QUrl.fromUserInput('%s?file=%s' % (PDFJS, PDF)))
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.setGeometry(600, 50, 800, 600)
window.show()
sys.exit(app.exec_())
I've found this thread over at the Qt Forums, where thebeast44 posted a snippet of Qt code answering your question. My translation to python is below.
You'll also need to unpack the res folder from the author's original code, I think he just modified the viewer... I've also attached said code here.
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import QtNetwork
from PyQt4 import QtWebKit
class PDFViewer(QtWebKit.QWebView):
pdf_viewer_page = 'res/pdf-viewer.html'
def __init__(self, parent=None):
super().__init__(parent)
self.settings = QtWebKit.QWebSettings.globalSettings()
self.settings.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessFileUrls, True )
self.settings.setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessRemoteUrls, True )
self.settings.setAttribute(QtWebKit.QWebSettings.DeveloperExtrasEnabled, True )
nam = QtNetwork.QNetworkAccessManager()
page = QtWebKit.QWebPage(self)
page.setNetworkAccessManager(nam)
self.setPage(page)
self.loadFinished.connect(self.onLoadFinish)
self.setUrl(QtCore.QUrl(self.pdf_viewer_page))
def onLoadFinish(self, success):
if success:
self.page().mainFrame().evaluateJavaScript("init();")
if __name__ == '__main__':
import sys
app = QtGui.QApplication(sys.argv)
viewer = PDFViewer(parent=None)
viewer.show()
sys.exit(app.exec_())
From PyQt5 v5.13 you can load PDF files with the chromium API. According to the documentation https://doc.qt.io/qt-5/qtwebengine-features.html#pdf-file-viewing this option is by default enabled.
This minimal example is adapted from Simple Browser
import sys
from pathlib import Path
from PyQt5 import QAxContainer
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QWidget, QVBoxLayout, QPushButton, QLineEdit, QApplication
class Main(QWidget):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.main_layout = QVBoxLayout(self)
self.qlineedit = QLineEdit()
self.qlineedit.returnPressed.connect(self.go_action)
self.main_layout.addWidget(self.qlineedit)
self.read_btn = QPushButton('Test')
self.read_btn.clicked.connect(self.go_action)
self.main_layout.addWidget(self.read_btn)
self.WebBrowser = QAxContainer.QAxWidget(self)
self.WebBrowser.setFocusPolicy(Qt.StrongFocus)
self.WebBrowser.setControl("{8856F961-340A-11D0-A96B-00C04FD705A2}")
self.main_layout.addWidget(self.WebBrowser)
def go_action(self):
# convert system path to web path
f = Path(self.qlineedit.text()).as_uri()
# load object
self.WebBrowser.dynamicCall('Navigate(const QString&)', f)
if __name__ == "__main__":
a = QApplication(sys.argv)
w = Main()
w.show()
sys.exit(a.exec_())
This example: