Uploaded image for project: 'Qt'
  1. Qt
  2. QTBUG-88223

QLineEdit Refresh Bug

    XMLWordPrintable

Details

    • Bug
    • Resolution: Unresolved
    • P2: Important
    • None
    • 5.15.1
    • None
    • MacOs Catalina 10.15.2 and pyqt5
    • macOS

    Description

      While I was developing my project of a simple calculator, I noticed a bug in the refresh of QLineEdit (the calculator screen). When I press the calculator buttons, QLineEdit does not display my changes. These changes appear only when for example I resize the widget window (see attached video).
      I am developing on MacOS Catalina 10.15.2 with pyqt5 5.15.1.
      The part of the View was created through Qt Designer and converted into .py file through pyuic and the files are: "Ui_FancyCalc.py and Ui_AboutDialog.py". The Model instead is implemented in the file "calculatormodel2.py". I also implemented my own Observable class in the “observable.py” file, which is imported into the model class. The file where I define my FancyCalc and execute the controller part is "FancyCalc.py".
      I am writing this thread because I tried to run the same project on a windows pc and I have not encountered any problems. So I wanted to know if it was a compatibility issue between my OS and the pyqt5 version.

      I do not include in the description the parts of code converted by QT Designer, but I attach below all the files necessary to run the project

      To run the project just run the "FancyCalc.py" file

      FancyCalc.py

      import sys
      from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog, qApp
      from Calculator2.Ui_FancyCalc import Ui_FancyCalc
      from Calculator2.Ui_AboutDialog import Ui_AboutDialog
      from Calculator2.calculatormodel2 import CalculatorModel
      
      
      # Fancy Calculator Class
      class FancyCalc(QMainWindow):
          def __init__(self):
              super().__init__()
      
              # Set up the user interface from QT Designer.
              self.ui = Ui_FancyCalc()
              self.ui.setupUi(self)
      
              # Create about dialog and wire actions.
              self._aboutDialog = AboutDialog()
              self.ui.actionAbout.triggered.connect(self._aboutDialog.exec_)
              self.ui.actionQuit.triggered.connect(QApplication.exit)
      
              self._model = CalculatorModel()
      
              # Connect the number buttons.
              self.ui.button_0.clicked.connect(lambda: self._model.insert_digit('0'))
              self.ui.button_1.clicked.connect(lambda: self._model.insert_digit('1'))
              self.ui.button_2.clicked.connect(lambda: self._model.insert_digit('2'))
              self.ui.button_3.clicked.connect(lambda: self._model.insert_digit('3'))
              self.ui.button_4.clicked.connect(lambda: self._model.insert_digit('4'))
              self.ui.button_5.clicked.connect(lambda: self._model.insert_digit('5'))
              self.ui.button_6.clicked.connect(lambda: self._model.insert_digit('6'))
              self.ui.button_7.clicked.connect(lambda: self._model.insert_digit('7'))
              self.ui.button_8.clicked.connect(lambda: self._model.insert_digit('8'))
              self.ui.button_9.clicked.connect(lambda: self._model.insert_digit('9'))
      
              # Connect updates to input text to the label in the UI.
              self._model.register(lambda txt: self.ui.calcDisplay.setText(txt))
      
              # Connect the clear button and equal button.
              self.ui.button_C.clicked.connect(self._model.clr)
              self.ui.button_eql.clicked.connect(self._model.eql)
      
              # Connect the operations buttons.
              self.ui.button_add.clicked.connect(self._model.add)
              self.ui.button_sub.clicked.connect(self._model.sub)
              self.ui.button_mul.clicked.connect(self._model.mul)
              self.ui.button_div.clicked.connect(self._model.div)
              self.ui.button_sub.clicked.connect(self._model.sub)
      
      
      # About Dialog class
      class AboutDialog(QDialog):
          def __init__(self):
              super().__init__()
      
              # Set up the user interface from QT Designer.
              self.ui = Ui_AboutDialog()
              self.ui.setupUi(self)
      
      
      app = QApplication(sys.argv)
      window = FancyCalc()
      window.show()
      sys.exit(app.exec_())
      
      

      calculatormodel2.py

      from Calculator2.observable import Observable
      
      
      # A first version of the calculator model.
      class CalculatorModel:
          def __init__(self):
              super().__init__()
              self._inserting = False
              self._accumulator = 0
              self._current_op = None
              self.current_input = Observable('0')
      
          # Register slots to listen for model changes.
          def register(self, slot):
              self.current_input.register(slot)
      
          # Digit insertion
          def insert_digit(self, d):
              if not self._inserting:
                  self.current_input.value = d
                  self._inserting = True if d is not '0' else False
              else:
                  self.current_input.value = self.current_input.value + d
      
          # Function that executes the current operation in preparation for next (if any).
          def execute_current(self):
              # If we are already inserting digits.
              if self._inserting:
                  # Is there an operation already pending? If so, apply it to
                  # accumulator and current input, save in accumulator.
                  if self._current_op:
                      self._accumulator = self._current_op(self._accumulator)
                      self.current_input.value = str(self._accumulator)
                  else:
                      # Otherwise save the current input in accumulator.
                      self._accumulator = int(self.current_input.value)
      
              # In any case we a *not* inserting anymore
              self._inserting = False
      
          # Public API for all calculator operations that manipulate the model.
          def add(self):
              self.execute_current()
              self._current_op = lambda x: x + int(self.current_input.value)
      
          def sub(self):
              self.execute_current()
              self._current_op = lambda x: x - int(self.current_input.value)
      
          def mul(self):
              self.execute_current()
              self._current_op = lambda x: x * int(self.current_input.value)
      
          def div(self):
              self.execute_current()
              self._current_op = lambda x: x // int(self.current_input.value)
      
          def eql(self):
              self.execute_current()
              self._current_op = None
      
          def clr(self):
              self.current_input.value = '0'
              self._inserting = False
              self._current_op = None
      
      

      observable.py

      from PyQt5.QtCore import QObject, pyqtSignal, pyqtProperty
      
      
      # A PyQT5 Observable object class
      class Observable(QObject):
          valueChange = pyqtSignal(object)
      
          def __init__(self, val):
              super().__init__()
              self._value = val
      
          def register(self, slot):
              '''Register a slot listening for changes to this observable.'''
              self.valueChange.connect(slot)
      
          # We access the value through this getter/setter property
          @pyqtProperty(object, notify=valueChange)
          def value(self):
              '''pyqtProperty getter for the observable value.'''
              return self._value
      
          # Note that we need to explicitly emit() the signal. Declaring the
          # pyqtProperty with th notify=valueChanged above will have
          # benefits when we, for example, want to use this model in QML
          @value.setter
          def value(self, newval):
              '''pyqtProperty setter for the observable value.'''
              self._value = newval
              self.valueChange.emit(self._value)
      

      Attachments

        1. calculatormodel2.py
          2 kB
        2. FancyCalc.py
          2 kB
        3. observable.py
          1.0 kB
        4. QLineEdit Refresh Bug.mov
          3.17 MB
        5. Ui_AboutDialog.py
          2 kB
        6. Ui_FancyCalc.py
          16 kB
        No reviews matched the request. Check your Options in the drop-down menu of this sections header.

        Activity

          People

            qt.team.quick.subscriptions Qt Quick and Widgets Team
            ocrim96 ocrim96
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

              Created:
              Updated:

              Gerrit Reviews

                There are no open Gerrit changes