【问题标题】:PyQt5 QTableWidget: select column with right click, and show a delete entry in context menuPyQt5 QTableWidget:右键选择列,并在上下文菜单中显示删除条目
【发布时间】:2019-02-21 06:41:12
【问题描述】:

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

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

如何解决?

【问题讨论】:

标签: python pyqt5 qtablewidget


【解决方案1】:

要获得该列,您必须使用通过 itemAt() 方法获得的按下项。

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

然后创建 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_())

【讨论】:

    【解决方案2】:

    好的-根据您的解决方案(非常感谢)-我尝试了一个视图。主要是它做我想要的。如果我在表格主体中的单元格上单击鼠标右键,则应选择该单元格并应显示上下文菜单-好的-有效。如果行头或列头在鼠标光标下,则应选择整行(列) - 有效。

    但是选择仍然存在,不应该是这样!

    这是我的视图代码:

    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()]
    

    以及用于测试: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()
    

    【讨论】:

      猜你喜欢
      • 2019-07-06
      • 2016-03-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-03
      • 1970-01-01
      相关资源
      最近更新 更多