2
votes

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:

enter image description here

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

3
what is the name of check box?eyllanesc
I'm not sure, as I said I designed it in PyQt designer, so I used the QTableWidget, double clicked on it, went to items, properties then under flags I checked user Checkable.Taf
No, I think you did not understand me, you want to identify the checkbox so I wonder what data you want to get from the item, in my answer I have proposed to print the label of the row and the columneyllanesc

3 Answers

2
votes

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_())
1
votes

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.

1
votes

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