2013-08-05 61 views
10

Bối cảnh: Tôi không thể tìm thấy ví dụ hoạt động đầy đủ của combobox bên trong QTableView. Vì vậy, tôi đã viết mã này dựa trên một số ví dụ khác contrived hơn ra khỏi đó. Vấn đề là, tuy nhiên, ví dụ này đòi hỏi bạn phải bấm đúp vào combobox trước khi nó được kích hoạt, sau đó bạn phải bấm một lần nữa để thả nó xuống. Nó không thân thiện với người dùng. Nếu tôi thực hiện mô hình không/mô hình xem bằng cách sử dụng QTableWidget, hộp tổ hợp sẽ giảm xuống trên nhấp chuột đầu tiên.PyQt - ví dụ làm việc đơn giản nhất của combobox bên trong QTableView

Câu hỏi: Ai đó có thể xem điều này và cho tôi biết cần phải làm gì để làm cho nó phản hồi giống như QTableWidget? Ngoài ra nếu có bất cứ điều gì mà tôi đang làm đó là không cần thiết, xin vui lòng chỉ ra rằng cũng có. Ví dụ, nó là hoàn toàn cần thiết để tham khảo các phong cách ứng dụng?

import sys 
from PyQt4 import QtGui, QtCore 

rows = "ABCD" 
choices = ['apple', 'orange', 'banana'] 

class Delegate(QtGui.QItemDelegate): 
    def __init__(self, owner, items): 
     super(Delegate, self).__init__(owner) 
     self.items = items 
    def createEditor(self, parent, option, index): 
     self.editor = QtGui.QComboBox(parent) 
     self.editor.addItems(self.items) 
     return self.editor 
    def paint(self, painter, option, index): 
     value = index.data(QtCore.Qt.DisplayRole).toString() 
     style = QtGui.QApplication.style() 
     opt = QtGui.QStyleOptionComboBox() 
     opt.text = str(value) 
     opt.rect = option.rect 
     style.drawComplexControl(QtGui.QStyle.CC_ComboBox, opt, painter) 
     QtGui.QItemDelegate.paint(self, painter, option, index) 
    def setEditorData(self, editor, index): 
     value = index.data(QtCore.Qt.DisplayRole).toString() 
     num = self.items.index(value) 
     editor.setCurrentIndex(num) 
    def setModelData(self, editor, model, index): 
     value = editor.currentText() 
     model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value)) 
    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

class Model(QtCore.QAbstractTableModel): 
    def __init__(self): 
     super(Model, self).__init__() 
     self.table = [[row, choices[0]] for row in rows] 
    def rowCount(self, index=QtCore.QModelIndex()): 
     return len(self.table) 
    def columnCount(self, index=QtCore.QModelIndex()): 
     return 2 
    def flags(self, index): 
     return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable 
    def data(self, index, role): 
     if role == QtCore.Qt.DisplayRole: 
      return self.table[index.row()][index.column()] 
    def setData(self, index, role, value): 
     if role == QtCore.Qt.DisplayRole: 
      self.table[index.row()][index.column()] = value 

class Main(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(Main, self).__init__(parent) 
     self.model = Model() 
     self.table = QtGui.QTableView() 
     self.table.setModel(self.model) 
     self.table.setItemDelegateForColumn(1, Delegate(self, ["apple", "orange", "banana"])) 
     self.setCentralWidget(self.table) 
     self.setWindowTitle('Delegate Test') 
     self.show() 

if __name__ == '__main__': 
    app = QtGui.QApplication(sys.argv) 
    main = Main() 
    app.exec_() 
+0

Bạn có thể tìm thấy câu trả lời của tôi để [câu hỏi này] (http://stackoverflow.com/questions/17615997/pyqt-how-to-set-qcombobox-in- a-table-view-using-qitemdelegate) hữu ích. –

+1

Cảm ơn bạn, bây giờ tôi thấy rằng 'paint' override là không cần thiết, và tôi cần' openPersistentEditor'. Nhưng gọi 'openPersistentEditor' dường như đánh bại mục đích của mô hình/xem nếu tôi cần gọi nó từ bên ngoài mô hình. Thêm vào đó, có vẻ như không hiệu quả khi vẽ tất cả các combobox đó khi bạn chỉ có thể hoạt động một lần tại một thời điểm. Có cách nào để loại bỏ yêu cầu nhấp đúp để nó xuất hiện khi lựa chọn ô? – user2120303

+0

Bạn không cần phải gọi nó từ mô hình. Bạn có thể sử dụng một đối tượng khác (ví dụ: dạng xem hoặc biểu mẫu con của bạn) để theo dõi thay đổi mô hình và gọi trình chỉnh sửa nếu cần. Đối với câu hỏi thứ hai, kết nối tín hiệu 'selectionChanged' của' view-> selectionModel() 'vào vị trí của bạn. Trong trình soạn thảo mở khe này trong ô đã chọn và đóng các trình chỉnh sửa trước đó nếu cần. –

Trả lời

5

Sử dụng QTableWiget.setCellWidget

import sys 
from PyQt4 import QtGui 
app = QtGui.QApplication(sys.argv) 
table = QtGui.QTableWidget(1,1) 
combobox = QtGui.QComboBox() 
combobox.addItem("Combobox item") 
table.setCellWidget(0,0, combobox) 
table.show() 
app.exec() 
+0

Câu hỏi đặt ra một hộp kết hợp bên trong QTableView chứ không phải QTableWidget. – ekhumoro

+0

@ekhumoro vâng, tôi đã thấy điều đó nhưng tôi nghĩ anh ấy chỉ muốn có một cách để có được một widget trong một cái bàn. Có lẽ tôi sẽ xóa câu trả lời này. –

1

Nếu bạn đang cố gắng để điều chỉnh khi xem hiển thị các biên tập viên, bạn cần phải thay đổi chỉnh sửa kích hoạt theo quy định tại QAbstractItemView. Mặc định là chỉnh sửa trên doubleClick, nhưng tôi nghĩ rằng những gì bạn đang sau là QAbstractItemView.CurrentChanged. Đặt nó bằng cách gọi myView.setEditTrigger()

-1

Nếu có ai quan tâm, dưới đây là những ví dụ tương tự sửa đổi cho PyQt5 và Python 3. cập nhật chính bao gồm:

  • Python 3: super().__init__()
  • PyQt5: hầu hết các lớp học nằm trong QtWidgets ; QtGui là không cần thiết ví dụ này
  • Model.setData: đầu vào để lập luận đổi thành: index, value, role, và True trở thay vì None
  • Combo hộp choices và bảng nội dung tại quy định bên Main; điều này làm cho DelegateModel tổng quát hơn
from PyQt5 import QtWidgets, QtCore 

class Delegate(QtWidgets.QItemDelegate): 
    def __init__(self, owner, choices): 
     super().__init__(owner) 
     self.items = choices 
    def createEditor(self, parent, option, index): 
     self.editor = QtWidgets.QComboBox(parent) 
     self.editor.addItems(self.items) 
     return self.editor 
    def paint(self, painter, option, index): 
     value = index.data(QtCore.Qt.DisplayRole) 
     style = QtWidgets.QApplication.style() 
     opt = QtWidgets.QStyleOptionComboBox() 
     opt.text = str(value) 
     opt.rect = option.rect 
     style.drawComplexControl(QtWidgets.QStyle.CC_ComboBox, opt, painter) 
     QtWidgets.QItemDelegate.paint(self, painter, option, index) 
    def setEditorData(self, editor, index): 
     value = index.data(QtCore.Qt.DisplayRole) 
     num = self.items.index(value) 
     editor.setCurrentIndex(num) 
    def setModelData(self, editor, model, index): 
     value = editor.currentText() 
     model.setData(index, QtCore.Qt.DisplayRole, QtCore.QVariant(value)) 
    def updateEditorGeometry(self, editor, option, index): 
     editor.setGeometry(option.rect) 

class Model(QtCore.QAbstractTableModel): 
    def __init__(self, table): 
     super().__init__() 
     self.table = table 
    def rowCount(self, parent): 
     return len(self.table) 
    def columnCount(self, parent): 
     return len(self.table[0]) 
    def flags(self, index): 
     return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable 
    def data(self, index, role): 
     if role == QtCore.Qt.DisplayRole: 
      return self.table[index.row()][index.column()] 
    def setData(self, index, value, role): 
     if role == QtCore.Qt.EditRole: 
      self.table[index.row()][index.column()] = value 
     return True 

class Main(QtWidgets.QMainWindow): 
    def __init__(self, parent=None): 
     super().__init__(parent) 
     # set combo box choices: 
     choices = ['apple', 'orange', 'banana'] 
     # create table data: 
     table = [] 
     table.append(['A', choices[0]]) 
     table.append(['B', choices[0]]) 
     table.append(['C', choices[0]]) 
     table.append(['D', choices[0]]) 
     # create table view: 
     self.model  = Model(table) 
     self.tableView = QtWidgets.QTableView() 
     self.tableView.setModel(self.model) 
     self.tableView.setItemDelegateForColumn(1, Delegate(self,choices)) 
     # make combo boxes editable with a single-click: 
     for row in range(len(table)): 
      self.tableView.openPersistentEditor(self.model.index(row, 1)) 
     # initialize 
     self.setCentralWidget(self.tableView) 
     self.setWindowTitle('Delegate Test') 
     self.show() 

if __name__ == '__main__': 
    import sys 
    app = QtWidgets.QApplication(sys.argv) 
    main = Main() 
    app.exec_()