我正试图在表小部件的水平(列)标题中放置一个复选框。基于这里的另一篇文章(因为基本对象类型相同),我尝试了这个:
item = QtGui.QTableWidgetItem()
item.setCheckState(QtCore.Qt.Checked)
self.tableWidget.setHorizontalHeaderItem(1, item)
我也试过这个:
self.tableWidget.horizontalHeaderItem(1).setCheckState(QtCore.Qt.Checked)
这两者都不会在水平标题中产生复选框。欢迎提出建议。
这并不那么漂亮,但qt-project.org网站上的常见问题解答中发布了一个解决方案。
我已经为Python调整了解决方案,并在评论中进行了一些修改。
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_())
为了感谢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]
希望它也能帮助除我之外的其他人:-)
我赞扬了Gary Hughes,因为他实际上把复选框放在了标题部分,但我想我会继续发布我的更简单的解决方案,以防有人想用简单的方式来做。这是基于我在Qt开发者论坛上得到的建议:
我将QTableWidget子类化,使复选框成为horizontalHeader()的子窗口小部件,并在表调整大小时手动重新定位复选框:
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)"将复选框保留在列标题的中间。
改编自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()