0

Я пишу инструмент с двумя видами стола бок о бок. Я перетаскиваю данные между ними. Все работает нормально, но не работает, чтобы получить пустую модель. Поэтому вначале я хочу иметь пустой TableView и добавлять элементы с перетаскиванием. Это работает, когда хотя бы один объект находится, но не с пустым. с пустым, нет даже заголовка.PySide заполнить пустым TableModel

Я думаю, что проблема заключается в том, что TableView не вызывает модели headerData, когда он пуст ... но не знаю, правильно ли это. вот моя модель

Это сработает, если я не установлю пустую модель, но дождитесь, пока элемент не появится в модели и не установит ее позже. Но это не очень приятно ...

class myTableModel(TableModel): 
    def __init__(self, headers = [], items = [[]], parent = None): 
     super(myTableModel,self).__init__(headers,items,parent) 
     self.__items = items 
     self.__headers = headers 

    def flags(self, index): 
     if not index.isValid(): 
      return QtCore.Qt.ItemIsEnabled 
     if index.column() == 0: 
      return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable 
     return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled 

    def supportedDropActions(self): 
     return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction  

    def removeRow(self, row, index=QtCore.QModelIndex()): 
     self.beginRemoveRows(QtCore.QModelIndex(), row, row) 
     self.__items.pop(row) 
     self.endRemoveRows() 
     return True 

    def insertRow(self, data,row=0,index=QtCore.QModelIndex()): 
     self.beginInsertRows(QtCore.QModelIndex(), 0,0) 
     self.__items.insert(0, data) 
     self.endInsertRows() 
     return True   
    def data(self,index,role=QtCore.Qt.DisplayRole): 
     if role == QtCore.Qt.DisplayRole: 
      row = index.row() 
      column = index.column() 

      if len(self.__items[row])-1 < column: 
       return "" 
      else: 
       return self.__items[row][column] 

    def setData(self, index, value, role=QtCore.Qt.EditRole): 
     if role == QtCore.Qt.EditRole: 
      row = index.row() 
      column = index.column() 
      self.__items[row][column] = value 
      self.dataChanged.emit(index, index) 
      return True 

    def headerData(self, section, orientation, role): 
     if role == QtCore.Qt.DisplayRole: 
      if orientation == QtCore.Qt.Horizontal: 
       if len(self.__headers)-1 < section: 
        return "" 
       else: 
        #print "%s in section %i" %(self.__headers[section],section) 
        return self.__headers[section] 

ответ

1

Я, наверное, слишком поздно, чтобы придумать ответ, но сам вопрос был мне интересен, так что я копаться в нем и был в состоянии найти решение.

Как оказалось, для реализации пустого состояния табличной модели есть несколько ошибок, чтобы они по-прежнему отображали заголовки столбцов и, кроме того, позволяли удалять вещи сами по себе.

Первый способ заключается в том, что Qt, похоже, не рисует заголовки столбцов, если columnCount метод возвращает 0 для недопустимого QModelIndex. В этом случае, по-видимому, даже не стоит называть метод headerData. Решение состоит в том, чтобы никогда не возвращать 0 из columnCount с недопустимым QModelIndex, даже если количество строк на самом деле равно 0, а наша базовая структура данных - это 2D-массив, где 0 строк - 0 столбцов.

Второй Гоча является то, что вам кажется, нужно настраиваемое представление подклассов QTableView потому, что вам нужно переопределить dragEnterEvent и dragMoveEvent принять сопротивление входит и сопротивление движется безоговорочно. В противном случае события сбрасывания не будут иметь возможности запускать, даже если вы установили свойство acceptDrops вида на True. По умолчанию реализация dragEnterEvent и/или dragMoveEvent, похоже, относится к базовой модели представления, и если у модели нет строк, представление отказывается принимать капли.

Третий gotcha - это не очень-то похожее, это именно то, что в методе dropMimeData вашей модели вам нужно вставлять строки, если у вас их нет, чтобы сделать комнату для сброшенного предмета.

Вот полное решение для PySide 1.2.1/Qt 4.8.5 протестирована с Python 2.7:

import sys 
from PySide import QtCore, QtGui 

class TableModel(QtCore.QAbstractTableModel): 
    def __init__(self, headers = [], items = [[]], parent = None): 
     super(TableModel,self).__init__(parent) 
     self.__items = items 
     self.__headers = headers 

     row_counter = 0 
     for row_item in self.__items: 
      column_counter = 0 
      for column_item in row_item: 
       idx = self.createIndex(row_counter, column_counter) 
       self.setData(idx, column_item, QtCore.Qt.EditRole) 
       self.dataChanged.emit(idx, idx) 
       column_counter += 1 
      row_counter += 1   

     num_headers = len(self.__headers) 
     for section in range(0, num_headers): 
      self.setHeaderData(section, QtCore.Qt.Horizontal, self.__headers[section]) 
     self.headerDataChanged.emit(QtCore.Qt.Horizontal, 0, num_headers) 

    def index(self, row, column, parent): 
     if row < 0 or row >= len(self.__items): 
      return QtCore.QModelIndex() 
     return self.createIndex(row, column, self.__items[row]) 

    def parent(self, index): 
     return QtCore.QModelIndex() 

    def rowCount(self, index): 
     if index.isValid(): 
      return 

     num_rows = len(self.__items) 

     # checking for empty nested columns list within a single "row" 
     if num_rows == 1: 
      if len(self.__items[0]) == 0: 
       return 0 

     return num_rows 

    def columnCount(self, index): 
     if index.isValid(): 
      return 0 

     # compute the max column count within all rows 
     max_column_count = 0 
     for row in self.__items: 
      column_count = len(row) 
      if column_count > max_column_count: 
       max_column_count = column_count 

     # if there are no real columns, make the column count return the number of headers instead 
     if max_column_count < len(self.__headers): 
      max_column_count = len(self.__headers) 
     return max_column_count 

    def flags(self, index): 
     if not index.isValid(): 
      return QtCore.Qt.ItemIsEnabled 
     if index.column() == 0: 
      return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | QtCore.Qt.ItemIsDragEnabled | \ 
        QtCore.Qt.ItemIsDropEnabled | QtCore.Qt.ItemIsEditable 
     return QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | \ 
       QtCore.Qt.ItemIsDragEnabled | QtCore.Qt.ItemIsDropEnabled 

    def supportedDropActions(self): 
     return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction  

    def insertRows(self, row, count, index): 
     if index.isValid(): 
      return False 
     if count <= 0: 
      return False 
     num_columns = self.columnCount(index) 
     # inserting 'count' empty rows starting at 'row' 
     self.beginInsertRows(QtCore.QModelIndex(), row, row + count - 1) 
     for i in range(0, count): 
      # inserting as many columns as the table currently has 
      self.__items.insert(row + i, ["" for i in range(0, num_columns)]) 
     self.endInsertRows() 
     return True 

    def removeRows(self, row, count, index): 
     if index.isValid(): 
      return False 
     if count <= 0: 
      return False 
     num_rows = self.rowCount(QtCore.QModelIndex()) 
     self.beginRemoveRows(QtCore.QModelIndex(), row, row + count - 1) 
     for i in range(count, 0, -1): 
      self.__items.pop(row - i + 1) 
     self.endRemoveRows() 
     return True 

    def data(self,index,role=QtCore.Qt.DisplayRole): 
     if role == QtCore.Qt.DisplayRole: 
      row = index.row() 
      column = index.column() 
      if row < 0 or row >= len(self.__items): 
       return "" 
      if column < 0 or column >= len(self.__items[row]): 
       return "" 
      else: 
       return self.__items[row][column] 
     return None 

    def setData(self, index, value, role=QtCore.Qt.EditRole): 
     if not index.isValid: 
      return False 
     if role == QtCore.Qt.EditRole: 
      row = index.row() 
      column = index.column() 
      if row < 0 or row >= self.rowCount(QtCore.QModelIndex()): 
       return False 
      if column < 0 or column >= len(self.__items[row]): 
       return False 
      self.__items[row].pop(column) 
      self.__items[row].insert(column, value) 
      self.dataChanged.emit(index, index) 
      return True 
     return False 

    def headerData(self, section, orientation, role): 
     if role == QtCore.Qt.DisplayRole: 
      if orientation == QtCore.Qt.Horizontal: 
       if section < 0 or section >= len(self.__headers): 
        return "" 
       else: 
        return self.__headers[section] 
     return None 

    def mimeTypes(self): 
     return ['application/vnd.tableviewdragdrop.list'] 

    def mimeData(self, indexes): 
     mimedata = QtCore.QMimeData() 
     encoded_data = QtCore.QByteArray() 
     stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.WriteOnly) 
     for index in indexes: 
      if index.isValid(): 
       text = self.data(index, QtCore.Qt.DisplayRole) 
       stream << QtCore.QByteArray(text) 
     mimedata.setData('application/vnd.tableviewdragdrop.list', encoded_data) 
     return mimedata 

    def dropMimeData(self, data, action, row, column, parent): 
     if action == QtCore.Qt.IgnoreAction: 
      return True 
     if not data.hasFormat('application/vnd.tableviewdragdrop.list'): 
      return False 
     if column > 0: 
      return False 

     num_rows = self.rowCount(QtCore.QModelIndex()) 

     begin_row = 0 
     if row != -1: 
      begin_row = row 
     elif parent.isValid(): 
      begin_row = parent.row() 
     else: 
      begin_row = num_rows 

     if begin_row == num_rows: 
      self.insertRows(begin_row, 1, QtCore.QModelIndex()) 

     if column < 0: 
      if parent.isValid(): 
       column = parent.column() 
      else: 
       column = 0 

     encoded_data = data.data('application/vnd.tableviewdragdrop.list') 
     stream = QtCore.QDataStream(encoded_data, QtCore.QIODevice.ReadOnly) 
     new_items = [] 
     rows = 0 
     while not stream.atEnd(): 
      text = QtCore.QByteArray() 
      stream >> text 
      new_items.append(str(text)) 
      rows += 1 

     for text in new_items: 
      idx = self.index(begin_row, column, QtCore.QModelIndex()) 
      self.setData(idx, text, QtCore.Qt.EditRole) 
      begin_row += 1 

     return True 

class TableView(QtGui.QTableView): 
    def __init__(self, parent=None): 
     super(TableView, self).__init__(parent) 
     self.setAcceptDrops(True) 

    def dragEnterEvent(self, event): 
     event.accept() 

    def dragMoveEvent(self, event): 
     event.accept() 

class MainForm(QtGui.QMainWindow): 
    def __init__(self, parent=None): 
     super(MainForm, self).__init__(parent) 

     self.left_model = TableModel(headers=["column0", "column1", "column2"]) 
     #self.left_model = TableModel(items=[["left0", "left1", "left2"],["left3","left4","left5"]], 
     #        headers=["column0", "column1", "column2"]) 
     self.right_model = TableModel(items=[['right0', 'right1', 'right2'], ['right3', 'right4', 'right5']], 
             headers=['column0', 'column1', 'column2']) 

     self.left_view = TableView() 
     self.left_view.setModel(self.left_model) 
     self.left_view.setDragDropMode(QtGui.QAbstractItemView.DragDrop) 

     self.right_view = TableView() 
     self.right_view.setModel(self.right_model) 
     self.right_view.setDragDropMode(QtGui.QAbstractItemView.DragDrop) 

     self.layout = QtGui.QHBoxLayout() 
     self.layout.addWidget(self.left_view) 
     self.layout.addWidget(self.right_view) 

     self.window = QtGui.QWidget() 
     self.window.setLayout(self.layout) 

     self.setCentralWidget(self.window) 

def main(): 
    app = QtGui.QApplication(sys.argv) 
    form = MainForm() 
    form.show() 
    app.exec_() 

if __name__ == '__main__': 
    main() 
Смежные вопросы