Search code examples
pythonpython-2.7pyqtpyqt4

Triggering and updating a docked window


I am trying to control some valves with a GUI and update the display when the button is pressed. The following code produces the correct initial display, but when I click one of the checkboxes I always get the value of i=2 and when unchecked I get i=0. I also have no idea how to update the docked window so that the message will toggle from close to open and vise versa. I do see the resultant value in self.states change in the array, but am always left with ['open', 'closed', 'open', 'closed', 'closed', 'closed'] Though this is changed the red closed on the right of the screen does not change to `open

class ApplicationWindow(gui.QMainWindow):
    def __init__(self):
        self.nCheckBoxes=6
        self.states = ['closed']*self.nCheckBoxes

        gui.QMainWindow.__init__(self)
        self.setAttribute(core.Qt.WA_DeleteOnClose)
        self.setWindowTitle("PiView")
        self.file_menu = gui.QMenu('&File', self)
        self.file_menu.addAction('&Quit', self.fileQuit, core.Qt.CTRL + core.Qt.Key_Q)
        self.menuBar().addMenu(self.file_menu)
        self.help_menu = gui.QMenu('&Help', self)
        self.menuBar().addSeparator()
        self.menuBar().addMenu(self.help_menu)
        self.help_menu.addAction('&About', self.about)
        self.help_menu.addAction('&Docs', self.doc)
        self.main_widget = gui.QWidget(self)

        l = gui.QVBoxLayout(self.main_widget)
        self.dc = MyMplCanvas(self.main_widget, width=5, height=4, dpi=100)
        l.addWidget(self.dc)

        self.main_widget.setFocus()
        self.setCentralWidget(self.main_widget)

        self.dw = self.createDockWindows(self.dc)
        self.statusBar().showMessage("Initialized", 2000)

    def createDockWindows(self, MyMplCanvas):
        """
        Create all the dock widgets
        """
        self.drawValves()
        self.drawGraphAdjustments()
        self.drawStartAndStop()

    def drawValves(self):
        cboxes = gui.QDockWidget("Controls", self)
        cboxes.setAllowedAreas(core.Qt.LeftDockWidgetArea)
        w = gui.QWidget()
        #layout = gui.QVBoxLayout()
        layout = gui.QGridLayout()
        w.setLayout(layout)

        self.c = [0]*self.nCheckBoxes
        # Create self.nCheckBoxes
        msgBox = gui.QLabel()
        msgBox.setText("States")
        font = gui.QFont()
        font.setBold(True)
        msgBox.setFont(font)
        msgBox.setStyleSheet("color: rgb(255,0,0)")
        layout.addWidget(msgBox,0,1)
        for i in range(self.nCheckBoxes):
            self.c[i] = gui.QCheckBox("Valve " + str(i))
            self.c[i].setChecked(False)
            #self.c[i].stateChanged.connect(lambda:self.btnstate(self.c[i]))
            #self.c[i].stateChanged.connect(self.checkedBox)
            self.c[i].stateChanged.connect(lambda i: self.checkedBox(i))
            layout.addWidget(self.c[i],i+1,0)
            # Messages
            msgBox = gui.QLabel()
            msgBox.setText(self.states[i])
            if self.states[i] == 'closed':
                msgBox.setStyleSheet("color: rgb(255,0,0)")
            else:
                msgBox.setStyleSheet("color: rgb(0,255,0)")
            layout.addWidget(msgBox,i+1,1)

        spacerItem = gui.QSpacerItem(20,40, gui.QSizePolicy.Minimum, gui.QSizePolicy.Expanding)
        layout.addItem(spacerItem)
        cboxes.setWidget(w)
        self.addDockWidget(core.Qt.LeftDockWidgetArea, cboxes)

    def checkedBox(self,i):
        sender = self.sender()
        self.states[i] = 'open' if 'close' else 'close'
        # For debugging
        print i
        print self.states

If I understand correctly I can just actuate the valve like I would normally in the function checkedBox.

This is what is displayed Unchecked Checked I want to be able to click a checkbox and the message just to the right to change from closed to open, and vise versa.


Solution

  • The problem arises because the default value of i takes the value sent by the signal (ie state: Unchecked = 0, PartiallyChecked = 1, Checked = 2), to solve this we will add a further value to the function: Index of the checkbox. Also if you want to change the text of QLabel you must be able to access them so I have created a new list with labels. To make the change we will use the states list, for this implement the function updateLabels.

    class ApplicationWindow(gui.QMainWindow):
        def __init__(self):
            self.nCheckBoxes=6
            self.states = ['closed']*self.nCheckBoxes
    
            gui.QMainWindow.__init__(self)
            self.setAttribute(core.Qt.WA_DeleteOnClose)
            self.setWindowTitle("PiView")
            self.file_menu = gui.QMenu('&File', self)
            #self.file_menu.addAction('&Quit', self.fileQuit, core.Qt.CTRL + core.Qt.Key_Q)
            self.menuBar().addMenu(self.file_menu)
            self.help_menu = gui.QMenu('&Help', self)
            self.menuBar().addSeparator()
            self.menuBar().addMenu(self.help_menu)
            #self.help_menu.addAction('&About', self.about)
            #self.help_menu.addAction('&Docs', self.doc)
            self.main_widget = gui.QWidget(self)
    
            l = gui.QVBoxLayout(self.main_widget)
            self.dc = MyMplCanvas(self.main_widget, width=5, height=4, dpi=100)
            l.addWidget(self.dc)
    
            self.main_widget.setFocus()
            self.setCentralWidget(self.main_widget)
    
            self.dw = self.createDockWindows(self.dc)
            self.statusBar().showMessage("Initialized", 2000)
    
        def createDockWindows(self, MyMplCanvas):
            """
            Create all the dock widgets
            """
            self.drawValves()
            #self.drawGraphAdjustments()
            #self.drawStartAndStop()
    
        def drawValves(self):
            cboxes = gui.QDockWidget("Controls", self)
            cboxes.setAllowedAreas(core.Qt.LeftDockWidgetArea)
            w = gui.QWidget()
            #layout = gui.QVBoxLayout()
            layout = gui.QGridLayout()
            w.setLayout(layout)
    
            self.c = []
            self.l = []
            # Create self.nCheckBoxes
            msgBox = gui.QLabel()
            msgBox.setText("States")
            font = gui.QFont()
            font.setBold(True)
            msgBox.setFont(font)
            msgBox.setStyleSheet("color: rgb(255,0,0)")
            layout.addWidget(msgBox,0,1)
            for i in range(self.nCheckBoxes):
                checkBox = gui.QCheckBox("Valve " + str(i))
                checkBox.setChecked(False)
                checkBox.stateChanged.connect(lambda state, p=i: self.checkedBox(state, p))
                self.c.append(checkBox)
    
                layout.addWidget(self.c[i],i+1,0)
                msgBox = gui.QLabel()
                msgBox.setText(self.states[i])
                self.l.append(msgBox)
                layout.addWidget(msgBox,i+1,1)
    
            self.update_labels()
    
            spacerItem = gui.QSpacerItem(20,40, gui.QSizePolicy.Minimum, gui.QSizePolicy.Expanding)
            layout.addItem(spacerItem)
            cboxes.setWidget(w)
            self.addDockWidget(core.Qt.LeftDockWidgetArea, cboxes)
    
        def checkedBox(self, state, p):
            if state == core.Qt.Unchecked:
                self.states[p] = 'closed'
            else:
                self.states[p] = 'open'
    
            self.update_labels()
    
        def update_labels(self):
            for i in range(self.nCheckBoxes):
                if self.states[i] == 'closed':
                    text = "closed"
                    styleSheet = "color: rgb(255,0,0)"
                else:
                    text = "open"
                    styleSheet = "color: rgb(0,255,0)"
                self.l[i].setText(text)
                self.l[i].setStyleSheet(styleSheet)
    

    enter image description here

    enter image description here