Несколько QcheckBox в одном QTableView. Выбрать только один QcheckBox
Столкнулся с проблемы. Есть таблица, в которой на одной строчке расположено несколько QcheckBox. Пользователь может изменить значение QcheckBox при помощи клика мыши.
Необходимо сделать так что в приделах одной строчки была, только одна галочка. То есть, при нажатии на Иванов status_2 галочка status_1 для Иванова уходила и вставала на status_2, соответственно должно работать и наоборот.
Также необходимо иметь актуальные данные, что реализовано в методе setData.
Подскажите как это сделать, не обновляя модель. Ниже указана часть кода:
import sys
from PyQt5 import QtWidgets, QtCore
class CheckBoxDelegate(QtWidgets.QItemDelegate):
def __init__(self, parent):
super().__init__(parent)
def createEditor(self, parent, option, index):
return None
def paint(self, painter, option, index):
checked = index.model().data(index, QtCore.Qt.DisplayRole) is True
check_box_style_option = QtWidgets.QStyleOptionButton()
if checked:
check_box_style_option.state |= QtWidgets.QStyle.State_On
else:
check_box_style_option.state |= QtWidgets.QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
check_box_style_option.state |= QtWidgets.QStyle.State_Enabled
QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
if event.type() == QtCore.QEvent.MouseButtonRelease:
if event.button() == QtCore.Qt.LeftButton:
model.setData(index, not index.data(), QtCore.Qt.DisplayRole)
return True
return False
def getCheckBoxRect(self, option):
check_box_style_option = QtWidgets.QStyleOptionButton()
check_box_rect = QtWidgets.QApplication.style().subElementRect(QtWidgets.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 TmodelCustom(QtCore.QAbstractTableModel):
def __init__(self, data=None, header=None):
QtCore.QAbstractTableModel.__init__(self)
self.arraydata = data
self.header = header
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.arraydata)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.arraydata[0])
def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.header[section])
else:
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return QtCore.QVariant()
column = index.column()
row = index.row()
val = self.arraydata[row][column]
if role == QtCore.Qt.DisplayRole:
if val is None:
return ""
else:
return val
return QtCore.QVariant()
def setData(self, index, value, role=QtCore.Qt.ItemDataRole):
self.arraydata[index.row()][index.column()] = value
self.dataChanged.emit(index, index, [QtCore.Qt.EditRole])
return True
def getData(self):
return self.arraydata
class Window(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.Window)
QtWidgets.QMainWindow.__init__(self)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
grid_layout = QtWidgets.QGridLayout()
central_widget.setLayout(grid_layout)
self.table = QtWidgets.QTableView(self)
horisontal_layout = QtWidgets.QHBoxLayout()
horisontal_layout.addStretch(1)
horisontal_layout.setAlignment(QtCore.Qt.AlignRight)
grid_layout.addLayout(horisontal_layout, 0, 0)
grid_layout.addWidget(self.table, 0, 0)
self.model = None
self.initTable()
def initTable(self):
header = ["Name", 'status_1', 'status_2']
df = [['Иванов', True, False],
['Сидорово', True, False],
['Петров', False, True]]
self.model = TmodelCustom(data=df, header=header)
self.table.setModel(self.model)
delegate = CheckBoxDelegate(self)
# self.table.setItemDelegateForColumn(0, delegate)
self.table.setItemDelegateForColumn(1, delegate)
self.table.setItemDelegateForColumn(2, delegate)
self.model.dataChanged.connect(self.test)
def test(self):
pass
if __name__ == "__main__":
application = QtWidgets.QApplication([])
window = Window()
window.setWindowTitle("Counter")
window.setMinimumSize(480, 380)
window.show()
sys.exit(application.exec_())
Заранее благодарю Вас!
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Попробуйте так:
import sys
from PyQt5 import QtWidgets, QtCore
class CheckBoxDelegate(QtWidgets.QItemDelegate):
def __init__(self, parent):
super().__init__(parent)
def createEditor(self, parent, option, index):
return None
def paint(self, painter, option, index):
checked = index.model().data(index, QtCore.Qt.DisplayRole) is True
check_box_style_option = QtWidgets.QStyleOptionButton()
if checked:
check_box_style_option.state |= QtWidgets.QStyle.State_On
else:
check_box_style_option.state |= QtWidgets.QStyle.State_Off
check_box_style_option.rect = self.getCheckBoxRect(option)
check_box_style_option.state |= QtWidgets.QStyle.State_Enabled
QtWidgets.QApplication.style().drawControl(QtWidgets.QStyle.CE_CheckBox, check_box_style_option, painter)
def editorEvent(self, event, model, option, index):
if event.type() == QtCore.QEvent.MouseButtonRelease:
if event.button() == QtCore.Qt.LeftButton:
# !!!
# +++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
fl = not index.data()
# model.setData(index, not index.data(), QtCore.Qt.DisplayRole)
model.setData(index, fl, QtCore.Qt.DisplayRole)
if fl:
row = index.row()
column = index.column()
column = 1 if column == 2 else 2
_index = model.index(row, column)
model.setData(_index, False, QtCore.Qt.DisplayRole)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
return True
return False
def getCheckBoxRect(self, option):
check_box_style_option = QtWidgets.QStyleOptionButton()
check_box_rect = QtWidgets.QApplication.style().subElementRect(QtWidgets.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 TmodelCustom(QtCore.QAbstractTableModel):
def __init__(self, data=None, header=None):
QtCore.QAbstractTableModel.__init__(self)
self.arraydata = data
self.header = header
def rowCount(self, parent=QtCore.QModelIndex()):
return len(self.arraydata)
def columnCount(self, parent=QtCore.QModelIndex()):
return len(self.arraydata[0])
def headerData(self, section: int, orientation: QtCore.Qt.Orientation, role: int = QtCore.Qt.DisplayRole):
if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
return QtCore.QVariant(self.header[section])
else:
return QtCore.QVariant()
def data(self, index, role=QtCore.Qt.DisplayRole):
if not index.isValid():
return QtCore.QVariant()
column = index.column()
row = index.row()
val = self.arraydata[row][column]
if role == QtCore.Qt.DisplayRole:
if val is None:
return ""
else:
return val
return QtCore.QVariant()
def setData(self, index, value, role=QtCore.Qt.ItemDataRole):
self.arraydata[index.row()][index.column()] = value
self.dataChanged.emit(index, index, [QtCore.Qt.EditRole])
return True
def getData(self):
return self.arraydata
class Window(QtWidgets.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.setWindowFlags(QtCore.Qt.Window)
QtWidgets.QMainWindow.__init__(self)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
grid_layout = QtWidgets.QGridLayout()
central_widget.setLayout(grid_layout)
self.table = QtWidgets.QTableView(self)
horisontal_layout = QtWidgets.QHBoxLayout()
horisontal_layout.addStretch(1)
horisontal_layout.setAlignment(QtCore.Qt.AlignRight)
grid_layout.addLayout(horisontal_layout, 0, 0)
grid_layout.addWidget(self.table, 0, 0)
self.model = None
self.initTable()
def initTable(self):
header = ["Name", 'status_1', 'status_2']
df = [['Иванов', True, False],
['Сидорово', True, False],
['Петров', False, True]]
self.model = TmodelCustom(data=df, header=header)
self.table.setModel(self.model)
delegate = CheckBoxDelegate(self)
# self.table.setItemDelegateForColumn(0, delegate)
self.table.setItemDelegateForColumn(1, delegate)
self.table.setItemDelegateForColumn(2, delegate)
self.model.dataChanged.connect(self.test)
def test(self):
pass
if __name__ == "__main__":
application = QtWidgets.QApplication([])
window = Window()
window.setWindowTitle("Counter")
window.setMinimumSize(480, 380)
window.show()
sys.exit(application.exec_())
