Search code examples
pythonfloating-pointpyqtqlineedit

Limit number of displayed float digits in pyQT QLineEdit without sacrificing internal accuracy


I'm using QLineEdit widgets in my application to enter and edit numeric (float) values. I would like to display a rounded version of the float value while keeping the full internal accuracy. Only when editing a QLineEdit field, the full number of digits should be displayed.

This is needed for three reasons:

  • complex values need way too much space for my GUI

  • The UI allows to select between log and linear representation and I'd like to hide the resulting numeric inaccuracies.

  • Simply rounding the value contained and displayed in QLineEdit is not an option as I would lose accuracy when editing the displayed value

Does anybody know a neat solution for this problem?

Below you find a MWE, the full code (pyfda) uses dynamic instantiation of widgets and other ugly stuff.

# -*- coding: utf-8 -*-
from __future__ import print_function, division
import numpy as np
import sys
from PyQt4 import QtGui

class InputNumFields(QtGui.QWidget):

    def __init__(self, parent):
        super(InputNumFields, self).__init__(parent)
        self.edit_input_float = 10*np.log10(np.pi) # store in log format
        self._init_UI()

    def _init_UI(self):    
        self.edit_input = QtGui.QLineEdit()
        self.edit_input.editingFinished.connect(self.store_entries)
        self.lay_g_main = QtGui.QGridLayout()
        self.lay_g_main.addWidget(self.edit_input, 0, 0)
        self.setLayout(self.lay_g_main)
        self.get_entries()

    def store_entries(self):
        """ Store text entry as log float"""
        self.edit_input_float = 10*np.log10(float(self.edit_input.text()))
        self.get_entries()

    def get_entries(self):
        """ Retrieve float value, delog and convert to string """
        self.edit_input.setText(str(10**(self.edit_input_float/10)))

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    mainw = InputNumFields(None)
    app.setActiveWindow(mainw) 
    mainw.show()
    sys.exit(app.exec_())

Solution

  • It seems that the behaviour should be this:

    • When the line-edit loses input focus, display the stored value rounded
    • When the line-edit gains input focus, display the stored value in full
    • Whenever editing finishes, store the full current value in log format

    This implies that rounding must not occur when return or enter is pressed (because the line-edit would not lose focus in that case).

    The above behaviour can be achieved with the following changes:

    from PyQt4 import QtCore, QtGui
    
    class InputNumFields(QtGui.QWidget):
        ...
    
        def _init_UI(self):
            self.edit_input = QtGui.QLineEdit()
            self.edit_input.installEventFilter(self)
            ...
    
        def eventFilter(self, source, event):
            if (event.type() == QtCore.QEvent.FocusIn and
                source is self.edit_input):
                self.get_entries()
            return super(InputNumFields, self).eventFilter(source, event)
    
        def get_entries(self):
            value = 10**(self.edit_input_float/10)
            if not self.edit_input.hasFocus():
                value = round(value, 3)
            self.edit_input.setText(str(value))
    

    PS:

    You should probably add a button or something to your example, so you can test the effects of changing focus.