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. Checkbox keeps initial state even after it has been changed

Checkbox keeps initial state even after it has been changed

Scheduled Pinned Locked Moved Solved Qt for Python
5 Posts 2 Posters 289 Views
  • 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.
  • SIG_KILLS Offline
    SIG_KILLS Offline
    SIG_KILL
    wrote on last edited by SIG_KILL
    #1

    This widget I created is just a vBox of 16 checkboxes. The problem I am stuck on is the checkbox always returns the initial state it was assigned. I have attached the full code of the widget and a screenshot before/after checking it.

    Windows: 10
    Python: 3.10.5
    PySide6: 6.3.0

    from typing import Dict
    
    from PySide6.QtCore import Qt, Signal
    from PySide6.QtWidgets import (
        QWidget,
        QCheckBox,
        QVBoxLayout,
    )
    
    
    class SwarmTable(QWidget):
    
        def __init__(self, parent=None):
            super().__init__(parent)
            self.parent = parent
    
            self.layout = QVBoxLayout()
            self.layout.setContentsMargins(10, 10, 10, 10)
            self.layout.setSpacing(1)
    
            self.add_rows()
            self.setLayout(self.layout)
            self.layout.addStretch(1)
    
        def add_rows(self):
            for port in range(1, 17):
                cb = QCheckBox(self)
                cb.setText(f"Port {port}")
                cb.setCheckState(Qt.Unchecked)
                cb.setEnabled(port < 15)
                self.layout.addWidget(cb, 0, Qt.AlignLeft | Qt.AlignVCenter)
    
        def get_active_ports(self) -> Dict[int, bool]:
            for c in self.children():
                if isinstance(c, QCheckBox):
                    print(f"{c.text()} is {c.checkState()}")
    
    

    af77f69b-f689-4144-b396-ef1232686760-image.png
    Initializes as expected SwarmTable.get_active_ports() returns:

    Port 1 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 2 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 3 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 4 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 5 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 6 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 7 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 8 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 9 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 10 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 11 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 12 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 13 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 14 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 15 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 16 is PySide6.QtCore.Qt.CheckState.Unchecked
    

    b386bada-50ee-4098-9118-f248a65e3a01-image.png
    However when I click a port, it shows visually correct but SwarmTable.get_active_ports() still returns the same incorrect information.

    Port 1 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 2 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 3 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 4 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 5 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 6 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 7 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 8 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 9 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 10 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 11 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 12 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 13 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 14 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 15 is PySide6.QtCore.Qt.CheckState.Unchecked
    Port 16 is PySide6.QtCore.Qt.CheckState.Unchecked
    

    Any ideas or suggestions would be appreciated. Been stuck on this for a few hours. Thanks!

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

      Hi,

      Where and how are you calling get_active_ports ?

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

      SIG_KILLS 1 Reply Last reply
      0
      • SGaistS SGaist

        Hi,

        Where and how are you calling get_active_ports ?

        SIG_KILLS Offline
        SIG_KILLS Offline
        SIG_KILL
        wrote on last edited by
        #3

        @SGaist
        I have an object that holds all my external process communication. When I click the purple "play" button in the toolbar, it calls the slot ProcManager.start_process seen in the following.

        class ProcManager(QObject):
            status_fwd = Signal(str)
            result_fwd = Signal(dict)
        
            uut_pt_fwd = Signal(dict)
            ref_pt_fwd = Signal(np.float64)
        
            active_uut_fwd = Signal(dict)
        
            active_step_fwd = Signal(dict)
            all_steps_fwd = Signal(dict)
        
            def __init__(self, parent):
                super().__init__(parent)
                self.parent = parent
        
                self.passive_cal = QProcess()
                self.passive_cal.setProcessChannelMode(QProcess.MergedChannels)
                self.passive_cal.setProgram("cal_passive_ion")
        
                self._timer = QTimer()
                self._timer.setInterval(100)
                self._timer.timeout.connect(self.read_stdout)
        
            def __init__(self, parent):
                super().__init__(parent)
                self.parent = parent
                self.pool = QThreadPool.globalInstance()
        
                self.passive_cal = QProcess()
                self.passive_cal.setProcessChannelMode(QProcess.MergedChannels)
                self.passive_cal.setProgram("cal_passive_ion")
        
                self._timer = QTimer()
                self._timer.setInterval(100)
                self._timer.timeout.connect(self.read_stdout)
        
            @Slot()
            def start_process(self):
                # get_active_ports() returns Dict[int, bool] 
                #   where int is the port number and bool is whether it is active
                # Don't need to go past here to observer issue.
                _a = json.dumps(self.parent.main_activity.tabs.ports_view.get_active_ports())
        
                self.passive_cal.setArguments([f"--active-ports={_a}"])
                self.passive_cal.start()
                self._timer.start()
        
            @Slot()
            def stop_process(self):
                self.passive_cal.terminate()
        
        

        and for reference heres my Mainwindow and MainActivity

        
        class MainActivity(QWidget):
            def __init__(self, parent=None):
                super().__init__()
                self.parent = parent
                layout = QHBoxLayout()
                layout.addWidget(self.tabs, 2)
                layout.addWidget(self.chart, 8)
                self.setLayout(layout)
        
            @cached_property
            def tabs(self):
                return DetailsTabs(self)
        
            @cached_property
            def chart(self):
                return PressurePlot(self)
        
        
        class MainWindow(QMainWindow):
            def __init__(self):
                super().__init__()
                self.session = Session(self)
                self.settings = Settings(self)
                self.proc_man = ProcManager(self)
                self.toolbar.start_calibration.connect(self.proc_man.start_process)
                self.toolbar.stop_calibration.connect(self.proc_man.stop_process)
                self.addToolBar(self.toolbar)
                self.setCentralWidget(self.main_activity)
        
            @cached_property
            def toolbar(self):
                return Toolbar(self)
        
            @cached_property
            def main_activity(self):
                return MainActivity(self)
        
        
        if __name__ == "__main__":
            app = QApplication(sys.argv)
            app.setStyle("Fusion")
        
            window = MainWindow()
            window.resize(QSize(1400, 947))
            window.show()
        
            sys.exit(app.exec())
        
        
        1 Reply Last reply
        0
        • SGaistS Offline
          SGaistS Offline
          SGaist
          Lifetime Qt Champion
          wrote on last edited by
          #4

          One issue I can see is that your widget explicitly grabs data from an unrelated widget through the parent which is a bad sign.

          It should rather be the other way around, the widget should be configured externally or through signals and slots.

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

          SIG_KILLS 1 Reply Last reply
          0
          • SGaistS SGaist

            One issue I can see is that your widget explicitly grabs data from an unrelated widget through the parent which is a bad sign.

            It should rather be the other way around, the widget should be configured externally or through signals and slots.

            SIG_KILLS Offline
            SIG_KILLS Offline
            SIG_KILL
            wrote on last edited by
            #5

            @SGaist I am not sure what you mean by "your widget explicitly grabs data from an unrelated widget through the parent" but I removed any use of self.parent... made get_active_ports into a slot that emits a signal. I then observed the same issue.

            So just out of curiosity I wanted to remove the cached_property decorator to see if that was part of the issue, and I noticed the table widget was a property, not a cached_property. So now my main widget looks like this:

            class MainActivity(QWidget):
                def __init__(self, parent=None):
                    super().__init__()
                    self.parent = parent
                    layout = QHBoxLayout()
                    layout.addWidget(self.tabs, 2)
                    layout.addWidget(self.chart, 8)
                    self.setLayout(layout)
            
                @cached_property  # <-- was @property
                def tabs(self):
                    return DetailsTabs(self)
            
                @cached_property
                def chart(self):
                    return PressurePlot(self)
            

            That was a typo on my part. Everything works fine now. Better, actually, because I think the change to signal/slot is more consistent.

            Thanks for you help help @SGaist , wouldn't have seen my if I didn't go to change that method call to a signal/slot. :)

            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