2013-07-12 31 views
5

Tôi đang cố gắng hiển thị hộp tổ hợp trong bảng của mình, để tôi có thể đặt chỉ mục đã chọn từ mô hình bảng, như với các ô khác trong bảng. Tôi đã ghép nối chúng lại với nhau từ các ví dụ khác nhưng vẫn không thể hiểu cách tương tác hoạt động để thiết lập chỉ mục đã chọn của QComboBox.PyQt - Cách đặt QComboBox ở chế độ xem bảng bằng cách sử dụng QItemDelegate

Đây là ví dụ đơn giản nhất mà tôi có thể đưa ra để minh họa sự cố. Nếu có ai có thể chứng minh làm thế nào để thiết lập chỉ mục tự động từ dữ liệu mô hình? Ngoài ra làm thế nào để sử dụng tín hiệu 'currentIndexChanged', vì điều này dường như cháy gần như liên tục bất cứ khi nào nó được sơn lại? Cảm ơn.

# The following tells SIP (the system that binds Qt's C++ to Python) 
# to return Python native types rather than QString and QVariant 
import sip 
sip.setapi('QString', 2) 
sip.setapi('QVariant', 2) 


from PyQt4 import QtCore, QtGui 

class TableModel(QtCore.QAbstractTableModel): 
    """ 
    A simple 5x4 table model to demonstrate the delegates 
    """ 
    def rowCount(self, parent=QtCore.QModelIndex()): return 5 
    def columnCount(self, parent=QtCore.QModelIndex()): return 4 

    def data(self, index, role=QtCore.Qt.DisplayRole): 
     if not index.isValid(): return None 
     if not role==QtCore.Qt.DisplayRole: return None 
     return "{0:02d}".format(index.row()) 


class ComboDelegate(QtGui.QItemDelegate): 
    """ 
    A delegate that places a fully functioning QComboBox in every 
    cell of the column to which it's applied 
    """ 
    def __init__(self, parent): 

     QtGui.QItemDelegate.__init__(self, parent) 

    def paint(self, painter, option, index): 

     self.combo = QtGui.QComboBox(self.parent()) 
     self.connect(self.combo, QtCore.SIGNAL("currentIndexChanged(int)"), self.parent().currentIndexChanged) 

     li = [] 
     li.append("Zero") 
     li.append("One") 
     li.append("Two") 
     li.append("Three") 
     li.append("Four") 
     li.append("Five") 

     self.combo.addItems(li) 

     if not self.parent().indexWidget(index): 
      self.parent().setIndexWidget(
       index, 
       self.combo 
      ) 

class TableView(QtGui.QTableView): 
    """ 
    A simple table to demonstrate the QComboBox delegate. 
    """ 
    def __init__(self, *args, **kwargs): 
     QtGui.QTableView.__init__(self, *args, **kwargs) 

     # Set the delegate for column 0 of our table 
     # self.setItemDelegateForColumn(0, ButtonDelegate(self)) 
     self.setItemDelegateForColumn(0, ComboDelegate(self)) 

    @QtCore.pyqtSlot() 
    def currentIndexChanged(self, ind): 
     print "Combo Index changed {0} {1} : {2}".format(ind, self.sender().currentIndex(), self.sender().currentText()) 

if __name__=="__main__": 
    from sys import argv, exit 

    class Widget(QtGui.QWidget): 
     """ 
     A simple test widget to contain and own the model and table. 
     """ 
     def __init__(self, parent=None): 
      QtGui.QWidget.__init__(self, parent) 

      l=QtGui.QVBoxLayout(self) 
      self._tm=TableModel(self) 
      self._tv=TableView(self) 
      self._tv.setModel(self._tm) 
      l.addWidget(self._tv) 

    a=QtGui.QApplication(argv) 
    w=Widget() 
    w.show() 
    w.raise_() 
    exit(a.exec_()) 

Trả lời

17

Bạn đang sử dụng phương pháp paint không chính xác. Nó sẽ được sử dụng khi bạn muốn thay đổi hiển thị hành vi của khung nhìn. Cũng tạo ra widget mới mỗi khi bạn muốn vẽ nó là rất tốn kém. Nhưng bạn muốn thay đổi hành vi chỉnh sửa, do đó bạn cần thay đổi toàn bộ logic của chương trình.

Xem fixed code. Dưới đây tôi sẽ tiếp tục thay đổi.

1. Trước hết, chúng tôi cần tạo cột đầu tiên có thể chỉnh sửa. Bạn có thể làm điều đó bằng cách reimplementing QAbstractItemModel::flags:

def flags(self, index): 
    if (index.column() == 0): 
     return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled 
    else: 
     return QtCore.Qt.ItemIsEnabled 

2. Theo mặc định, biên tập viên mục được tạo ra khi người dùng thực hiện một cú nhấp đúp chuột vào mục đó. Nếu bạn muốn hiển thị tất cả các comboboxes theo mặc định, bạn có thể sử dụng openPersistentEditor:

for row in range(0, self._tm.rowCount()): 
    self._tv.openPersistentEditor(self._tm.index(row, 0)) 

Lưu ý rằng bạn nên biên tập viên cũng mở cho các tế bào mới được tạo ra (nếu có).

3. Bây giờ, hãy quay lại đại diện của chúng tôi. Chúng tôi cần phải thực hiện createEditor phương pháp đó sẽ được tự động gọi bằng quan điểm khi một biên tập viên được yêu cầu cho một tế bào:

def createEditor(self, parent, option, index): 
    combo = QtGui.QComboBox(parent) 
    li = [] 
    li.append("Zero") 
    li.append("One") 
    li.append("Two") 
    li.append("Three") 
    li.append("Four") 
    li.append("Five") 
    combo.addItems(li) 
    self.connect(combo, QtCore.SIGNAL("currentIndexChanged(int)"), 
       self, QtCore.SLOT("currentIndexChanged()")) 
    return combo 

Lưu ý rằng connect dưới append bởi vì chúng ta cần phải tránh currentIndexChanged tín hiệu trên khởi tạo.

4. Thực hiện phương thức setEditorData sẽ được gọi theo chế độ xem khi dữ liệu mô hình đã được thay đổi. Ngoài ra, nó sẽ được gọi một lần khi một trình soạn thảo được khởi tạo.

def setEditorData(self, editor, index): 
    editor.blockSignals(True) 
    editor.setCurrentIndex(int(index.model().data(index))) 
    editor.blockSignals(False) 

Một lần nữa, chúng tôi muốn tránh các tín hiệu không do người dùng gây ra, vì vậy chúng tôi sử dụng blockSignals.

5. Trong khe chúng tôi chỉ đơn giản là phát ra commitData tín hiệu rằng sẽ gây ra quan điểm để gọi setModelData của đại biểu của chúng tôi:

@QtCore.pyqtSlot() 
def currentIndexChanged(self): 
    self.commitData.emit(self.sender()) 

6. Thực hiện setModelData phương pháp:

def setModelData(self, editor, model, index): 
    model.setData(index, editor.currentIndex()) 

7. Mô hình của bạn cần phải hỗ trợ thay đổi dữ liệu.Vì vậy, chúng ta nên thực hiện setData phương pháp mô hình:

def setData(self, index, value, role=QtCore.Qt.DisplayRole): 
    print "setData", index.row(), index.column(), value 
    # todo: remember the data 
+0

Tôi đã thêm một câu hỏi theo dõi về mô hình dữ liệu [ở đây] (http://stackoverflow.com/questions/17697352/pyqt-implement-a-qabstracttablemodel -for-display-in-qtableview) thay vì mở rộng câu hỏi này quá nhiều. – drexiya

+0

Ngoài ra một câu hỏi tiếp theo [tại đây] (http://stackoverflow.com/questions/17748546/pyqt-column-of-checkboxes-in-a-qtableview) về việc thêm một cột hộp kiểm vào chế độ xem. – drexiya

Các vấn đề liên quan