2017-01-25 24 views
1

플로트 또는 복잡한 항목이 많은 QTableWidget에 가로 공간이 많이 필요합니다. 문자열 형식을 통해 자릿수를 줄인 값을 표시하는 것은 잘 작동하지만 테이블에 항목을 편집하고 저장할 때 정확도가 느슨합니다. FocusIn 이벤트 복사 QLineEdit의 텍스트 필드 전체 정밀도 저장된 값, FocusOut 이벤트 또는 Return_Key 저장 변경된 값 및 감소 된 수와 텍스트 필드를 겹쳐 :QTableView가 eventFilter에 예상 FocusIn/FocusOut 이벤트를 보내지 않습니다.

는 I는 eventFilter를 사용하여 QLineEdit 위젯에 대한 해결책을 발견 자리 수.

    예상대로
  • 하는 focusIn 및 대한 focusOut 이벤트가 생성되지 않습니다 : 내가 항목을 두 번 클릭하면, 내가 얻을 대한 focusOut QTableWidgets과 같은 방법을 사용

    나에게 다음과 같은 (아마도 관련) 문제를 제공합니다 이벤트에서 다른 항목을 클릭하면 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_()) 

답변

1

완전히 잘못된 방식으로 진행됩니다. 이러한 유스 케이스는 이미 기존 API에 의해 제공되므로 현재 사용중인 것보다 훨씬 간단한 몇 가지 솔루션을 사용할 수 있습니다.

아마 가장 간단한 방법은 QStyledItemDelegate을 사용하고 dispalyText 메서드를 다시 구현하는 것입니다. 이렇게하면 테이블에 전체 값을 저장할 수 있지만 표시를 위해 다르게 형식을 지정할 수 있습니다. 편집 할 때, 전체 값은 항상 (문자열로) 표시됩니다 :

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

NB를 : 그것은이 문제를 해결하기 위해 item roles를 사용하는 유혹입니다. 그러나 QTableWidgetItemQStandardItemDisplayRoleEditRole을 하나의 역할로 취급하므로 필요한 기능을 얻으려면 datasetData 메서드를 다시 구현해야합니다.

+0

진정한 우아한 솔루션! 나는 [delegate_classes] (http://doc.qt.io/qt-5/model-view-programming.html#delegate-classes)에 물어야 할 것 같아요 ... – Chipmuenk