Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Simplest way for two-way binding a text field
Forum Updated to NodeBB v4.3 + New Features

Simplest way for two-way binding a text field

Scheduled Pinned Locked Moved Solved Qt for Python
pyside
6 Posts 3 Posters 3.1k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • X Offline
    X Offline
    xtofl
    wrote on last edited by
    #1

    Hi, I'm having trouble to have updates sent to a bound property without explicitly defining an event handler.

    class Model(QtCore.QObject):
        """simplest model with a text property"""
    
        def __init__(self):
            super().__init__()
            self._member_a = 'YES'
    
        def a(self):
            return self._member_a
    
        def set_a(self, v):
            print(f'changing to {v}')
            self._member_a = v
    
        @QtCore.Signal
        def a_changed(self):
            pass
    
        a = QtCore.Property(str, a, set_a, notify=a_changed)
    
    
    model = Model()
    
    app = QtGui.QGuiApplication(sys.argv)
    view = QtQuick.QQuickView()
    view.rootContext().setContextProperty('model', model)
    
    view.setResizeMode(QtQuick.QQuickView.SizeRootObjectToView)
    with Path('Main.qml').open('w') as f:
        f.write('''
            import QtQuick 2.0
            import QtQuick.Controls 2.0
            TextField {
              text: model.a
              // I don't want this: 
              // onEditingFinished: model.a = text
            }''')
    
    view.setSource('Main.qml')
    view.resize(100, 100)
    view.show()
    result = app.exec_()
    

    My setup is with PySide6 6..0.1:

    $ poetry show
    astroid           2.5    An abstract syntax tree for Python with inference support.
    isort             5.7.0  A Python utility / library to sort Python imports.
    lazy-object-proxy 1.5.2  A fast and thorough lazy object proxy.
    mccabe            0.6.1  McCabe checker, plugin for flake8
    pylint            2.7.0  python code static checker
    pyside6           6.0.1  Python bindings for the Qt cross-platform application and UI framework
    shiboken6         6.0.1  Python / C++ bindings helper module
    toml              0.10.2 Python Library for Toms Obvious, Minimal Language
    wrapt             1.12.1 Module for decorators, wrappers and monkey patching.
    

    I tried to find proper guidance in the documentation, but failed.

    Is there a better way than to define the onEditingFinished handler?

    Thanks!

    1 Reply Last reply
    0
    • X xtofl

      Thanks - the emit is a necessary addition, I agree. I meant that adding a line by definition makes code less simple.

      But what I really don't understand is why I would need the onEditingFinished handler in the qml itself. I was hoping to get the 2-way binding working without explicit event handling, by just binding Textfield.text property to model.a property.

      eyllanescE Offline
      eyllanescE Offline
      eyllanesc
      wrote on last edited by eyllanesc
      #6

      @xtofl In QML the binding is unidirectional: from right to left:

      Foo {
           id: foo
           a: bar.b
      }
      

      This binding indicates that every time the property "b" (which must be a signal) of the object "bar" then the property "a" of the object "foo" will be updated with that value. In python it would be something like:

      bar.b_Signal.connect(lambda: setattr(foo, "a", foo.b))
      

      If you want to implement a 2-way binding then create a class that listens when one of those properties change ("a" or "b") and then updates the other.

      If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

      1 Reply Last reply
      1
      • SGaistS Offline
        SGaistS Offline
        SGaist
        Lifetime Qt Champion
        wrote on last edited by
        #2

        Hi,

        @xtofl said in Simplest way for two-way binding a text field:

        def set_a(self, v):
        print(f'changing to {v}')
        self._member_a = v

        You are not emitting the change signal.

        The classic implementation is:

        def set_a(self, value):
            if self._member_a == value:
                return
            self._member_a = value
            self.a_changed.emit(value)
        

        Interested in AI ? www.idiap.ch
        Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

        1 Reply Last reply
        1
        • X Offline
          X Offline
          xtofl
          wrote on last edited by
          #3

          Thank you. Only... this makes things even less simple. Are you saying that this is the simplest way?

          1 Reply Last reply
          0
          • SGaistS Offline
            SGaistS Offline
            SGaist
            Lifetime Qt Champion
            wrote on last edited by
            #4

            In what way is it less simple ?

            The only simpler would be:

            def set_a(self, value):
                if self._member_a != value:
                    self._member_a = value
                    self.a_changed.emit(value)
            

            Interested in AI ? www.idiap.ch
            Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

            1 Reply Last reply
            1
            • X Offline
              X Offline
              xtofl
              wrote on last edited by
              #5

              Thanks - the emit is a necessary addition, I agree. I meant that adding a line by definition makes code less simple.

              But what I really don't understand is why I would need the onEditingFinished handler in the qml itself. I was hoping to get the 2-way binding working without explicit event handling, by just binding Textfield.text property to model.a property.

              eyllanescE 1 Reply Last reply
              0
              • X xtofl

                Thanks - the emit is a necessary addition, I agree. I meant that adding a line by definition makes code less simple.

                But what I really don't understand is why I would need the onEditingFinished handler in the qml itself. I was hoping to get the 2-way binding working without explicit event handling, by just binding Textfield.text property to model.a property.

                eyllanescE Offline
                eyllanescE Offline
                eyllanesc
                wrote on last edited by eyllanesc
                #6

                @xtofl In QML the binding is unidirectional: from right to left:

                Foo {
                     id: foo
                     a: bar.b
                }
                

                This binding indicates that every time the property "b" (which must be a signal) of the object "bar" then the property "a" of the object "foo" will be updated with that value. In python it would be something like:

                bar.b_Signal.connect(lambda: setattr(foo, "a", foo.b))
                

                If you want to implement a 2-way binding then create a class that listens when one of those properties change ("a" or "b") and then updates the other.

                If you want me to help you develop some work then you can write to my email: e.yllanescucho@gmal.com.

                1 Reply Last reply
                1

                • Login

                • Login or register to search.
                • First post
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved