Ввод данных в QTableView

Пытаюсь сделать программу, куда можно будет записывать игроков, и их баллы. Желательно, что бы данные можно было записывать подряд, т.е. когда ввел одно имя, нужно ввести следующее и т.д. Также нужно что бы была возможность переписывания данных по определенной колонке и строке, т.е в определенной клетке.

Вопрос: как это здесь реализовать?

Ввод: Player 1 | 25 ; Player 2 | 18

Вывод:


| Player 1 | 25 |

| Player 2 | 18 |


Counter.py

import sys
from random import randint
from PyQt5 import QtWidgets, QtCore, QtGui

class CustomTableView(QtWidgets.QTableView):
    def __init__(self, parent=None):
        super(CustomTableView, self).__init__(parent)
        self.setSortingEnabled(True)

    def KeyPressEvent(self, event: QtGui.QKeyEvent):
        if event.key() == QtCore.Qt.Key_Enter:
            print("Key_Enter ")
        elif event.key() == QtCore.Qt.Key_Return:
            print("Key_Return ")


class NumberSortModel(QtCore.QSortFilterProxyModel):

    def lessThan(self, left_index: "QModelIndex",
                 right_index: "QModelIndex") -> bool:

        left_var: str = left_index.data(QtCore.Qt.EditRole)
        right_var: str = right_index.data(QtCore.Qt.EditRole)

        try:
            return float(left_var) < float(right_var)
        except (ValueError, TypeError):
            pass

        try:
            return left_var < right_var
        except TypeError: 
            return True


class Counter(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Counter, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Window)
        QtWidgets.QMainWindow.__init__(self)

        font = QtGui.QFont("Formula1", 10, QtGui.QFont.Bold)
        self.setFont(font)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        grid_layout = QtWidgets.QGridLayout()
        central_widget.setLayout(grid_layout)

        self.model = QtGui.QStandardItemModel(self)
        self.model.setHorizontalHeaderLabels(["Name" , "Points"])

        self.proxy = NumberSortModel()
        self.proxy.setSourceModel(self.model)

        self.table = CustomTableView(self)
        self.table.setModel(self.proxy)
        for i in range(10):
            self.model.appendRow([QtGui.QStandardItem(f'Name{randint(10, 99)}'), 
                                  QtGui.QStandardItem(str(randint(1, 100)))])

        sort_button = QtWidgets.QPushButton("Sort")

        qlineedit_name = QtWidgets.QLineEdit()
        qlineedit_name.resize(24, 80)
        qlineedit_name.setText("Name")
        qlineedit_name.selectAll()
        qlineedit_points = QtWidgets.QLineEdit()
        qlineedit_points.resize(24, 80)
        qlineedit_points.setText("Points")
        qlineedit_points.selectAll()

        horisontal_layout = QtWidgets.QHBoxLayout()
        horisontal_layout.addStretch(1)
        horisontal_layout.addWidget(qlineedit_name)
        horisontal_layout.addStretch(1)
        horisontal_layout.addWidget(qlineedit_points)
        horisontal_layout.addStretch(1)
        horisontal_layout.addWidget(sort_button)
        horisontal_layout.addStretch(1)
        horisontal_layout.setAlignment(QtCore.Qt.AlignRight)

        grid_layout.addLayout(horisontal_layout, 0, 0)
        grid_layout.addWidget(self.table, 1, 0)


if __name__ == "__main__":
    application = QtWidgets.QApplication([])
    window = Counter()
    window.setWindowTitle("Counter")
    window.setMinimumSize(480, 380)
    window.show()
    sys.exit(application.exec_())

Ответы (2 шт):

Автор решения: Alexander Chernin

Чтобы среагировать на нажатие кнопки ввода, у QLineEdit имеется такой сигнал returnPressed:

def __init__():
    #...

    # лучше добавить self.qlineedit_name, чтобы можно было обращать к объекту за данными
    self.qlineedit_name = QtWidgets.QLineEdit()
    self.qlineedit_name.returnPressed.connect(self._nameEntered)

def _nameEntered(self):
    # получили данные из QLineEdit
    name = self.qlineedit_name.text()

    # Дальше решаем, что делать, либо изменить значение в столбце,
    # выделенной строки, либо добавить новую строку, либо что-то еще

Предположим, что вам надо изменить значения только в первой (их может быть много) выделенной строке. Из таблицы получаем модель выбора, из нее выделенные строки (их индексы), при помощи которых обновляем данные в модели данных таблицы при помощи метода setData:

s_model = self.table->selectionModel();
rows = s_model.selectedRows(0) # 0 - это номер колонки

if len(rows) > 0:
    self.model.setData(rows[0], name, Qt.DisplayRole)

Если таблица пустая, или выделенных строк нет, что подразумевает добавление новой строки, то делается это так:

if len(rows) > 0:
    #...
else: # Таблица пустая, или нет выделенных строк
    item1 = QStandartItem()
    item1.setText(self.qlineedit_name.text())

    item2 = QStandartItem()
    item2.setText(self.qlineedit_points.text())

    items = [item1, item2]
    self.model.appendRow(items)
→ Ссылка
Автор решения: S. Nick

я добавил для вас метод on_update_button , которые сработает по нажатию кнопки Update

import sys
from random import randint
from PyQt5 import QtWidgets, QtCore, QtGui

class CustomTableView(QtWidgets.QTableView):
    def __init__(self, parent=None):
        super(CustomTableView, self).__init__(parent)
        self.setSortingEnabled(True)

    def KeyPressEvent(self, event: QtGui.QKeyEvent):
        if event.key() == QtCore.Qt.Key_Enter:
            print("Key_Enter ")
        elif event.key() == QtCore.Qt.Key_Return:
            print("Key_Return ")


class NumberSortModel(QtCore.QSortFilterProxyModel):

    def lessThan(self, left_index: "QModelIndex",
                 right_index: "QModelIndex") -> bool:

        left_var: str = left_index.data(QtCore.Qt.EditRole)
        right_var: str = right_index.data(QtCore.Qt.EditRole)

        try:
            return float(left_var) < float(right_var)
        except (ValueError, TypeError):
            pass

        try:
            return left_var < right_var
        except TypeError: 
            return True


class Counter(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(Counter, self).__init__(parent)
        self.setWindowFlags(QtCore.Qt.Window)
        QtWidgets.QMainWindow.__init__(self)

        font = QtGui.QFont("Formula1", 10, QtGui.QFont.Bold)
        self.setFont(font)

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)

        grid_layout = QtWidgets.QGridLayout()
        central_widget.setLayout(grid_layout)

        self.model = QtGui.QStandardItemModel(self)
        self.model.setHorizontalHeaderLabels(["Name" , "Points"])

        self.proxy = NumberSortModel()
        self.proxy.setSourceModel(self.model)

        self.table = CustomTableView(self)
        self.table.setModel(self.proxy)
        for i in range(10):
            self.model.appendRow([QtGui.QStandardItem(f'Name{randint(10, 99)}'), 
                                  QtGui.QStandardItem(str(randint(1, 100)))])


        update_button = QtWidgets.QPushButton("Update")                           # +++
        update_button.clicked.connect(self.on_update_button)                      # +++
        sort_button = QtWidgets.QPushButton("Sort")

        self.qlineedit_name = QtWidgets.QLineEdit()
        self.qlineedit_name.resize(24, 80)
        self.qlineedit_name.setText("Name")
        self.qlineedit_name.selectAll()
        self.qlineedit_points = QtWidgets.QLineEdit()
        self.qlineedit_points.resize(24, 80)
        self.qlineedit_points.setText("Points")
        self.qlineedit_points.selectAll()

        horisontal_layout = QtWidgets.QHBoxLayout()
#        horisontal_layout.addStretch(1)
        horisontal_layout.addWidget(self.qlineedit_name, stretch=1)
#        horisontal_layout.addStretch(1)
        horisontal_layout.addWidget(self.qlineedit_points, stretch=1)
        horisontal_layout.addStretch(1)
        horisontal_layout.addWidget(update_button)                                 # +++
        horisontal_layout.addWidget(sort_button)
#        horisontal_layout.addStretch(1)
        horisontal_layout.setAlignment(QtCore.Qt.AlignRight)

        grid_layout.addLayout(horisontal_layout, 0, 0)
        grid_layout.addWidget(self.table, 1, 0)

# ++ vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
    def on_update_button(self):
        name = self.qlineedit_name.text().strip()
        point = self.qlineedit_points.text().strip() if self.qlineedit_points.text().strip() else '0'
        if not point.isdigit():
            msg = QtWidgets.QMessageBox.information(self, 'ВНИМАНИЕ', 'Заполните правильно поле ввода Points!')
            return

        if not name:
            msg = QtWidgets.QMessageBox.information(self, 'ВНИМАНИЕ', 'Заполните поле ввода Name!')
            return
        rows  = self.table.model().rowCount()
        add_record = True
        for row in range(rows):
            if name == self.proxy.data(self.proxy.index(row, 0)):
                #print(name)
                add_record = False
                row_edit = row
                break

        if add_record:       # add
            if self.table.selectedIndexes():
                #print(f'  {self.table.selectedIndexes()[-1].row()}')   
                row = self.table.selectedIndexes()[-1].row()
                # insertRow(int row, const QList<QStandardItem *> &items)
                self.model.insertRow(row+1, [QtGui.QStandardItem(name), 
                                      QtGui.QStandardItem(point)])                  

            else:
                #print(f' ничего не выбрано, добавляем в конец ')
                self.model.appendRow([QtGui.QStandardItem(name), 
                                      QtGui.QStandardItem(point)])            
        else:               # update  
            self.model.setData(self.model.index(row_edit, 1), point, QtCore.Qt.EditRole)
# +++ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        


if __name__ == "__main__":
    application = QtWidgets.QApplication([])
    window = Counter()
    window.setWindowTitle("Counter")
    window.setMinimumSize(480, 380)
    window.show()
    sys.exit(application.exec_())

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

→ Ссылка