Reputation: 71
I'm attempting to make a room booking system, using a table. In the table I have check boxes, I would like it so that when the user clicks the book button, the program would see which check boxes have been checked, so that it can remove those check boxes from the table.
I have created the table through PyQt5 designer, with checkboxes in each space of the table like this:
The UI file code has many lines like this:
item = QtWidgets.QTableWidgetItem()
item.setFlags(QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled)
item.setCheckState(QtCore.Qt.Unchecked)
self.tableWidget.setItem(0, 0, item)
item = QtWidgets.QTableWidgetItem()
item.setFlags(QtCore.Qt.ItemIsUserCheckable|QtCore.Qt.ItemIsEnabled)
item.setCheckState(QtCore.Qt.Unchecked)
self.tableWidget.setItem(0, 1, item)
Does this mean that the check boxes are all called item? is there a way in which I can a separate name for each check boxes?
Sorry if this seems like a basic question - Thanks in advance
Upvotes: 2
Views: 3481
Reputation: 103
I did it for you , you are lucky)))
The main Window.
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QHeaderView
from examples.checkedItemsModel import CheckedItemsModel
from examples.checkedItemsUI import Ui_CheckedItemsView
class CheckedItems(QtWidgets.QMainWindow):
def __init__(self, model= None, parent = None):
super(CheckedItems, self).__init__(parent)
self._ui = Ui_CheckedItemsView()
self._ui.setupUi(self)
self._model = model
self._ui.ui_table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self._ui.ui_table_view.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
# set the table model
self._ui.ui_table_view.setModel(self._model)
# create connecitons
self._ui.btn_book.clicked.connect(self.print_checked_items)
def print_checked_items(self):
model = self._ui.ui_table_view.model()
items = model.checkedItems()
self._ui.ui_result.setPlainText(str(items))
print(items)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
# data for table creation
column_headers = ['P1', 'P2', 'P3', 'P4', 'P5', 'P6']
row_headers = ['C101', 'C214', 'C320', 'F04', 'E201']
# create table model
model = CheckedItemsModel(column_headers, row_headers)
# pass model to custom widget
w = CheckedItems(model)
w.show()
sys.exit(app.exec_())
Realization of the model:
import typing
from PyQt5 import QtCore
from PyQt5.QtCore import QAbstractTableModel, Qt, QModelIndex
class CheckedItemsModel(QAbstractTableModel):
def __init__(self, column_headers= [], row_headers=[], parent = None):
super(CheckedItemsModel, self).__init__(parent)
self._column_headers = column_headers
self._row_headers = row_headers
# create all unchecked items by default
self._items = []
for i in range(len(self._row_headers)):
self._items.append([])
for j in range(len(self._column_headers)):
self._items[i].append(Qt.Unchecked)
def rowCount(self, parent: QModelIndex = QtCore.QModelIndex()) -> int:
return len(self._row_headers)
def columnCount(self, parent: QModelIndex = ...) -> int:
return len(self._column_headers)
def data(self, index: QModelIndex, role: int = QtCore.Qt.DisplayRole) -> typing.Any:
if role == QtCore.Qt.DisplayRole:
return ''#str(index.row()) + ', ' + str(index.column())
if role == QtCore.Qt.CheckStateRole:
if self._items[index.row()][index.column()] == Qt.Checked:
return QtCore.Qt.Checked
else:
return QtCore.Qt.Unchecked
def headerData(self, section: int, orientation: Qt.Orientation, role: int = ...) -> typing.Any:
if role == QtCore.Qt.DisplayRole:
if orientation == Qt.Horizontal:
return self._column_headers[section]
else:
return self._row_headers[section]
def setData(self, index: QModelIndex, value: typing.Any, role: int = QtCore.Qt.EditRole) -> bool:
if role == Qt.EditRole:
self._items[index.row()][index.column()] = value
self.dataChanged.emit(index, index)
return True
if role == Qt.CheckStateRole:
self._items[index.row()][index.column()] = value
self.dataChanged.emit(index, index)
return True
def flags(self, index: QModelIndex):
return Qt.ItemIsUserCheckable | Qt.ItemIsEnabled
def checkedItems(self):
items = []
for i in range(self.rowCount()):
for j in range(self.columnCount()):
if self._items[i][j] == QtCore.Qt.Checked:
items.append('(' + str(self._row_headers[i]) + ', ' + str(self._column_headers[j]) + ')')
return items
And the View class(automatically converted .ui file to .py) from Qt Designer:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'ui_CheckedItems.ui'
#
# Created by: PyQt5 UI code generator 5.9.2
#
# WARNING! All changes made in this file will be lost!
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_CheckedItemsView(object):
def setupUi(self, CheckedItemsView):
CheckedItemsView.setObjectName("CheckedItemsView")
CheckedItemsView.resize(685, 470)
self.centralwidget = QtWidgets.QWidget(CheckedItemsView)
self.centralwidget.setObjectName("centralwidget")
self.horizontalLayout = QtWidgets.QHBoxLayout(self.centralwidget)
self.horizontalLayout.setObjectName("horizontalLayout")
self.verticalLayout = QtWidgets.QVBoxLayout()
self.verticalLayout.setObjectName("verticalLayout")
self.ui_table_view = QtWidgets.QTableView(self.centralwidget)
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.ui_table_view.sizePolicy().hasHeightForWidth())
self.ui_table_view.setSizePolicy(sizePolicy)
self.ui_table_view.setMinimumSize(QtCore.QSize(200, 200))
self.ui_table_view.setObjectName("ui_table_view")
self.verticalLayout.addWidget(self.ui_table_view)
self.ui_result = QtWidgets.QTextEdit(self.centralwidget)
self.ui_result.setReadOnly(True)
self.ui_result.setObjectName("ui_result")
self.verticalLayout.addWidget(self.ui_result)
self.buttonsLayout = QtWidgets.QHBoxLayout()
self.buttonsLayout.setObjectName("buttonsLayout")
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.buttonsLayout.addItem(spacerItem)
self.btn_book = QtWidgets.QPushButton(self.centralwidget)
self.btn_book.setObjectName("btn_book")
self.buttonsLayout.addWidget(self.btn_book)
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
self.buttonsLayout.addItem(spacerItem1)
self.verticalLayout.addLayout(self.buttonsLayout)
self.verticalLayout.setStretch(0, 5)
self.verticalLayout.setStretch(1, 1)
self.horizontalLayout.addLayout(self.verticalLayout)
CheckedItemsView.setCentralWidget(self.centralwidget)
self.retranslateUi(CheckedItemsView)
QtCore.QMetaObject.connectSlotsByName(CheckedItemsView)
def retranslateUi(self, CheckedItemsView):
_translate = QtCore.QCoreApplication.translate
CheckedItemsView.setWindowTitle(_translate("CheckedItemsView", "MainWindow"))
self.btn_book.setText(_translate("CheckedItemsView", "Book"))
How the program look like, when you execute
Upvotes: 1
Reputation: 103
Just modify a bit the code above!
1) in the constructor declare the empty list value.
self._checked_items = []
2) inside the 'book_clicked' method add line:
self._checked_items.append([h, v])
3) declare a getter of checked_items:
def checked_items(self):
return self._checked_items
4) print checked_items in the main method:
print(w.checked_items())
But I suggest you to use QTableView() , not QTableWidget(). QTableWidget() is item based, QTableView() is model based.
Of cause, at the first time it looks like more complicated, but later , when you understand how to use model based widgets you will love it!
What you have to do is to implement custom CheckedItemsModel , which extends QAbstractItemModel. Look at the documentation, you'll find a lot of examples.
Upvotes: 1
Reputation: 244301
You have to iterate over the table and do a check of the status of each item, using the filtered items you can get the row and column with what you can get the labels.
from PyQt5 import QtCore, QtGui, QtWidgets
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super(Widget, self).__init__(parent)
self.tableWidget = QtWidgets.QTableWidget(6, 5)
self.book_button = QtWidgets.QPushButton("Book")
self.book_button.clicked.connect(self.book_clicked)
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.tableWidget)
lay.addWidget(self.book_button)
self.tableWidget.setHorizontalHeaderLabels("P1 P2 P3 P4 P5 P6".split())
self.tableWidget.setVerticalHeaderLabels("C101 C214 C320 F04 E201".split())
for i in range(self.tableWidget.rowCount()):
for j in range(self.tableWidget.columnCount()):
item = QtWidgets.QTableWidgetItem()
item.setFlags(item.flags() | QtCore.Qt.ItemIsUserCheckable)
item.setCheckState(QtCore.Qt.Unchecked)
self.tableWidget.setItem(i, j, item)
@QtCore.pyqtSlot()
def book_clicked(self):
items = []
for i in range(self.tableWidget.rowCount()):
for j in range(self.tableWidget.columnCount()):
item = self.tableWidget.item(i, j)
if item.checkState() == QtCore.Qt.Checked:
items.append(item)
for it in items:
r = it.row()
c = it.column()
v, h = self.tableWidget.horizontalHeaderItem(c).text(), self.tableWidget.verticalHeaderItem(r).text()
print(h, v)
if __name__ == '__main__':
import sys
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Upvotes: 2