2016-03-01 72 views
1

我正在寫一個QGIS插件使用Qt和python(以及pyqt)。QTableWidgetItem返回項目類型(pyqt)

在QtDesigner中,我有一個QTableWidget對象,如果有辦法獲得列項類型,我真的很掙扎。

例如,如下表所示:

enter image description here

我輸入用戶可以編輯一些缺省參數。此外,用戶可以添加具有其他值的其他行。我想知道如果我可以得到強制列數據類型輸入(例如float,int,string),並獲取我可以在Python代碼中使用的列表(或任何其他python對象)的此信息。

我沒有在Qt API中找到有用的東西。

你知道是否有辦法做到這一點?

編輯

得益於@rbaleksandar答案我做了一個步驟。

的一段代碼如下:

l = [] 
for i in range(self.tableWidget.columnCount()): 
    itm = self.tableWidget.item(0,i) 
    l.append(itm.type()) 

但是,即使在填充有一些數量的,用的QVariant 結果列表的表的第一行翻譯值由零的:

l = [0, 0, 0, 0, 0, 0, 0, 0, 0] 

我發現了與數字(2爲中等,6爲雙和10絃樂)相關聯的類型的QVariant所以預計l填充有這些數字,所以:

l = [2, 6, 6, 6, 6, 6, 6, 6, 6] 

我錯過了什麼嗎?

再次感謝

+1

你可以提供概括您的問題最小工作示例,這樣其他人(包括我自己)不必鍵入整個應用程序,而是與您的代碼工作? – rbaleksandar

+0

你想限制用戶可以輸入到單元格中的內容嗎?例如,只允許他們輸入整數和浮點數? –

+0

@Brendan Abel,如果有可能的話。 – matteo

回答

1

細看在構造函數和更精確的type論點:

QTableWidgetItem::QTableWidgetItem(int type = Type) 
QTableWidgetItem::QTableWidgetItem(const QString & text, int type = Type) 
QTableWidgetItem::QTableWidgetItem(const QIcon & icon, const QString & text, int type = Type) 

另外看看QTableWidgetItem::UserType(SO張貼here例如)

+0

感謝您的答案。無論如何,我無法獲得QVariant tyoe數字列表,請參閱編輯 – matteo

0

type參數QTableWidgetItem構造函數只是一種方式,用於區分某些項目,它不會使Qt顯示任何不同的數據或做類型轉換或類似的東西。例如,您可以選擇使用type=1001代替int單元格,使用type=1002代替float單元格,但您仍然必須自行從int/float <-> string進行轉換。

可以使用data()方法和自定義用戶角色(或只是繼承QTableWidgetItem和存儲額外的數據作爲一個屬性)存儲在一個QTableWidgetItem幾乎任何數據。但無論您存儲在該物品上的任何額外數據如何,該物品都需要向用戶顯示某種東西。您需要在display role上設置字符串數據(這是setText()的功能),或者使用QItemDelegate手動在每個項目單元上繪製某些內容。

你想要做的是設置項目int/float數據,但它們顯示的字符串表示,並且還允許用戶編輯數據是什麼。

這通常是一個QItemDelegate完成。這是一種可以完成的方式。

MY_DATA_ROLE = QtCore.Qt.UserRole + 1 
INT_TYPE = QtGui.QTableWidgetItem.UserType + 1 
FLOAT_TYPE = QtGui.QTableWidgetItem.UserType + 2 


class MyFloatIntDelegate(QtGui.QItemDelegate): 

    def __init__(self, parent, table): 
     super(MyFloatIntDelegate, self).__init__(parent) 
     self.table = table 

    def paint(self, painter, option, index): 
     item = self.table.itemFromIndex(index) 
     # This ensures the table is always displaying 
     # the int/float value stored in the custom data role. 
     if item and item.text() != str(item.data(MY_DATA_ROLE)): 
      item.setText(str(item.data(MY_DATA_ROLE))) 
     super(MyFloatIntDelegate, self).paint(painter, option, index) 

    def createEditor(self, parent, option, index): 
     editor = None 
     item = self.table.itemFromIndex(index) 
     if item: 
      # Is this an int item? 
      if item.type() == INT_TYPE: 
       editor = QtGui.QSpinBox(parent) 
       # Set the min/max as appropriate 
       editor.setRange(0, 100) 
      # or a float item? 
      elif item.type() == FLOAT_TYPE: 
       editor = QtGui.QDoubleSpinBox(parent) 
       # Set the min/max as appropriate 
       editor.setRange(0, 100) 
     return editor 

    def setEditorData(self, editor, index): 
     item = self.table.itemFromIndex(index) 
     if item:   
      if item.type() == INT_TYPE: 
       editor.setValue(item.data(MY_DATA_ROLE)) 
      elif item.type() == FLOAT_TYPE: 
       editor.setValue(item.data(MY_DATA_ROLE)) 

    def setModelData(self, editor, model, index): 
     item = self.table.itemFromIndex(index) 
     if item: 
      item.setData(MY_DATA_ROLE, editor.value()) 
      item.setText(str(editor.value())) 



class MyWidget(QtGui.QWidget): 

    def __init__(self): 
     ... 
     self.table = QtGui.QTableWiget(self) 
     self.delegate = MyIntFloatDelegate(self, self.table) 
     self.table.setItemDelegate(self.delegate) 

     # Creating Items 
     vals = [1, 3.5, 6.6, 1.0, 1.0] 
     row = 0 
     self.table.setColumnCount(len(vals)) 
     self.table.setRowCount(1) 
     for col, val in enumerate(vals): 
      item_type = INT_TYPE if isinstance(val, int) else FLOAT_TYPE 
      item = QtGui.QTableWidgetItem(item_type) 
      item.setData(MY_DATA_ROLE, val) 
      self.table.setItem(row, col, item) 

     # Getting data 
     vals = [] 
     for col in range(len(vals)): 
      item = self.table.item(row, col) 
      val = item.data(MY_DATA_ROLE) 
      vals.append(val) 

你也可以省略使用type值,並只爲每個不同類型的子類QTableWidgetItem並做isinstance()檢查在QItemDelegate而不是檢查type()值。在這種情況下,你也可以只存儲int/float值作爲text數據,而不是創建MY_DATA_ROLE自定義角色和文本數據,只要你想要的數據值轉換來回int/float值。當然,這通常不能用比int/float值更復雜的數據完成,因此使用自定義數據角色(或子類型QTableItemWidgets上的屬性)更靈活,可用於更多情況。

+0

哇!我會試一試!謝謝 – matteo

1

一個QTableWidget將自動提供了most common data types正確的編輯。但爲了使其正常工作,您必須使用EditRole將值添加到setData的表格控件項目中。

這裏有一個簡單的演示:

from PyQt4 import QtCore, QtGui 

class Window(QtGui.QWidget): 
    def __init__(self): 
     super(Window, self).__init__() 
     self.table = QtGui.QTableWidget(3, 6, self) 
     self.button = QtGui.QPushButton('Get Value', self) 
     self.edit = QtGui.QLineEdit(self) 
     self.edit.setReadOnly(True) 
     self.button.clicked.connect(self.handleButton) 
     layout = QtGui.QGridLayout(self) 
     layout.addWidget(self.table, 0, 0, 1, 2) 
     layout.addWidget(self.button, 1, 0, 1, 1) 
     layout.addWidget(self.edit, 1, 1, 1, 1) 
     # populate the table 
     data = ['text', 1, 0.25, True, 
       QtCore.QDate.currentDate(), 
       QtCore.QTime.currentTime()] 
     for row in range(3): 
      for column, value in enumerate(data): 
       item = QtGui.QTableWidgetItem() 
       item.setData(QtCore.Qt.EditRole, value) 
       self.table.setItem(row, column, item) 

    def handleButton(self): 
     try: 
      item = self.table.selectedItems()[0] 
      self.edit.setText('Value: %s, Type: %s' % 
       (item.text(), type(item.data(QtCore.Qt.EditRole)))) 
     except IndexError: 
      self.edit.clear() 

if __name__ == '__main__': 

    import sys 
    app = QtGui.QApplication(sys.argv) 
    window = Window() 
    window.setGeometry(500, 300, 700, 200) 
    window.show() 
    sys.exit(app.exec_()) 
+0

太棒了! - 我一直在四處尋找嘗試尋找從按鈕更新表項並獲得各種基於線程的悲傷的方法。這非常簡單。 – Tim