Есть ли способ проверить, какие флажки были отмечены в таблице PyQt5

Я пытаюсь создать систему бронирования номеров, используя таблицу. В таблице у меня есть флажки, я бы хотел, чтобы, когда пользователь нажимает кнопку книги, программа видела, какие флажки были отмечены, чтобы она могла удалить эти флажки из таблицы.

Я создал таблицу с помощью дизайнера PyQt5 с флажками в каждом пространстве таблицы, например:

введите здесь описание изображения

В коде файла пользовательского интерфейса много таких строк:

        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)

Означает ли это, что все флажки называются элементами? есть ли способ, которым я могу указать отдельное имя для каждого флажка?

Извините, если это кажется базовым вопросом. Заранее спасибо.


person Taf    schedule 30.03.2019    source источник
comment
как называется флажок?   -  person eyllanesc    schedule 31.03.2019
comment
Я не уверен, как я уже сказал, я разработал его в дизайнере PyQt, поэтому я использовал QTableWidget, дважды щелкнул по нему, перешел к элементам, свойствам, а затем под флагами я проверил пользователя Checkable.   -  person Taf    schedule 31.03.2019
comment
Нет, я думаю, вы меня не поняли, вы хотите идентифицировать флажок, поэтому мне интересно, какие данные вы хотите получить от элемента, в моем ответе я предложил напечатать метку строки и столбца.   -  person eyllanesc    schedule 31.03.2019


Ответы (3)


Вы должны перебирать таблицу и проверять состояние каждого элемента, используя отфильтрованные элементы, вы можете получить строку и столбец, с помощью которых вы можете получить метки.

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_())
person eyllanesc    schedule 30.03.2019
comment
Как я могу сделать так, чтобы вместо печати (h, v) они добавлялись в один массив или список, чтобы затем печатать как один. - person Taf; 31.03.2019
comment
Также, как бы я снял флажок после этого - person Taf; 31.03.2019

Просто немного измените код выше!

1) в конструкторе объявить значение пустого списка.

self._checked_items = []

2) внутри метода book_clicked добавить строку:

self._checked_items.append([h, v])

3) объявить геттер checked_items:

def checked_items(self):
    return self._checked_items

4) напечатать checked_items в основном методе:

print(w.checked_items())

Но я предлагаю вам использовать QTableView() , а не QTableWidget(). QTableWidget() основан на элементах, QTableView() основан на модели.

Конечно, сначала это кажется более сложным, но позже, когда вы поймете, как использовать виджеты на основе моделей, вам это понравится!

Что вам нужно сделать, так это реализовать пользовательскую CheckedItemsModel, которая расширяет QAbstractItemModel. Посмотрите документацию, вы найдете много примеров.

person akushyn    schedule 01.04.2019

Я сделал это за тебя, тебе повезло)))

Главное окно.

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

Реализация модели:

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

И класс View (автоматически преобразованный файл .ui в .py) из 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"))

Как выглядит программа при выполнении

person akushyn    schedule 02.04.2019