Search code examples
pythonqt4pyside

No effect from ZoomIn in QTextEdit after font size change


This code runs a little window with a toolbar and a QTextEdit area.

If you highlight 'bananas' and change the font size, then using zoom from either the toolbar buttons or CTRL + mouse wheel will only resize 'apples'. Anyone know why?

from PySide import QtGui, QtCore

class MainWindow(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainWindow, self).__init__(parent)
        self.textEdit = Editor(self)
        self.toolBar  = QtGui.QToolBar(self)
        self.addToolBar(self.toolBar)
        self.setCentralWidget(self.textEdit)
        self.textEdit.setHtml('<font color=blue>apples bananas</font>')

        # Zoom
        self.actionZoomIn  = QtGui.QAction('Zoom In',  self)
        self.actionZoomOut = QtGui.QAction('Zoom Out', self)
        self.toolBar.addAction(self.actionZoomIn)
        self.toolBar.addAction(self.actionZoomOut)
        self.actionZoomIn.triggered.connect(self.onZoomInClicked)
        self.actionZoomOut.triggered.connect(self.onZoomOutClicked)

        # Font Size
        self.comboSize = QtGui.QComboBox(self.toolBar)
        self.toolBar.addWidget(self.comboSize)
        self.comboSize.addItem('0')
        self.comboSize.addItem('10')
        self.comboSize.addItem('18')
        self.comboSize.addItem('30')
        self.comboSize.addItem('48')
        self.comboSize.setCurrentIndex(1)
        self.comboSize.activated[str].connect(self.textSize)

    def textSize(self, pointSize):
        pointSize = int(pointSize)
        if pointSize > 0:
            fmt = QtGui.QTextCharFormat()
            fmt.setFontPointSize(pointSize)
            self.mergeFormatOnWordOrSelection(fmt)

    def mergeFormatOnWordOrSelection(self, format):
        cursor = self.textEdit.textCursor()
        if not cursor.hasSelection():
            cursor.select(QtGui.QTextCursor.WordUnderCursor)

        cursor.mergeCharFormat(format)
        self.textEdit.mergeCurrentCharFormat(format)

    def onZoomInClicked(self):
        self.textEdit.zoom(+1)

    def onZoomOutClicked(self):
        self.textEdit.zoom(-1)

class Editor(QtGui.QTextEdit):
    def __init__(self, parent=None):
        super(Editor, self).__init__(parent)
        self.zoomValue = 0

    def zoom(self, delta):
        zoomIncrement = 3

        if delta < 0:
            zoomIncrement = 0 - zoomIncrement

        self.zoomIn(zoomIncrement)
        self.zoomValue = self.zoomValue + zoomIncrement

        print "self.zoomValue", self.zoomValue

    def wheelEvent(self, event):
        if (event.modifiers() & QtCore.Qt.ControlModifier):
            self.zoom(event.delta())

if __name__ == '__main__':
    app = QtGui.QApplication([])
    window = MainWindow()
    window.resize(400, 180)
    window.show()
    app.exec_()

Solution

  • The default implementation of QTextEdit.zoomIn/Out simply changes the pointSize of the base font for the text-edit.

    The method used in the example to change font size wraps the selected word in a span tag and uses inline css to set the font-size property to a fixed value. This means that when the text-edit is subsequently zoomed, only the unchanged text will be affected.

    It would be possible overcome this problem by using relative font sizes. However, it looks like only a limted subset of css properties is supported, so its only possible to set imprecise values like small, large, etc.

    This can be implemented in the example by making the following changes:

        # Font Size
        self.comboSize = QtGui.QComboBox(self.toolBar)
        self.toolBar.addWidget(self.comboSize)
        self.comboSize.addItem('small')
        self.comboSize.addItem('medium')
        self.comboSize.addItem('large')
        self.comboSize.addItem('x-large')
        self.comboSize.addItem('xx-large')
        self.comboSize.setCurrentIndex(1)
        self.comboSize.activated[int].connect(self.textSize)
    
    def textSize(self, size):
        fmt = QtGui.QTextCharFormat()
        fmt.setProperty(QtGui.QTextFormat.FontSizeAdjustment, size - 1)
        self.mergeFormatOnWordOrSelection(fmt)