dre*_*iya 11 python pyqt python-2.7 pandas
我正在从Pandas数据帧动态创建QTableView.我这里有示例代码.
我可以使用复选框创建表格,但是我无法获得反映模型数据的复选框,甚至根本无法更改为取消选中.
我正在关注上一个问题的示例代码,并以@raorao答案为指导.这将显示表格中的框,但不起作用.
任何人都可以建议任何更改,或者此代码有什么问题.为什么它不反映模型,为什么它不会改变?
请查看我的完整示例代码.
编辑一:Frodon评论后更新:更正了字符串强制转换为bool并进行比较xxx =='True'
class CheckBoxDelegate(QtGui.QStyledItemDelegate):
"""
A delegate that places a fully functioning QCheckBox in every
cell of the column to which it's applied
"""
def __init__(self, parent):
QtGui.QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
'''
Important, otherwise an editor is created if the user clicks in this cell.
** Need to hook up a signal to the model
'''
return None
def paint(self, painter, option, index):
'''
Paint a checkbox without the label.
'''
checked = index.model().data(index, QtCore.Qt.DisplayRole) == 'True'
check_box_style_option = QtGui.QStyleOptionButton()
if (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
check_box_style_option.state |= QtGui.QStyle.State_Enabled
else:
check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
if checked:
check_box_style_option.state |= QtGui.QStyle.State_On
else:
check_box_style_option.state |= QtGui.QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
# this will not run - hasFlag does not exist
#if not index.model().hasFlag(index, QtCore.Qt.ItemIsEditable):
#check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
check_box_style_option.state |= QtGui.QStyle.State_Enabled
QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
'''
Change the data in the model and the state of the checkbox
if the user presses the left mousebutton or presses
Key_Space or Key_Select and this cell is editable. Otherwise do nothing.
'''
print 'Check Box editor Event detected : '
if not (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
print 'Check Box edior Event detected : passed first check'
# Do not change the checkbox-state
if event.type() == QtCore.QEvent.MouseButtonRelease or event.type() == QtCore.QEvent.MouseButtonDblClick:
if event.button() != QtCore.Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
return False
if event.type() == QtCore.QEvent.MouseButtonDblClick:
return True
elif event.type() == QtCore.QEvent.KeyPress:
if event.key() != QtCore.Qt.Key_Space and event.key() != QtCore.Qt.Key_Select:
return False
else:
return False
# Change the checkbox-state
self.setModelData(None, model, index)
return True
Run Code Online (Sandbox Code Playgroud)
我找到了适合你的解决方案.诀窍是:
setData
模型的方法data
方法中返回QVariant这里是.(我必须创建一个名为的类Dataframe
,以使示例在没有大熊猫的情况下工作.请替换您的所有if has_pandas
语句):
from PyQt4 import QtCore, QtGui
has_pandas = False
try:
import pandas as pd
has_pandas = True
except:
pass
class TableModel(QtCore.QAbstractTableModel):
def __init__(self, parent=None, *args):
super(TableModel, self).__init__()
self.datatable = None
self.headerdata = None
def update(self, dataIn):
print 'Updating Model'
self.datatable = dataIn
print 'Datatable : {0}'.format(self.datatable)
if has_pandas:
headers = dataIn.columns.values
else:
headers = dataIn.columns
header_items = [
str(field)
for field in headers
]
self.headerdata = header_items
print 'Headers'
print self.headerdata
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.datatable.index)
def columnCount(self, parent=QtCore.QModelIndex()):
if has_pandas:
return len(self.datatable.columns.values)
else:
return len(self.datatable.columns)
def data(self, index, role=QtCore.Qt.DisplayRole):
if role == QtCore.Qt.DisplayRole:
i = index.row()
j = index.column()
return QtCore.QVariant('{0}'.format(self.datatable.iget_value(i, j)))
else:
return QtCore.QVariant()
def setData(self, index, value, role=QtCore.Qt.DisplayRole):
if index.column() == 4:
self.datatable.iset_value(index.row(), 4, value)
return value
return value
def headerData(self, col, orientation, role):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return '{0}'.format(self.headerdata[col])
def flags(self, index):
if index.column() == 4:
return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled
else:
return QtCore.Qt.ItemIsEnabled
class TableView(QtGui.QTableView):
"""
A simple table to demonstrate the QComboBox delegate.
"""
def __init__(self, *args, **kwargs):
QtGui.QTableView.__init__(self, *args, **kwargs)
self.setItemDelegateForColumn(4, CheckBoxDelegate(self))
class CheckBoxDelegate(QtGui.QStyledItemDelegate):
"""
A delegate that places a fully functioning QCheckBox in every
cell of the column to which it's applied
"""
def __init__(self, parent):
QtGui.QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
'''
Important, otherwise an editor is created if the user clicks in this cell.
** Need to hook up a signal to the model
'''
return None
def paint(self, painter, option, index):
'''
Paint a checkbox without the label.
'''
checked = index.data().toBool()
check_box_style_option = QtGui.QStyleOptionButton()
if (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
check_box_style_option.state |= QtGui.QStyle.State_Enabled
else:
check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
if checked:
check_box_style_option.state |= QtGui.QStyle.State_On
else:
check_box_style_option.state |= QtGui.QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
# this will not run - hasFlag does not exist
#if not index.model().hasFlag(index, QtCore.Qt.ItemIsEditable):
#check_box_style_option.state |= QtGui.QStyle.State_ReadOnly
check_box_style_option.state |= QtGui.QStyle.State_Enabled
QtGui.QApplication.style().drawControl(QtGui.QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
'''
Change the data in the model and the state of the checkbox
if the user presses the left mousebutton or presses
Key_Space or Key_Select and this cell is editable. Otherwise do nothing.
'''
print 'Check Box editor Event detected : '
print event.type()
if not (index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
print 'Check Box editor Event detected : passed first check'
# Do not change the checkbox-state
if event.type() == QtCore.QEvent.MouseButtonPress:
return False
if event.type() == QtCore.QEvent.MouseButtonRelease or event.type() == QtCore.QEvent.MouseButtonDblClick:
if event.button() != QtCore.Qt.LeftButton or not self.getCheckBoxRect(option).contains(event.pos()):
return False
if event.type() == QtCore.QEvent.MouseButtonDblClick:
return True
elif event.type() == QtCore.QEvent.KeyPress:
if event.key() != QtCore.Qt.Key_Space and event.key() != QtCore.Qt.Key_Select:
return False
else:
return False
# Change the checkbox-state
self.setModelData(None, model, index)
return True
def setModelData (self, editor, model, index):
'''
The user wanted to change the old state in the opposite.
'''
print 'SetModelData'
newValue = not index.data().toBool()
print 'New Value : {0}'.format(newValue)
model.setData(index, newValue, QtCore.Qt.EditRole)
def getCheckBoxRect(self, option):
check_box_style_option = QtGui.QStyleOptionButton()
check_box_rect = QtGui.QApplication.style().subElementRect(QtGui.QStyle.SE_CheckBoxIndicator, check_box_style_option, None)
check_box_point = QtCore.QPoint (option.rect.x() +
option.rect.width() / 2 -
check_box_rect.width() / 2,
option.rect.y() +
option.rect.height() / 2 -
check_box_rect.height() / 2)
return QtCore.QRect(check_box_point, check_box_rect.size())
###############################################################################################################################
class Dataframe(dict):
def __init__(self, columns, values):
if len(values) != len(columns):
raise Exception("Bad values")
self.columns = columns
self.values = values
self.index = values[0]
super(Dataframe, self).__init__(dict(zip(columns, values)))
pass
def iget_value(self, i, j):
return(self.values[j][i])
def iset_value(self, i, j, value):
self.values[j][i] = value
if __name__=="__main__":
from sys import argv, exit
class Widget(QtGui.QWidget):
"""
A simple test widget to contain and own the model and table.
"""
def __init__(self, parent=None):
QtGui.QWidget.__init__(self, parent)
l=QtGui.QVBoxLayout(self)
cdf = self.get_data_frame()
self._tm=TableModel(self)
self._tm.update(cdf)
self._tv=TableView(self)
self._tv.setModel(self._tm)
for row in range(0, self._tm.rowCount()):
self._tv.openPersistentEditor(self._tm.index(row, 4))
self.setGeometry(300, 300, 550, 200)
l.addWidget(self._tv)
def get_data_frame(self):
if has_pandas:
df = pd.DataFrame({'Name':['a','b','c','d'],
'First':[2.3,5.4,3.1,7.7], 'Last':[23.4,11.2,65.3,88.8], 'Class':[1,1,2,1], 'Valid':[True, False, True, False]})
else:
columns = ['Name', 'First', 'Last', 'Class', 'Valid']
values = [['a','b','c','d'], [2.3,5.4,3.1,7.7], [23.4,11.2,65.3,88.8], [1,1,2,1], [True, False, True, False]]
df = Dataframe(columns, values)
return df
a=QtGui.QApplication(argv)
w=Widget()
w.show()
w.raise_()
exit(a.exec_())
Run Code Online (Sandbox Code Playgroud)
这是上面与PyQt5相同代码的端口。在这里发帖,因为似乎并没有QT5中CheckBox代表可以正常工作的另一个例子,而我正在撕扯我的头发,以使其正常工作。希望它对某人有用。
from PyQt5 import QtCore, QtWidgets
from PyQt5.QtCore import QModelIndex
from PyQt5.QtGui import QStandardItemModel
from PyQt5.QtWidgets import QApplication, QTableView
class CheckBoxDelegate(QtWidgets.QItemDelegate):
"""
A delegate that places a fully functioning QCheckBox cell of the column to which it's applied.
"""
def __init__(self, parent):
QtWidgets.QItemDelegate.__init__(self, parent)
def createEditor(self, parent, option, index):
"""
Important, otherwise an editor is created if the user clicks in this cell.
"""
return None
def paint(self, painter, option, index):
"""
Paint a checkbox without the label.
"""
self.drawCheck(painter, option, option.rect, QtCore.Qt.Unchecked if int(index.data()) == 0 else QtCore.Qt.Checked)
def editorEvent(self, event, model, option, index):
'''
Change the data in the model and the state of the checkbox
if the user presses the left mousebutton and this cell is editable. Otherwise do nothing.
'''
if not int(index.flags() & QtCore.Qt.ItemIsEditable) > 0:
return False
if event.type() == QtCore.QEvent.MouseButtonRelease and event.button() == QtCore.Qt.LeftButton:
# Change the checkbox-state
self.setModelData(None, model, index)
return True
return False
def setModelData (self, editor, model, index):
'''
The user wanted to change the old state in the opposite.
'''
model.setData(index, 1 if int(index.data()) == 0 else 0, QtCore.Qt.EditRole)
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
model = QStandardItemModel(4, 3)
tableView = QTableView()
tableView.setModel(model)
delegate = CheckBoxDelegate(None)
tableView.setItemDelegateForColumn(1, delegate)
for row in range(4):
for column in range(3):
index = model.index(row, column, QModelIndex())
model.setData(index, 1)
tableView.setWindowTitle("Check Box Delegate")
tableView.show()
sys.exit(app.exec_())
Run Code Online (Sandbox Code Playgroud)