当 QTableView 中的 adding/deleating 行时如何禁用 select 行行为
how to diseable select row behavior when adding/deleating a row in QTableView
我有一个带有 insert/deleate 行方法的子类 QAbstractTableModel
在主要部分 window 我有一个方法 insert_data
可以在当前选中单元格时插入一个字符串
(我打开了单选)
这是我想要更改的行为:
当我使用子类 QAbstractTableModel
的 setData
方法在单元格中插入一个值时
或者 insert_data
并删除该行 ---> 上面的行被选中(该行将其颜色更改为灰色),
所以该方法会自动插入字符串
结论是 add/del 方法在执行时将 added/deleated 行更改为被选中
我试过什么:
add/del 行方法与两个按钮连接
self.addrow_button.clicked.connect(
lambda: self.datamodel.insertRows(-1, 1))
self.deleaterow_button.clicked.connect(
lambda: self.datamodel.removeRows(-1, 1))
所以我将它们连接到 selectionModel().clearSelection())
以在某行获得 added/deleated
时清除该行的选择
self.addrow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
self.deleaterow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
但这只会删除单元格的灰色---> 单元格仍处于选中状态,行为继续
有没有办法在执行 adding/deleating 行方法时禁止选择 above/below 行?
代码示例
"""
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_())
每当删除 当前索引 的项目时,总是会自动 select 编辑前一个项目。请注意,当前索引无法匹配项目 selection:如果您 select 一个索引然后清除 selection,该索引仍将是当前索引。
最简单的解决方案是将当前索引设置为无效索引,方法是使用 QModelIndex
的新实例(这是一个无效索引)并在 之前 删除行。
# ...
self.deleaterow_button.clicked.connect(self.delete_row)
# ...
def delete_row(self):
self.mytable_view.setCurrentIndex(qtc.QModelIndex())
self.datamodel.removeRows(-1, 1)
我有一个带有 insert/deleate 行方法的子类 QAbstractTableModel
在主要部分 window 我有一个方法 insert_data
可以在当前选中单元格时插入一个字符串
(我打开了单选)
这是我想要更改的行为:
当我使用子类 QAbstractTableModel
的 setData
方法在单元格中插入一个值时
或者 insert_data
并删除该行 ---> 上面的行被选中(该行将其颜色更改为灰色),
所以该方法会自动插入字符串
结论是 add/del 方法在执行时将 added/deleated 行更改为被选中
我试过什么:
add/del 行方法与两个按钮连接
self.addrow_button.clicked.connect(
lambda: self.datamodel.insertRows(-1, 1))
self.deleaterow_button.clicked.connect(
lambda: self.datamodel.removeRows(-1, 1))
所以我将它们连接到 selectionModel().clearSelection())
以在某行获得 added/deleated
self.addrow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
self.deleaterow_button.clicked.connect(lambda: self.mytable_view.selectionModel().clearSelection())
但这只会删除单元格的灰色---> 单元格仍处于选中状态,行为继续
有没有办法在执行 adding/deleating 行方法时禁止选择 above/below 行?
代码示例
"""
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_())
每当删除 当前索引 的项目时,总是会自动 select 编辑前一个项目。请注意,当前索引无法匹配项目 selection:如果您 select 一个索引然后清除 selection,该索引仍将是当前索引。
最简单的解决方案是将当前索引设置为无效索引,方法是使用 QModelIndex
的新实例(这是一个无效索引)并在 之前 删除行。
# ...
self.deleaterow_button.clicked.connect(self.delete_row)
# ...
def delete_row(self):
self.mytable_view.setCurrentIndex(qtc.QModelIndex())
self.datamodel.removeRows(-1, 1)