Results 1 to 2 of 2

Thread: Custom Filter(s) within QAbstractTableModel (PyQt)

  1. #1
    Join Date
    Dec 2014
    Posts
    48
    Thanks
    23
    Thanked 1 Time in 1 Post
    Qt products
    Qt3 Qt4 PyQt3 PyQt4
    Platforms
    Windows

    Default Re: Custom Filter(s) within QAbstractTableModel (PyQt)

    Hello.
    This is a carry-over from another thread Rapid Updates of QSortFilterProxyModel, where it was recommended filtering be bypassed in QSortFilterProxyModel - and move such responsibilities into the trunk AbstractTableModel.

    Snags were hit rather quickly in this transition (novice with script here).
    The code below results in correct headers for my QtableView window, but no rows ever populate.
    To check why this was so, a print statement for 'rowCount()' was added after selected rows were 'updated', and appropriately reflects the size of the selection, yet the tableView is not updated...
    selection.jpg

    Most importantly, when using the save function, the *.CSV source file contains only the rows selected and all others are lost (overwritten).
    The errors are probably obious - but wiser eyes might observe such quicker then I.
    Thanks for any help.
    Qt Code:
    1. # QTableModel data handeler (aka tableData)
    2. class CSVModel(QtCore.QAbstractTableModel):
    3.  
    4. # load in csv data, and establish inital limiter on loaded row count (for efficency)
    5. def __init__(self, iface, fileName, parent=None):
    6. super(CSVModel,self).__init__()
    7. self.iface = iface
    8. self.rows = []
    9. self.fileName = fileName
    10. self.loadCSV(fileName)
    11. self.rowsLoaded = len(self.rows)
    12. self.iface.mapCanvas().selectionChanged.connect(self.addRow)
    13.  
    14. def loadCSV(self,fileName):
    15. self.header = []
    16. self.dataIn = []
    17. with open(self.fileName, "rb") as fileInput:
    18. for idx, row in enumerate(csv.reader(fileInput)):
    19. headerIDx = 0
    20. if idx is headerIDx:
    21. self.header.append(row)
    22. elif idx>headerIDx:
    23. items = [field for field in row]
    24. self.dataIn.append(items)
    25.  
    26. def addRow(self):
    27. del self.rows[:]
    28. editLayer_Atrib = ftools_utils.getMapLayerByName(unicode(self.iface.activeLayer().name()))
    29. totalFeatures = range(editLayer_Atrib.featureCount())
    30. features = editLayer_Atrib.selectedFeatures()
    31. self.beginResetModel()
    32. for feature in features:
    33. ID = feature.attributes()[0]
    34. self.rows.append(self.dataIn[ID])
    35. self.endResetModel()
    36.  
    37. # relative axis index counts
    38. def rowCount(self,index):
    39. print len(self.rows)
    40. if not self.rows:
    41. return 0
    42. if len(self.rows) <= self.rowsLoaded:
    43. return len(self.rows)
    44. else:
    45. return self.rowsLoaded
    46. def columnCount(self,index):
    47. return len(self.header[0])
    48.  
    49. # source value data for cell(s) in QtableView
    50. def data(self,index,role):
    51. if index.isValid() and role == Qt.DisplayRole:
    52. return self.rows[index.row()][index.column()]
    53.  
    54. # establish header data
    55. def headerData(self,section,orientation,role):
    56. if role != Qt.DisplayRole:
    57. return
    58. if orientation == Qt.Vertical:
    59. return int(section)
    60. if orientation == Qt.Horizontal:
    61. return self.header[0][section]
    62.  
    63. # write changes from QtableView and proxyFilter to (self) tableData
    64. def setData(self, index, value, role):
    65. if index.isValid() and role == Qt.EditRole:
    66. self.rows[index.row()][index.column()]=str(value)
    67. self.dataChanged.emit(index, index)
    68. return True
    69. return False
    70.  
    71. # distinguish capabilities of total cells in tableData model
    72. def flags(self, index):
    73. return QtCore.Qt.ItemIsEditable | QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable
    74.  
    75. # one piece of toast and jam please
    76. def saveIt(self):
    77. with open(self.fileName, "wb") as fileOutput:
    78. writer = csv.writer(fileOutput)
    79. writer.writerow(self.header[0])
    80. for rowNumber in range(len(self.rows)):
    81. fields = self.rows[rowNumber]
    82. writer.writerow(fields)
    To copy to clipboard, switch view to plain text mode 


    Added after 17 minutes:


    Alright, discovered removing the un-necessaries from rowCount() now populates the table nearly immediately. Even for enormous selection counts!

    Qt Code:
    1. def loadCSV(self,fileName):
    2. self.header = []
    3. self.dataIn = []
    4. with open(self.fileName, "rb") as fileInput:
    5. for idx, row in enumerate(csv.reader(fileInput)):
    6. headerIDx = 0
    7. if idx is headerIDx:
    8. self.header.append(row)
    9. elif idx>headerIDx:
    10. items = [field for field in row]
    11. self.dataIn.append(items)
    12.  
    13. def addRow(self):
    14. del self.rows[:]
    15. editLayer_Atrib = ftools_utils.getMapLayerByName(unicode(self.iface.activeLayer().name()))
    16. totalFeatures = range(editLayer_Atrib.featureCount())
    17. features = editLayer_Atrib.selectedFeatures()
    18. self.beginResetModel()
    19. for feature in features:
    20. ID = feature.attributes()[0]
    21. self.rows.append(self.dataIn[ID])
    22. self.endResetModel()
    23.  
    24. # relative axis index counts
    25. def rowCount(self,index):
    26. return len(self.rows)
    27. def columnCount(self,index):
    28. return len(self.header[0])
    To copy to clipboard, switch view to plain text mode 

    Now my concern resides in the save function. Loaded rows (with possible changes made) need to be combined back with the original data source (dataIn) prior to writing.

    Qt Code:
    1. # one piece of toast with jam please
    2. def saveIt(self):
    3. with open(self.fileName, "wb") as fileOutput:
    4. writer = csv.writer(fileOutput)
    5. writer.writerow(self.header[0])
    6. for rowNumber in range(len(self.rows)):
    7. fields = self.rows[rowNumber]
    8. writer.writerow(fields)
    To copy to clipboard, switch view to plain text mode 

    Any clues on doing this in a clean manner?


    Added after 57 minutes:


    This IS a frowned upon solution, but it works.
    j[0] and I[0] are refereeing to ID values, represented by each object and row (selected) respectively.
    The problem is, if multiple edits are made to different selections - this will not work.
    It seems the edits, as they are made, need to be pushed to the dataIn source correct?
    ...Rather then conclusively right before a save is called?

    Qt Code:
    1. def mergeEdits(self):
    2. for idx,j in enumerate(self.rows):
    3. if j[0] == self.dataIn[idx][0]:
    4. self.dataIn[idx] = j
    5. else:
    6. pass
    7.  
    8. # one piece of toast with jam please
    9. def saveIt(self):
    10. self.mergeEdits()
    11. with open(self.fileName, "wb") as fileOutput:
    12. writer = csv.writer(fileOutput)
    13. writer.writerow(self.header[0])
    14. for rowNumber in range(len(self.dataIn)):
    15. fields = self.dataIn[rowNumber]
    16. writer.writerow(fields)
    To copy to clipboard, switch view to plain text mode 


    UPDATE:
    As it turns out, this method does allow multiple edits. As each user change is pushed to the list (self.rows), and it not fully written until the user opts to use the save function.
    I suppose this current procedure will be the best option - unless there is a wiser way?

    Kudos to this forum, for its spoken and unspoken help!
    Last edited by jkrienert; 5th January 2015 at 18:24.

  2. The following user says thank you to jkrienert for this useful post:

    d_stranz (5th January 2015)

  3. #2
    Join Date
    Jan 2008
    Location
    Alameda, CA, USA
    Posts
    5,230
    Thanks
    302
    Thanked 864 Times in 851 Posts
    Qt products
    Qt5
    Platforms
    Windows

    Default Re: Custom Filter(s) within QAbstractTableModel (PyQt)

    You know, I hope that when you are doing all this talking to yourself, it isn't loud enough for your coworkers to hear. You might start getting some funny looks.

    Thanks for sharing your solutions.

  4. The following user says thank you to d_stranz for this useful post:

    jkrienert (5th January 2015)

Similar Threads

  1. Custom Multi-Filter QSortFilterProxyModel
    By fruzzo in forum Qt Programming
    Replies: 1
    Last Post: 5th April 2012, 13:26
  2. Replies: 0
    Last Post: 5th April 2011, 16:51
  3. Custom role in custom QAbstractTableModel
    By hailflex in forum Newbie
    Replies: 3
    Last Post: 10th December 2009, 12:09
  4. QAbstractTableModel , custom data
    By akon in forum Newbie
    Replies: 0
    Last Post: 17th April 2009, 16:03
  5. QStringList withing QDomText
    By NoRulez in forum Qt Programming
    Replies: 5
    Last Post: 13th November 2008, 10:13

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.