I have a subclassed QAbstractTableModel
with a insert/deleate rows method
in the main window I have a methods insert_data
thats insert a string when the cell is currently selected
(I turned on singe selection)
Here is the behavior that I want to change:
when I insert a value in a cell with the setData
method of the subclassed QAbstractTableModel
or with insert_data
and deleate that row --->the row above gets selected (the row changes its color to grey ),
so the method automatically inserts the string
the conclusion is that the add/del methods change the added/deleated rows to being selected when executed
What ive tryed:
add/del rows methods are connected with two pushbuttons
self.addrow_button.clicked.connect(
lambda: self.datamodel.insertRows(-1, 1))
self.deleaterow_button.clicked.connect(
lambda: self.datamodel.removeRows(-1, 1))
so I connectet them to selectionModel().clearSelection())
to clear the selection of that row when a row gets added/deleated
self.addrow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
self.deleaterow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
but this only remove the grey color of the cell---> the cell is still selected, behavior continues
is there a way to diseable that the above/below row is beeing selected when the adding/deleating row method gets executed ?
code example
"""
Testing Template for throw away experiment
"""
import sys
import os
import re
from PyQt5 import QtWidgets as qtw
from PyQt5 import QtCore as qtc
from PyQt5 import QtGui as qtg
class DataModel(qtc.QAbstractTableModel):
def __init__(self, input_data=None):
super().__init__()
self.input_data = input_data or [[None], [None], [None], [None], [None]]
def data(self, index, role):
if role == qtc.Qt.DisplayRole:
try:
text = self.input_data[index.row()][index.column()]
# self.scaledatachanged_signal.emit() dont need it
except IndexError:
text = None
return text
def rowCount(self, index=qtc.QModelIndex()):
return 0 if index.isValid() else len(self.input_data)
def columnCount(self, index):
return len(self.input_data[0])
def headerData(self, section, orientation, role):
if role == qtc.Qt.DisplayRole:
if orientation == qtc.Qt.Vertical:
return "row " + str(section + 1)
def flags(self, index):
return qtc.Qt.ItemIsEditable | qtc.Qt.ItemIsSelectable | qtc.Qt.ItemIsEnabled
def setData(self, index, value, role=qtc.Qt.EditRole):
if role == qtc.Qt.EditRole: # The data in a form suitable for editing in an editor. returns string
try:
row = index.row()
column = index.column()
# filter floats and digits and comma stuff
pattern = '^[\d]+(?:[,.][\d]+)?$' # execepts "," and "."
if re.fullmatch(pattern, value, flags=0):
pattern = '^.*[,].*$'
if re.fullmatch(pattern, value, flags=0):
value = value.replace(',', '.')
self.input_data[row][column] = float(value)
print(type(value))
else:
self.input_data[row][column] = float(value) # float
print(type(value))
else:
pass
return True
except ValueError:
return False
def insertRows(self, position, rows, parent=qtc.QModelIndex()):
position = (position + self.rowCount()) if position < 0 else position
start = position
end = position + rows - 1
if end <= 8:
self.beginInsertRows(parent, start, end)
self.input_data.append([None])
self.endInsertRows()
return True
else:
return False
def removeRows(self, position, rows, parent=qtc.QModelIndex()):
position = (position + self.rowCount()) if position < 0 else position
start = position
end = position + rows - 1
if end >= 1:
self.beginRemoveRows(parent, start, end)
del self.input_data[start:end + 1]
self.endRemoveRows()
return True
else:
return False
class MainWindow(qtw.QWidget):
def __init__(self):
super().__init__()
self.mytable_view = qtw.QTableView()
self.mytable_view.setSelectionMode(qtw.QAbstractItemView.SingleSelection)
self.datamodel = DataModel()
self.mytable_view.setModel(self.datamodel)
# widget
self.addrow_button = qtw.QPushButton("add row")
self.deleaterow_button = qtw.QPushButton("deleate row")
# set the layout
layout = qtw.QVBoxLayout()
layout.addWidget(self.mytable_view)
layout.addWidget(self.addrow_button)
layout.addWidget(self.deleaterow_button)
self.setLayout(layout)
# -------------------------------- #
self.addrow_button.clicked.connect(
lambda: self.datamodel.insertRows(-1, 1))
self.deleaterow_button.clicked.connect(
lambda: self.datamodel.removeRows(-1, 1))
self.mytable_view.selectionModel().selectionChanged.connect(self.insert_data)
self.addrow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
self.deleaterow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
def insert_data(self):
x = self.mytable_view.selectionModel().currentIndex().row()
y = self.mytable_view.selectionModel().currentIndex().column()
self.datamodel.input_data[x][y] = "insert this string if cell is selected"
self.datamodel.layoutChanged.emit()
self.mytable_view.selectionModel().clearSelection()
if __name__ == '__main__':
app = qtw.QApplication(sys.argv)
main = MainWindow()
main.show()
sys.exit(app.exec_())
Whenever an item that is the current index is removed, the previous one is always automatically selected. Note that current index could not match the item selection: if you select an index and then clear the selection, that index will still be the current index.
The most simple solution is to set the current index to an invalid one btyusing a new instance of QModelIndex
(which is an invalid index) and before deleting the row.
# ...
self.deleaterow_button.clicked.connect(self.delete_row)
# ...
def delete_row(self):
self.mytable_view.setCurrentIndex(qtc.QModelIndex())
self.datamodel.removeRows(-1, 1)