I have modified a short piece of pyqt code to produce real-time rendering of a user's expression. I have used sympy's pretty-printing function for this, however the output does not appear correctly as the QTextBrowser uses a proportional rather than a monospaced font.
As a beginner I would also welcome any other thoughts you had on the code.
Many thanks and best wishes, Geddes
from __future__ import division
import sys
import sympy
from PyQt4.QtCore import *
from PyQt4.QtGui import *
class Form(QDialog):
def __init__(self, parent=None):
super(Form, self).__init__(parent)
self.browser = QTextBrowser()
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:
if text=='': self.browser.clear()
app = QApplication(sys.ar开发者_开发知识库gv)
form = Form()
form.show()
app.exec_()
You should be able to change the font with setFontFamily
.
Concerning your code: I haven't really worked with PyQt yet (only some hacks like the font family in qbzr...), so I can't tell you if everything is okay. But the following is not a good idea:
except:
if text=='': self.browser.clear()
- Never catch all exceptions with
except:
. This will also catchBaseException
s likeSystemExit
, which shouldn't be caught unless you have a reason to do so. Always catch specific exceptions, or if you're at the highest level (before the unhandled exception handler is executed) and want to log errors, rather useexcept Exception:
which will only handle exceptions based onException
. if text==''
- I thinkif not text
is more "pythonic".
QTextBrowser inherits QTextEdit, so you can use the setCurrentFont(QFont)
method to set a monospace font.
self.browser = QTextBrowser()
self.browser.setCurrentFont(QFont("Courier New")) #Or whatever monospace font family you want...
As for general comments on style, there's probably a way do change your text replacement stuff in updateUi()
to regex, but I can't be sure without seeing sample data to figure out what you're trying to do.
Also, you should probably refactor
try:
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
self.browser.clear()
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
except:
if text=='': self.browser.clear()
Into something more like:
self.browser.clear()
try:
self.browser.append(sympy.printing.pretty(sympy.sympify(text)))
except:
if text=='': self.browser.clear()
Except probably catching the actual Exception you're expecting.
EDIT Here's something for the equation normalizing it looks like you're trying to do, it works with lowercase a-z and real numbers:
def updateUi(self):
text = unicode(self.lineedit.text())
text = re.sub(r'(\d+)([\(]|[a-z])',r'\1*\2',text) #for multiplication
text = re.sub(r'([a-z]|[\)])(\d+)',r'\1^\2',text) #for exponentiation
The first pattern looks for 1 or more digits \d+
followed by an open parenthesis, or a single letter a-z [\(]|[a-z]
. It uses parentheses to capture the digit part of the pattern and the variable part of the pattern, and inserts a * between them. \1*\2
.
The second pattern looks for a variable a-z or a close parenthesis [a-z]|[\)]
, followed by one or more digits \d+
. It uses the grouping parentheses to capture the digit and the variable again, and inserts a ^ between them \1^\2
.
It's not quite perfect (doesn't handle xy --> x*y
) but its closer. If you want to make a full computer algebra system you'll probably need to build a dedicated parser :)
精彩评论