Python QTableView没有';t将预期的FocusIn/FocusOut事件发送到eventFilter

Python QTableView没有';t将预期的FocusIn/FocusOut事件发送到eventFilter,python,pyqt,qtablewidget,qtablewidgetitem,qevent,Python,Pyqt,Qtablewidget,Qtablewidgetitem,Qevent,我有一个QTableWidget,它带有需要大量水平空间的浮动或复杂条目。通过字符串格式以较少的位数显示值效果很好,但显然,在编辑和存储表中的条目时,我会降低精度 我通过使用eventFilter找到了QLineEdit小部件的解决方案:一个FocusIn事件将存储的值以全精度复制到QLineEdit文本字段,一个FocusOut事件或一个Return\u键存储更改的值,并用更少的位数覆盖文本字段 对QTableWidgets使用相同的方法会给我带来以下(可能相关的)问题: FocusIn和F

我有一个QTableWidget,它带有需要大量水平空间的浮动或复杂条目。通过字符串格式以较少的位数显示值效果很好,但显然,在编辑和存储表中的条目时,我会降低精度

我通过使用eventFilter找到了QLineEdit小部件的解决方案:一个
FocusIn
事件将存储的值以全精度复制到QLineEdit文本字段,一个
FocusOut
事件或一个
Return\u键
存储更改的值,并用更少的位数覆盖文本字段

对QTableWidgets使用相同的方法会给我带来以下(可能相关的)问题:

  • FocusIn和FocusOut事件未按预期生成:当我双击一个项目时,我会得到一个FocusOut事件,单击另一个项目会生成一个FocusIn事件
  • 我无法复制已编辑的选定项目的内容,我始终获取未编辑的值
  • 通过单击来选择项目不会产生事件
我已尝试评估QTableWidgetItem事件,但没有收到任何结果-是否需要在每个QTableWidgetItem上设置事件筛选器?如果是这样,我是否需要在每次调整表的大小时断开QTableWidgetItem eventFilters(在我的应用程序中经常这样做)?用QLineEdit小部件填充我的表有意义吗

附加的MWE不是很小,但我可以进一步缩小它

# -*- coding: utf-8 -*-
#from PyQt5.QWidgets import ( ...)
from PyQt4.QtGui import (QApplication, QWidget, QTableWidget, QTableWidgetItem, 
                         QLabel, QVBoxLayout)
import PyQt4.QtCore as QtCore
from PyQt4.QtCore import QEvent
from numpy.random import randn

class EventTable (QWidget):
    def __init__(self, parent = None):
        super(EventTable, self).__init__(parent)
        self.myTable = QTableWidget(self)
        self.myTable.installEventFilter(self) # route all events to self.eventFilter()

        myQVBoxLayout = QVBoxLayout()
        myQVBoxLayout.addWidget(self.myTable)
        self.setLayout(myQVBoxLayout)

        self.rows = 3; self.columns = 4 # table + data dimensions
        self.data = randn(self.rows, self.columns) # initial data
        self._update_table() # create table 

    def eventFilter(self, source, event):
        if isinstance(source, (QTableWidget, QTableWidgetItem)):
#            print(type(source).__name__, event.type()) #too much noise
            if event.type() == QEvent.FocusIn:  # 8: enter widget
                print(type(source).__name__, "focus in")
                self.item_edited = False
                self._update_table_item() # focus: display data with full precision
                return True # event processing stops here

            elif event.type() == QEvent.KeyPress:
                print(type(source).__name__, "key pressed")
                self.item_edited = True # table item has been changed
                key = event.key() # key press: 6, key release: 7
                if key in {QtCore.Qt.Key_Return, QtCore.Qt.Key_Enter}: # store entry
                    self._store_item() # store edited data in self.data
                    return True
                elif key == QtCore.Qt.Key_Escape: # revert changes
                    self.item_edited = False
                    self._update_table() # update table from self.data
                    return True

            elif event.type() == QEvent.FocusOut: # 9: leave widget
                print(type(source).__name__, "focus out")
                self._store_item() 
                self._update_table_item() # no focus: use reduced precision
                return True

        return super(EventTable, self).eventFilter(source, event)

    def _update_table(self):
        """(Re-)Create the table with rounded data from self.data """
        self.myTable.setRowCount(self.rows)
        self.myTable.setColumnCount(self.columns)
        for col in range(self.columns):
            for row in range(self.rows):
                self.myTable.setItem(row,col, 
                        QTableWidgetItem(str("{:.3g}".format(self.data[row][col]))))
        self.myTable.resizeColumnsToContents()
        self.myTable.resizeRowsToContents()

    def _update_table_item(self, source = None):
        """ Re-)Create the current table item with full or reduced precision. """
        row = self.myTable.currentRow()
        col = self.myTable.currentColumn()
        item = self.myTable.item(row, col)
        if item: # is something selected?
            if not item.isSelected(): # no focus, show self.data[row][col] with red. precision
                print("\n_update_item (not selected):", row, col)
                item.setText(str("{:.3g}".format(self.data[row][col])))
            else: #  in focus, show self.data[row][col] with full precision
                item.setText(str(self.data[row][col]))
                print("\n_update_item (selected):", row, col)

    def _store_item(self):
        """ Store the content of item in self.data """
        if self.item_edited:
            row = self.myTable.currentRow()
            col = self.myTable.currentColumn()
            item_txt = self.myTable.item(row, col).text()
            self.data[row][col] = float(str(item_txt))
            print("\n_store_entry - current item/data:", item_txt, self.data[row][col])



if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    mainw = EventTable()
    app.setActiveWindow(mainw) 
    mainw.show()
    sys.exit(app.exec_())

你这样做完全是错误的。现有的API已经满足了这类用例的需求,因此有几种解决方案比您目前拥有的解决方案简单得多

可能最简单的方法就是使用一个并重新实现它的方法。这将允许您在表中存储完整的值,但格式不同,以便显示。编辑时,将始终显示完整值(作为字符串):



注:用它来解决这个问题很有诱惑力。但是,
QTableWidgetItem
QStandardItem
都将
DisplayRole
EditRole
视为一个角色,这意味着需要重新实现它们的
数据
设置数据
方法来获得所需的功能。

一个真正优雅的解决方案!我想,我得咬一下。。。
from PyQt4.QtGui import (QApplication, QWidget, QTableWidget, QTableWidgetItem,
                         QLabel, QVBoxLayout,QStyledItemDelegate)
import PyQt4.QtCore as QtCore
from PyQt4.QtCore import QEvent
from numpy.random import randn

class ItemDelegate(QStyledItemDelegate):
    def displayText(self, text, locale):
        return "{:.3g}".format(float(text))

class EventTable (QWidget):
    def __init__(self, parent = None):
        super(EventTable, self).__init__(parent)
        self.myTable = QTableWidget(self)
        self.myTable.setItemDelegate(ItemDelegate(self))
        myQVBoxLayout = QVBoxLayout()
        myQVBoxLayout.addWidget(self.myTable)
        self.setLayout(myQVBoxLayout)
        self.rows = 3; self.columns = 4 # table + data dimensions
        self.data = randn(self.rows, self.columns) # initial data
        self._update_table() # create table

    def _update_table(self):
        self.myTable.setRowCount(self.rows)
        self.myTable.setColumnCount(self.columns)
        for col in range(self.columns):
            for row in range(self.rows):
                item = QTableWidgetItem(str(self.data[row][col]))
                self.myTable.setItem(row, col, item)
        self.myTable.resizeColumnsToContents()
        self.myTable.resizeRowsToContents()

if __name__ == "__main__":
    import sys

    app = QApplication(sys.argv)
    mainw = EventTable()
    app.setActiveWindow(mainw)
    mainw.show()
    sys.exit(app.exec_())