【问题标题】:PySide/PyQt4: adding a checkbox to QTableWidget Horizontal (column) HeaderPySide/PyQt4:向 QTableWidget Horizo​​ntal (column) Header 添加一个复选框
【发布时间】:2012-03-16 21:53:48
【问题描述】:

我试图在我的表格小部件的水平(列)标题中放置一个复选框。基于另一篇帖子here(因为基础对象类型相同),我试过这个:

item = QtGui.QTableWidgetItem()
item.setCheckState(QtCore.Qt.Checked)
self.tableWidget.setHorizontalHeaderItem(1, item)

我也试过这个:

self.tableWidget.horizontalHeaderItem(1).setCheckState(QtCore.Qt.Checked)

这些都不会在水平标题中产生复选框。欢迎提出建议。

【问题讨论】:

    标签: python pyqt4 pyside


    【解决方案1】:

    这并不是那么漂亮,但解决此问题的方法是posted in a FAQ qt-project.org 网站。

    我已针对 Python 调整了该解决方案,并在 cmets 中提出了一些建议。

    from PyQt4.QtCore import Qt, QRect
    from PyQt4.QtGui import QTableWidget, QApplication, QHeaderView, QStyleOptionButton, QStyle
    
    import sys
    
    class MyHeader(QHeaderView):
    
        isOn = False
    
        def __init__(self, orientation, parent=None):
            QHeaderView.__init__(self, orientation, parent)
    
        def paintSection(self, painter, rect, logicalIndex):
            painter.save()
            QHeaderView.paintSection(self, painter, rect, logicalIndex)
            painter.restore()
    
            if logicalIndex == 0:
                option = QStyleOptionButton()
                option.rect = QRect(10, 10, 10, 10)
                if self.isOn:
                    option.state = QStyle.State_On
                else:
                    option.state = QStyle.State_Off
                self.style().drawControl(QStyle.CE_CheckBox, option, painter)
    
        def mousePressEvent(self, event):
            self.isOn = not self.isOn
            self.updateSection(0)
            QHeaderView.mousePressEvent(self, event)
    
    class MyTable(QTableWidget):
        def __init__(self):
            QTableWidget.__init__(self, 3, 3)
    
            myHeader = MyHeader(Qt.Horizontal, self)
            self.setHorizontalHeader(myHeader)
    
    if __name__ == '__main__':
        app = QApplication(sys.argv)
        myTable = MyTable()
        myTable.show()
        sys.exit(app.exec_())
    

    【讨论】:

    【解决方案2】:

    感谢 Gary 的回答,这是他的可检查标题的修改版本,其中所有部分都可以单独检查

    class QCheckableHeader(QHeaderView):
    
    def __init__(self, orientation, parent=None):
        QHeaderView.__init__(self, orientation, parent)
        self.lisCheckboxes = []
        self.sectionCountChanged.connect(self.onSectionCountChanged)
    
    def paintSection(self, painter, rect, logicalIndex):
        print "paintSection", logicalIndex
        painter.save()
        QHeaderView.paintSection(self, painter, rect, logicalIndex)
        painter.restore()
        painter.save()
        painter.translate(rect.topLeft())
    
        option = QStyleOptionButton()
        option.rect = QRect(10, 10, 10, 10)
        if (len(self.lisCheckboxes) != self.count()):
            self.onSectionCountChanged(len(self.lisCheckboxes), self.count())
    
        if self.lisCheckboxes[logicalIndex]:
            option.state = QStyle.State_On
        else:
            option.state = QStyle.State_Off
        self.style().drawControl(QStyle.CE_CheckBox, option, painter)
        painter.restore()
    
    def mousePressEvent(self, event):
    
        iIdx = self.logicalIndexAt(event.pos())
        self.lisCheckboxes[iIdx] = not self.lisCheckboxes[iIdx]
        self.updateSection(iIdx)
        QHeaderView.mousePressEvent(self, event)
    
    @QtCore.Slot()
    def onSectionCountChanged(self, oldCount,  newCount):
        if newCount > oldCount:
            for i in range(newCount - oldCount):
                self.lisCheckboxes.append(False)
        else:
            self.lisCheckboxes = self.lisCheckboxes[0:newCount]
    

    希望它对我以外的其他人也有帮助:-)

    【讨论】:

      【解决方案3】:

      我将功劳归功于 Gary Hughes,因为他实际上将复选框放在了标题部分本身,但我想我会继续发布我更简单的解决方案,以防有人想以简单的方式做到这一点。这是基于我在Qt Developer 论坛上获得的建议:

      我将 QTableWidget 子类化以使复选框成为 Horizo​​ntalHeader() 的子小部件,并在表格调整大小时手动重新定位复选框:

      class custom_table(QtGui.QTableWidget):
      
          def __init__(self, parent=None):
              QtGui.QTableWidget.__init__(self, parent)
              self.chkbox1 = QtGui.QCheckBox(self.horizontalHeader())
      
          def resizeEvent(self, event=None):
              super().resizeEvent(event)
              self.chkbox1.setGeometry(QtCore.QRect((self.columnWidth(0)/2), 2, 16, 17))
      

      “(self.columnWidth(0)/2)”将复选框保持在列标题的中间。

      【讨论】:

        【解决方案4】:

        改编自qt博客http://blog.qt.io/blog/2014/04/11/qt-weekly-5-widgets-on-a-qheaderview/

        这也可用于将任意小部件放入标题中

        # coding=utf-8
        from PySide.QtCore import Qt
        from PySide.QtGui import QHeaderView, QCheckBox
        from qtpy import QtCore
        
        
        class CustomHeaderView(QHeaderView):
            def __init__(self, parent=None):
                QHeaderView.__init__(self, Qt.Horizontal, parent)
                self.setMovable(True)
                self.boxes = []
        
                self.sectionResized.connect(self.handleSectionResized)
                self.sectionMoved.connect(self.handleSectionMoved)
        
            def scrollContentsBy(self, dx, dy):
                super().scrollContentsBy(dx, dy)
                if dx != 0:
                    self.fixComboPositions()
        
            def fixComboPositions(self):
                for i in range(self.count() + 1):
                    self.boxes[i].setGeometry(self.sectionViewportPosition(i), 0,
                                              self.sectionSize(i) - 5, self.height())
        
            @QtCore.Slot()
            def showEvent(self, e):
                for i in range(self.count() + 1):
                    if len(self.boxes) <= i:
                        self.boxes.append(QCheckBox(self))
                    self.boxes[i].setGeometry(self.sectionViewportPosition(i), 0,
                                              self.sectionSize(i) - 5, self.height())
                    self.boxes[i].show()
        
                super().showEvent(e)
        
            @QtCore.Slot()
            def handleSectionMoved(self, logical, oldVisualIndex, newVisualIndex):
                for i in range(min(oldVisualIndex, newVisualIndex),self.count()):
                    logical = self.logicalIndex(i)
                    self.boxes[logical].setGeometry(self.sectionViewportPosition(logical), 0,
                                                    self.sectionSize(logical) - 5, self.height())
        
            @QtCore.Slot()
            def handleSectionResized(self, i):
                for j in range(self.visualIndex(i),self.count()):
                    logical = self.logicalIndex(j)
                    self.boxes[logical].setGeometry(self.sectionViewportPosition(logical), 0,
                                                    self.sectionSize(logical) - 5, self.height())
                    self.boxes[logical].updateGeometry()
        

        【讨论】:

          猜你喜欢
          • 2011-07-19
          • 1970-01-01
          • 1970-01-01
          • 2023-01-17
          • 2011-03-30
          • 1970-01-01
          • 2019-03-30
          • 2017-01-23
          • 2011-12-05
          相关资源
          最近更新 更多