render latex / mathml with PySide - python

I have a small program that renders a typed equation on the fly using SymPy's 'pretty-printing' facility. This works fine but doesn't look very professional. As SymPy will produce latex or mml I was wondering whether these could be rendered graphically with a PySide widget? I would obviously need to change the 'QTextBrowser()', but to what I'm not sure. I know Nokia provides QtMmlWidget but I'm not sure if this could be used by PySide.
Many thanks and best wishes.
from __future__ import division
import sys
import sympy
from PySide.QtGui import *
from PySide.QtCore import *
from PySide.QtXml import *
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.browser = QTextBrowser()
self.browser.setCurrentFont(QFont("Courier New",10,QFont.Bold))
self.lineedit = QLineEdit("please type an expression")
self.lineedit.selectAll()
layout = QVBoxLayout()
layout.addWidget(self.browser)
layout.addWidget(self.lineedit)
self.setLayout(layout)
self.lineedit.setFocus()
self.connect(self.lineedit, SIGNAL("textChanged (const QString&)"),self.updateUi)
def updateUi(self):
text = unicode(self.lineedit.text())
for z in range(0,9):
text = text.replace('x'+str(z),'x^'+str(z))
text = text.replace(')'+str(z),')^'+str(z))
text = text.replace(str(z)+'x',str(z)+'*x')
text = text.replace(str(z)+'(',str(z)+'*(')
try:
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
self.browser.clear()
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
except Exception:
if text=='': self.browser.clear()
app = QApplication(sys.argv)
form = Form()
form.show()
app.exec_()

One hacky way would be to display it in a QWebiew using something like MathJax
Or, inspired by this question you could use the SVGMath module to convert form MathML to SVG, which can then be displayed in a QSvgWidget

Related

Best way to handle multiple windows Qt4 python

I have got two main-windows which will run all the time and open other windows. Every window has to communicate with each other. All windows are created with qt designer and as I read in another question I should not modify these files, so I tried to make a new class (communicator) to handle all the jobs.
What is the best way to structure a project like this. So how can i communicate best between these windows now, e.g. if I press a button in 'self.mainWindows_images' I want to do something in 'self.mainWindows_classifier'
from classifier import Form as Form_classifier
from cnn_avg import Form as Form_cnn_avg
from images import Form as Form_images
from PyQt4.QtGui import *
from PyQt4.QtCore import *
import sys
class Communicator():
def __init__(self, parent=None):
self.mainWindow_images = Form_images()
self.mainWindow_images.show()
self.mainWindow_classifier = Form_classifier()
self.mainWindow_classifier.show()
def main():
app = QApplication(sys.argv)
app.setStyle('cleanlooks')
comm = Communicator()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
One of the window files, generated by Qt Designer, looks like with the additional -w flag:
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("Form"))
Form.resize(1145, 654)
...
class Form(QtGui.QWidget, Ui_Form):
def __init__(self, parent=None, f=QtCore.Qt.WindowFlags()):
QtGui.QWidget.__init__(self, parent, f)
self.setupUi(self)
I want to do something like this and add the setImage-method to the mainWindow_classifier, becaus as I mentioned I should not modify the generated qt python file:
self.mainWindow_classifier.pushButton.clicked.connect(self.setImage)
def setImage(self):
# change QLabel in self.mainWindow_images

QToolbar behaving weird with QAction and &(ampersand)

According to the docs the QAction uses a single & to mark a shortcut mnemonic but when I used it on the QToolbar it does not work. Then I tried && which worked and the mnemonic appeared with the shortcut working fine and underline appearing properly.
But according to the docs && is used to show single & in the label.
Failing code
from PySide.QtGui import *
from PySide.QtCore import *
import sys
#####Custom edited example
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.actionNotification = QAction(self)
self.actionNotification.setCheckable(True)
self.actionNotification.setChecked(False)
self.actionNotification.setEnabled(True)
self.actionNotification.setAutoRepeat(True)
self.actionNotification.setVisible(True)
self.actionNotification.setIconVisibleInMenu(False)
self.actionNotification.setObjectName("actionNotification")
self.toolBar = QToolBar(self)
self.toolBar.setLayoutDirection(Qt.RightToLeft)
self.toolBar.setStyleSheet("")
self.toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.toolBar.setObjectName("toolBar")
self.toolBar.addAction(self.actionNotification)
self.actionNotification.setText("&Notification") #the problem lies here
self.actionNotification.setToolTip(
QApplication.translate("MainWindow", "Click to see new notifications", None,
QApplication.UnicodeUTF8))
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Main()
form.show()
app.exec_()
Working code
from PySide.QtGui import *
from PySide.QtCore import *
import sys
#####Custom edited example
class Main(QMainWindow):
def __init__(self, parent=None):
super(Main, self).__init__(parent)
self.actionNotification = QAction(self)
self.actionNotification.setCheckable(True)
self.actionNotification.setChecked(False)
self.actionNotification.setEnabled(True)
self.actionNotification.setAutoRepeat(True)
self.actionNotification.setVisible(True)
self.actionNotification.setIconVisibleInMenu(False)
self.actionNotification.setObjectName("actionNotification")
self.toolBar = QToolBar(self)
self.toolBar.setLayoutDirection(Qt.RightToLeft)
self.toolBar.setStyleSheet("")
self.toolBar.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
self.toolBar.setObjectName("toolBar")
self.toolBar.addAction(self.actionNotification)
self.actionNotification.setText("&&Notification") #this works
self.actionNotification.setToolTip(
QApplication.translate("MainWindow", "Click to see new notifications", None,
QApplication.UnicodeUTF8))
if __name__ == '__main__':
app = QApplication(sys.argv)
form = Main()
form.show()
app.exec_()
A quick question on IRC(people there were really helpful) confirmed me that it was a qt issue as this was the same issue in pyqt4 and that QAction works fine with QMenu and the problem exists only for QToolBar
I thought about asking this question here to have an extended discussion and if possible to learn why it behaves so.
tl;dr:what should be done about this weird behaviour of QToolBar? I would like to know why it behaves so.
Any help or suggestion would be really great
system: Debian,python2.7, PySide-1.1
To work around this bug, you can call QAction.setIconText("&Foo") and the mnemonic will be respected.

QT python connect passing arguments to function

Why this code works:
from PySide.QtCore import *
from PySide.QtGui import *
import sys
from functools import partial
import pyside # my code generated by QT Design
class MainDialog(QMainWindow, pyside.Ui_MainWindow):
def __init__(self, parent=None):
super(MainDialog,self).__init__(parent)
self.setupUi(self)
self.connect(self.Connect_buttom, SIGNAL("clicked()"), partial(self.get_fb_token, "aaaaa","bbbbbb"))
def get_fb_token(self,email,passwd):
print email
print passwd
app = QApplication(sys.argv)
form = MainDialog()
form.show()
app.exec_()
And prints aaaaa and bbbbb
But if I change:
self.connect(self.Connect_buttom, SIGNAL("clicked()"), partial(self.get_fb_token, "aaaaa","bbbbbb"))
to
self.connect(self.Connect_buttom, SIGNAL("clicked()"), partial(self.get_fb_token, self.FB_username.text() ,self.FB_password.text()))
it does not print what I am introducing in the text boxes FB_password and FB_username (it does not crash but it does not print anything like if it is not sending both arguments to the function get_fb_token) ???
** Took the example from: http://www.blog.pythonlibrary.org/2013/04/10/pyside-connecting-multiple-widgets-to-the-same-slot/
Im using QT and pyside
The partial object is created when you define the connection, not when the event is triggered. Which means the FB_username.text() is called when connecting, so it will always print the contents that you have set in the designer.
To achieve what you want you have to use a function that retrieves those values when called.
The simplest solution would be:
from PySide.QtCore import *
from PySide.QtGui import *
import sys
import pyside # my code generated by QT Design
class MainDialog(QMainWindow, pyside.Ui_MainWindow):
def __init__(self, parent=None):
super(MainDialog,self).__init__(parent)
self.setupUi(self)
# use new-style signals & slots!
self.Connect_buttom.clicked.connect(self.get_fb_token)
def get_fb_token(self):
email = self.FB_username.text()
password = self.FB_password.text()
print email
print passwd
app = QApplication(sys.argv)
form = MainDialog()
form.show()
app.exec_()
If, for some reason, you don't want to modify get_fb_token, you can use a lambda like this:
self.Connect_buttom.clicked.connect(lambda: self.get_fb_token(self.FB_username.text(), self.FB_password.text()))

PDF with QWebView: missing refresh/repaint after loading

I use the QWebView (python 3.3 + pyside 1.1.2 + Qt 4.8) as FileViewer. Picture, Text, HTML, ... all fine, but PDF has a display problem. I tested two possible ways.
internal pdf viewer: after use webview.load(file) it loads, but
the screen is blank, after loading another file, all works fine, it
shows the file
pdf.js: after use setContent() with filebase, it
loads the webviewer.html/.js with a white page and the loading circle. The
screen only refresh if I resize the form or use the scrollbars, but
then all is fine
I don't find an event for "plugin/javascript finished loading", so I could force a repaint or so.
Here an example code for case 1:
import sys
from PySide import QtCore, QtGui, QtWebKit ##UnusedWildImport
class DialogTest(QtGui.QDialog):
def __init__(self, parent = None):
super(DialogTest, self).__init__(parent)
self.resize(620, 600)
self.setAttribute(QtCore.Qt.WA_DeleteOnClose)
self.PreviewBox = QtWebKit.QWebView()
self.PreviewBox.settings().setAttribute(QtWebKit.QWebSettings.PluginsEnabled, True)
self.PreviewBox.settings().setAttribute(QtWebKit.QWebSettings.WebAttribute.DeveloperExtrasEnabled, True)
self.PreviewBox.settings().setAttribute(QtWebKit.QWebSettings.PrivateBrowsingEnabled, True)
self.PreviewBox.settings().setAttribute(QtWebKit.QWebSettings.LocalContentCanAccessRemoteUrls, True)
self.PreviewBox.loadFinished.connect(self._loadfinished)
self.button_test1 = QtGui.QPushButton("File 1")
self.button_test1.clicked.connect(self._onselect1)
self.button_test2 = QtGui.QPushButton("File 2")
self.button_test2.clicked.connect(self._onselect2)
layout_Buttons = QtGui.QHBoxLayout()
layout_Buttons.addWidget(self.button_test1)
#layout_Buttons.addStretch()
layout_Buttons.addWidget(self.button_test2)
layout_Main = QtGui.QVBoxLayout()
layout_Main.addLayout(layout_Buttons)
layout_Main.addWidget(self.PreviewBox)
self.setLayout(layout_Main)
def Execute(self):
self.show()
self.exec_()
def _onselect1(self):
self.PreviewBox.load(QtCore.QUrl().fromLocalFile("c:\\tmp\\test1.pdf"))
def _onselect2(self):
self.PreviewBox.load(QtCore.QUrl().fromLocalFile("c:\\tmp\\test2.pdf"))
def _loadfinished(self, ok):
#self.PreviewBox.repaint()
pass
app = QtGui.QApplication(sys.argv)
DialogTest().Execute()
Edit: Workaround
Case 1 (webkit plugin) has an otherbug, it takes the focus to itself, so this solution isn't acceptable to me. I played with the pdf.js again and found a workaroud:
self.PreviewBox.setHtml(content, baseUrl = QtCore.QUrl().fromLocalFile(path))
self.PreviewBox.hide()
QtCore.QTimer.singleShot(700, self.PreviewBox.show)
The hide() must be after the content filling and the timer haven't to be too low.
//jay
I just solved a similar problem cleaning the QWebView before every pdf load.
Be careful with the loadFinished() signal.
In your example:
self.PreviewBox.load(QUrl('about:blank'))
or, in case we don't like 'about:blank' this may be a more portable solution:
self.PreviewBox.setHtml('<html><head></head><title></title><body></body></html>')

How to make a window that occupies the full screen without maximising?

I'm writing in python using Qt
I want to create the application window (with decorations) to occupy the full screen size. Currently this is the code I have:
avGeom = QtGui.QDesktopWidget().availableGeometry()
self.setGeometry(avGeom)
the problem is that it ignores window decorations so the frame is larger... I googled and what not, found this:
http://harmattan-dev.nokia.com/docs/library/html/qt4/application-windows.html#window-geometry
which seems to indicate I need to set the frameGeometry to the avGeom however I haven't found a way to do that. Also, in the comments in the above link it says what I'm after may not be even possible as the programme can't set the frameGeometry before running... If that is the case I just want confirmation that my problem is not solvable.
EDIT:
So I played around with the code a bit and this gives what I want... however the number 24 is basically through trial and error until the window title is visible.... I want some better way to do this... which is window manager independent..
avGeom = QtGui.QDesktopWidget().availableGeometry()
avGeom.setTop(24)
self.setGeometry(avGeom)
Now I can do what I want but purely out of trial and error
Running Ubuntu, using Spyder as an IDE
thanks
Use QtGui.QApplication().desktop().availableGeometry() for the size of the window:
#!/usr/bin/env python
#-*- coding:utf-8 -*-
from PyQt4 import QtGui, QtCore
class MyWindow(QtGui.QWidget):
def __init__(self, parent=None):
super(MyWindow, self).__init__(parent)
self.pushButtonClose = QtGui.QPushButton(self)
self.pushButtonClose.setText("Close")
self.pushButtonClose.clicked.connect(self.on_pushButtonClose_clicked)
self.layoutVertical = QtGui.QVBoxLayout(self)
self.layoutVertical.addWidget(self.pushButtonClose)
titleBarHeight = self.style().pixelMetric(
QtGui.QStyle.PM_TitleBarHeight,
QtGui.QStyleOptionTitleBar(),
self
)
geometry = app.desktop().availableGeometry()
geometry.setHeight(geometry.height() - (titleBarHeight*2))
self.setGeometry(geometry)
#QtCore.pyqtSlot()
def on_pushButtonClose_clicked(self):
QtGui.QApplication.instance().quit()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
app.setApplicationName('MyWindow')
main = MyWindow()
main.show()
sys.exit(app.exec_())
I've always found inheritting from the QMainWindow class to be particularly useful. Like this:
import sys
from PySide.QtGui import *
from PySide.QtCore import *
class Some_APP(QMainWindow):
def __init__(self):
super().__init__()
self.initUI()
def initUI(self):
### this line here is what you'd be looking for
self.setWindowState(Qt.WindowMaximized)
###
self.show()
def main():
app = QApplication(sys.argv)
some_app = Some_APP()
sys.exit(app.exec_())
if __name__ == "__main__":
main()

Categories