Question

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.argv)
form = Form()
form.show()
app.exec_()
Was it helpful?

Solution

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()
  1. Never catch all exceptions with except:. This will also catch BaseExceptions like SystemExit, 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 use except Exception: which will only handle exceptions based on Exception.
  2. if text=='' - I think if not text is more "pythonic".

OTHER TIPS

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 :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top