Хорошо - на основании вашего решения (большое спасибо) - я попробовал посмотреть.Главным образом это делает то, что я хочу.Если я щелкну правой кнопкой мыши на ячейке в теле таблицы, ячейка должна быть выбрана, и должно появиться контекстное меню - все в порядке.Если заголовок строки или столбца находится под курсором мыши, следует выбрать всю строку (столбец) - работает.
НО выбор остается, и это не должно быть!
Вот мой коддля просмотра:
import logging
import sys
from PyQt5.QtWidgets import \
QApplication, QWidget, QVBoxLayout, QMenu, \
QTableWidget, QTableWidgetItem, QTableWidgetSelectionRange
from PyQt5.QtCore import \
QPoint, Qt
class View(QWidget):
def __init__(self, app, parent=None):
super().__init__(parent)
self.app = app
# gui elements
self.layout = None
self.tbl = None
self.tbl_selection = None
self.tbl_item = None
self.tbl_item_pos = [-1, -1]
def _setup_layout(self):
logging.debug("<View._setup_layout>")
self.setMinimumHeight(600)
self.setMinimumWidth(800)
self.layout = QVBoxLayout()
self.setLayout(self.layout)
def _setup_table(self):
logging.debug("<View._setup_table()>")
if self.app.data:
data = self.app.data
rows, cols = len(data), len(data[0])
self.tbl = tbl = QTableWidget(rows, cols)
tbl.setHorizontalHeaderLabels(data.pop(0))
for r, ds in enumerate(data):
for c, f in enumerate(ds):
item = QTableWidgetItem(f)
tbl.setItem(r, c, item)
def _setup_widgets(self):
logging.debug("<View._setup_widgets()>")
if self.app is not None:
self._setup_table()
else:
self.tbl = QTableWidget()
tbl = self.tbl
tbl.verticalHeader().setContextMenuPolicy(
Qt.CustomContextMenu)
tbl.horizontalHeader().setContextMenuPolicy(
Qt.CustomContextMenu)
self.layout.addWidget(self.tbl)
def _connect_evt_with_handler(self):
logging.debug("<View._connect_evt_with_handler()>")
tbl = self.tbl
tbl.setContextMenuPolicy(Qt.CustomContextMenu)
tbl.customContextMenuRequested.connect(self.on_tbl_rightclick)
# event for click on row heads
tbl.verticalHeader().customContextMenuRequested.connect(
self.on_tbl_rhead_rightclick)
# event for click on col heads
tbl.horizontalHeader().customContextMenuRequested.connect(
self.on_tbl_chead_rightclick)
# protected
def _get_clicked_item(self, qpoint: QPoint) -> bool:
logging.debug("<View._get_clicked_item(qpoint={})>".format(qpoint))
self.tbl_item = item = self.tbl.itemAt(qpoint)
self.tbl_item_pos = [item.row(), item.column()]
return self.tbl_item is not None
def _set_selection(self):
logging.debug("<View._set_selection()>")
r, c = self.tbl_item_pos
logging.debug("... row={}, col={}".format(r, c))
if r >= 0 and c >= 0:
self.tbl_selection = QTableWidgetSelectionRange(
r, c, r, c)
elif c < 0:
# row head
self.tbl_selection = QTableWidgetSelectionRange(
r, 0, r, self.tbl.columnCount() - 1)
elif r < 0:
# col head
self.tbl_selection = QTableWidgetSelectionRange(
0, c, self.tbl.rowCount() - 1, c)
self.tbl.setRangeSelected(self.tbl_selection, True)
def _build_ctx_mnu(self, qpoint: QPoint):
logging.debug("<View._build_ctx_mnu(qpoint={})>".format(qpoint))
r, c = self.tbl_item_pos
logging.debug("... row={}, col={}".format(r, c))
# build menu
action_del_col = None
action_del_row = None
menu = QMenu()
if c < 0:
# row head
action_del_row = menu.addAction("Delete row")
elif r < 0:
# col head
action_del_col = menu.addAction("Delete column")
else:
# table body
action_del_col = menu.addAction("Delete column")
action_del_row = menu.addAction("Delete row")
action = menu.exec_(self.tbl.viewport().mapToGlobal(qpoint))
if action is not None and action == action_del_col:
logging.debug("... action: {}".format(action_del_col.text()))
self.tbl.removeColumn(c)
elif action is not None and action == action_del_row:
logging.debug("... action: {}".format(action_del_row.text()))
self.tbl.removeRow(r)
# UI
def setup(self):
logging.debug("<View.setup()>")
self._setup_layout()
self._setup_widgets()
self._connect_evt_with_handler()
# events
def on_tbl_rightclick(self, qpoint: QPoint):
logging.debug("<View.on_tbl_rightclick(qpoint={})>".format(qpoint))
if self._get_clicked_item(qpoint):
self._set_selection()
self._build_ctx_mnu(qpoint)
def on_tbl_rhead_rightclick(self, qpoint: QPoint):
logging.debug(
"<View.on_tbl_rhead_rightclick(qpoint={})>".format(qpoint))
if self._get_clicked_item(qpoint):
self.tbl_item_pos[1] = -1
self._set_selection()
self._build_ctx_mnu(qpoint)
def on_tbl_chead_rightclick(self, qpoint: QPoint):
logging.debug(
"<View.on_tbl_chead_rightclick(qpoint={})>".format(qpoint))
if self._get_clicked_item(qpoint):
self.tbl_item_pos[0] = -1
self._set_selection()
self._build_ctx_mnu(qpoint)
А вот некоторая дата - еще раз:
data = [f.strip().split(",") for f in """\
id,first_name,last_name,email,gender,ip_address
1,Hillard,Tasseler,htasseler0@google.com.br,Male,104.153.237.243
2,Tyrus,Oley,toley1@ft.com,Male,163.73.24.45
3,Kora,Covil,kcovil2@privacy.gov.au,Female,158.44.166.87
4,Phineas,McEntee,pmcentee3@rambler.ru,Male,71.82.246.45
5,Dottie,Spraging,dspraging4@berkeley.edu,Female,226.138.241.22
6,Andria,Ivatts,aivatts5@about.com,Female,57.5.76.78
7,Missy,Featherstone,mfeatherstone6@unblog.fr,Female,9.56.215.203
8,Anstice,Sargant,asargant7@about.me,Female,36.115.185.109
9,Teresita,Trounce,ttrounce8@myspace.com,Female,240.228.133.166
10,Sib,Thomke,sthomke9@ibm.com,Female,129.191.2.7
11,Amery,Dallander,adallandera@elpais.com,Male,4.115.194.100
12,Rourke,Rowswell,rrowswellb@bloomberg.com,Male,48.111.190.66
13,Cloe,Benns,cbennsc@slideshare.net,Female,142.48.24.44
14,Enos,Fery,eferyd@pen.io,Male,59.19.200.235
15,Russell,Capelen,rcapelene@fc2.com,Male,38.205.20.141""".split()]
А для тестирования: объект приложения и основная функция:
class App:
def __init__(self, data=()):
self.view = View(app=self)
self.data = []
if isinstance(data, (list, tuple)) and len(data) > 0:
self.set(data)
def set(self, data):
logging.debug("<App.set(data)>")
self.data = data
def setup(self):
logging.debug("<App.setup()>")
self.view.setup()
def show(self):
logging.debug("<App.show()>")
self.view.show()
def main():
logging.basicConfig(level=logging.DEBUG)
qapp = QApplication(sys.argv)
app = App(data=data)
app.setup()
app.show()
sys.exit(qapp.exec_())
main()