PyQt5 QTableWidget:右键单击选择列,并在上下文菜单中显示删除条目

问题描述 投票:0回答:2

我想在右键单击中选择一列,然后上下文菜单必须提供删除所选列的删除条目。

使用transportet QPoint arg,鼠标位置被发送到插槽。但我需要点击列。

怎么解决?

python pyqt5 qtablewidget
2个回答
1
投票

要获取列,必须使用使用itemAt()方法获得的按下项。

通过传递QTableWidgetSelectionRange(使用列作为数据),使用setRangeSelected方法选择它。

然后创建QMenu和exec_()方法,传递信号的位置,但必须使用mapToGlobal从视口转换为全局。

然后使用removeColumn()方法删除该列。

from PyQt5 import QtCore, QtGui, QtWidgets

class Widget(QtWidgets.QWidget):
    def __init__(self, parent=None):
        super(Widget, self).__init__(parent)

        self.table_widget = QtWidgets.QTableWidget(20, 10)

        for i in range(self.table_widget.rowCount()):
            for j in range(self.table_widget.columnCount()):
                it = QtWidgets.QTableWidgetItem("{}-{}".format(i, j))
                self.table_widget.setItem(i, j, it)

        vlay = QtWidgets.QVBoxLayout(self)
        vlay.addWidget(self.table_widget)

        self.table_widget.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
        self.table_widget.customContextMenuRequested.connect(self.on_customContextMenuRequested)

    @QtCore.pyqtSlot(QtCore.QPoint)
    def on_customContextMenuRequested(self, pos):
        it = self.table_widget.itemAt(pos)
        if it is None: return
        c = it.column()
        item_range = QtWidgets.QTableWidgetSelectionRange(0, c, self.table_widget.rowCount()-1 , c)
        self.table_widget.setRangeSelected(item_range, True)

        menu = QtWidgets.QMenu()
        delete_column_action = menu.addAction("Delete column")
        action = menu.exec_(self.table_widget.viewport().mapToGlobal(pos))
        if action == delete_column_action:
            self.table_widget.removeColumn(c)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

1
投票

好的 - 基于你的解决方案(非常感谢) - 我尝试了一个视图。大多数情况下,它做我想要的。如果我在表格主体的单元格上单击鼠标右键,则应选择单元格并显示上下文菜单 - 确定 - 有效。如果行或列头位于鼠标光标下,则应选择整行(列) - 工作。

但选择仍然存在,而且不应该如此!

这是我的视图代码:

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,[email protected],Male,104.153.237.243
    2,Tyrus,Oley,[email protected],Male,163.73.24.45
    3,Kora,Covil,[email protected],Female,158.44.166.87
    4,Phineas,McEntee,[email protected],Male,71.82.246.45
    5,Dottie,Spraging,[email protected],Female,226.138.241.22
    6,Andria,Ivatts,[email protected],Female,57.5.76.78
    7,Missy,Featherstone,[email protected],Female,9.56.215.203
    8,Anstice,Sargant,[email protected],Female,36.115.185.109
    9,Teresita,Trounce,[email protected],Female,240.228.133.166
    10,Sib,Thomke,[email protected],Female,129.191.2.7
    11,Amery,Dallander,[email protected],Male,4.115.194.100
    12,Rourke,Rowswell,[email protected],Male,48.111.190.66
    13,Cloe,Benns,[email protected],Female,142.48.24.44
    14,Enos,Fery,[email protected],Male,59.19.200.235
    15,Russell,Capelen,[email protected],Male,38.205.20.141""".split()]

并且用于测试:app对象和主要功能:

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()
© www.soinside.com 2019 - 2024. All rights reserved.