Results 1 to 4 of 4

Thread: Tableview column size update

  1. #1
    Join Date
    Oct 2015
    Posts
    45
    Thanks
    8
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Tableview column size update

    I'm using a delegate to display the data in a table.

    The goal is to display an indicator with some text.

    And that part works. But, I can't seem to figure out how to get the column width to resize to fit the painted cell width. (If I expand the width of the column, the complete string is there)

    It appears that it is sizing the columns based on the with of the header data, not the cell data.

    (I've "translated" this from an example in C++, and between my level of QT expertise and the translating...I probably have missed something obvious. )

    The main window starts:

    Qt Code:
    1. class TDDlg(QtWidgets.QMainWindow):
    2.  
    3. #CueFileUpdate_sig = pyqtSignal()
    4. def __init__(self, parent=None):
    5. super(TDDlg, self).__init__(parent)
    6. self.setupUi(self)
    7. self.tableheader_horz = self.get_header_horz()
    8. self.tableheader_vert = []
    9. #self.tableView.doubleClicked.connect(self.on_table_dblclick)
    10. #self.tableView.clicked.connect(self.on_table_click)
    11. self.tabledata = []
    12. self.get_table_data()
    13. self.leveldata = []
    14. self.get_level_data()
    15. self.tablemodel = MyTableModel(self.tabledata, self.leveldata, self.tableheader_horz, self.tableheader_vert, self)
    16. self.tableView.setModel(self.tablemodel)
    17. #self.tableView.setItemDelegateForColumn(3, CellDelegate())
    18. self.tableView.setItemDelegate(CellDelegate())
    19. self.tableView.setSelectionMode(QAbstractItemView.SingleSelection)
    20. self.tableView.setSelectionBehavior(QAbstractItemView.SelectItems)
    21. self.tableView.resizeColumnsToContents()
    22. i = self.tableView.model().index(0, 0)
    23.  
    24. def setupUi(self, MainWindow):
    25. MainWindow.setObjectName("MainWindow")
    26. MainWindow.resize(800, 600)
    27. self.centralwidget = QtWidgets.QWidget(MainWindow)
    28. self.centralwidget.setObjectName("centralwidget")
    29. self.gridLayout_2 = QtWidgets.QGridLayout(self.centralwidget)
    30. self.gridLayout_2.setObjectName("gridLayout_2")
    31. self.gridLayout = QtWidgets.QGridLayout()
    32. self.gridLayout.setObjectName("gridLayout")
    33. self.tableView = QtWidgets.QTableView(self.centralwidget)
    34. self.tableView.setObjectName("tableView")
    35. self.gridLayout.addWidget(self.tableView, 0, 0, 1, 1)
    36. self.gridLayout_2.addLayout(self.gridLayout, 0, 0, 1, 1)
    37. MainWindow.setCentralWidget(self.centralwidget)
    38. self.menubar = QtWidgets.QMenuBar(MainWindow)
    39. self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 28))
    40. self.menubar.setObjectName("menubar")
    41. MainWindow.setMenuBar(self.menubar)
    42. self.statusbar = QtWidgets.QStatusBar(MainWindow)
    43. self.statusbar.setObjectName("statusbar")
    44. MainWindow.setStatusBar(self.statusbar)
    45. self.toolBar = QtWidgets.QToolBar(MainWindow)
    46. self.toolBar.setObjectName("toolBar")
    47. MainWindow.addToolBar(QtCore.Qt.TopToolBarArea, self.toolBar)
    48.  
    49. self.retranslateUi(MainWindow)
    50. QtCore.QMetaObject.connectSlotsByName(MainWindow)
    51.  
    52.  
    53. And the model and the delegate:
    54.  
    55. [CODE]
    56. class MyTableModel(QtCore.QAbstractTableModel):
    57. def __init__(self, datain, leveldata, headerdata_horz, headerdata_vert, parent=None):
    58. QtCore.QAbstractTableModel.__init__(self, parent)
    59. self.arraydata = datain
    60. self.leveldata = leveldata
    61. self.headerdata_horz = headerdata_horz
    62. self.headerdata_vert = headerdata_vert
    63.  
    64. def rowCount(self, parent):
    65. if parent.isValid():
    66. return 0
    67. return len(self.arraydata)
    68.  
    69. def columnCount(self, parent):
    70. if parent.isValid():
    71. return 0
    72. else:
    73. if self.arraydata:
    74. return len(self.arraydata[0])
    75. else:
    76. return 0
    77.  
    78. def data(self, index, role): # Return data from the model
    79. if not index.isValid():
    80. logging.info('Invalid index in MyModel>data')
    81. retval = QtCore.QVariant()
    82. elif role == QtCore.Qt.BackgroundRole:
    83. cell_contents = self.arraydata[index.row()][index.column()]
    84. if cell_contents[-1] == '0':
    85. retval = QtCore.QVariant()
    86. else:
    87. retval = QBrush(Qt.red)
    88. elif role == QtCore.Qt.DisplayRole:
    89. retval = QtCore.QVariant(self.arraydata[index.row()][index.column()])
    90. else:
    91. retval = QtCore.QVariant()
    92.  
    93. return retval
    94.  
    95. def setData(self, index, value, role): # Set data in the model
    96. if role == QtCore.Qt.EditRole and index.isValid():
    97. print(index.row())
    98. self.arraydata[index.row()][index.column()] = value
    99. print('Return from rowCount: {0}'.format(self.rowCount(index)))
    100. self.dataChanged.emit(index, index, [QtCore.Qt.DisplayRole])
    101. return True
    102. return False
    103.  
    104. def headerData(self, col, orientation, role):
    105. if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
    106. if col < len(self.headerdata_horz):
    107. return QtCore.QVariant(self.headerdata_horz[col])
    108. else:
    109. return QtCore.QVariant('')
    110. elif orientation == QtCore.Qt.Vertical and role == QtCore.Qt.DisplayRole:
    111. if col < len(self.headerdata_vert):
    112. return QtCore.QVariant(self.headerdata_vert[col])
    113. else:
    114. return QtCore.QVariant('')
    115.  
    116. return QtCore.QVariant()
    117.  
    118. class CellDelegate(QStyledItemDelegate):
    119. def __init__(self):
    120. QStyledItemDelegate.__init__(self)
    121. self.diameter = 10
    122. def paint(self, painter, item, modelindex): #QStyleOptionViewItem
    123. diameter = min(item.rect.width(),item.rect.height())
    124. self.diameter = diameter
    125. adjustedRect = copy.copy(item.rect)
    126. adjustedRect.setWidth(diameter)
    127. adjustedRect.setHeight(diameter)
    128. adjustedRect = adjustedRect.adjusted(5,5,-5,-5)
    129. shade = 120
    130. background = QColor(shade, shade, 128)
    131. painter.setPen(background)
    132. painter.setBrush(background)
    133. painter.drawEllipse(adjustedRect)
    134. val = modelindex.data()
    135. level = '>' + val.split(':')[0] + ':' + str(int_to_db(int(val.split(':')[1])))
    136. painter.setPen(Qt.red)
    137. painter.drawText(item.rect.adjusted(round(diameter * 1.1),0,0,0),
    138. QtCore.Qt.AlignHCenter | QtCore.Qt.AlignVCenter,
    139. level)
    140. return
    To copy to clipboard, switch view to plain text mode 
    [/CODE]

  2. #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: Tableview column size update

    The call to resizeColumnsToContents() in the __init__ function has no effect, since the table is not yet visible and therefore the geometry has not yet been calculated. This happens only just prior to the showEvent(). So the place to put this is to override showEvent() for your TDDlg and call it there. You'll also need to call it again each time the table contents changes. For that, you'll need to connect a slot to one of the model's signals that indicates a change (such as dataChanged()).
    <=== The Great Pumpkin says ===>
    Please use CODE tags when posting source code so it is more readable. Click "Go Advanced" and then the "#" icon to insert the tags. Paste your code between them.

  3. #3
    Join Date
    Oct 2015
    Posts
    45
    Thanks
    8
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: Tableview column size update

    I added this to TDDLG:

    Qt Code:
    1. def showEvent(self, event):
    2. self.tableView.resizeColumnsToContents()
    To copy to clipboard, switch view to plain text mode 

    It never gets called.

    I added this to TDDLG __init__:

    Qt Code:
    1. self.tablemodel.dataChanged.connect(self.model_changed)
    To copy to clipboard, switch view to plain text mode 

    and this to TDDLG:

    Qt Code:
    1. def model_changed(self, event):
    2. self.tableView.resizeColumnsToContents()
    To copy to clipboard, switch view to plain text mode 

    It never gets called either, but I have no way to change data in the table at this point, so that is no surprise...I think.


    Update: I don't know what I did but showEvent in TDDlg is now being called...but it still doesn't change the columns to fit the data.


    Added after 15 minutes:


    If I understand...which always questionable, the sizeHint in the delegate is called to determine the cell size.

    Maybe I'm not calculating that correctly:

    Qt Code:
    1. def sizeHint(self, item, modelindex):
    2. textwidth = item.fontMetrics.width(modelindex.data())
    3. newwidth = textwidth + self.diameter
    4. return QSize(newwidth, item.fontMetrics.height())
    To copy to clipboard, switch view to plain text mode 

    The intent the diameter is the additional width added by the drawEllipse in the delegate paint routine.
    Last edited by drmacro; 31st August 2017 at 23:18.

  4. #4
    Join Date
    Oct 2015
    Posts
    45
    Thanks
    8
    Qt products
    Qt5
    Platforms
    Unix/X11

    Default Re: Tableview column size update

    Ok, back at this after a trip.

    I have implemented it as discussed previously and re-implemented with decorator role.

    I am not able to get the custom delegate code to update the width of the cell to the data.
    (If I put a fudge factor in the cell delegate size hint as shown below, the cell expands and shows the text of the data.
    Of course, the fudge only works for the test data and won't be big enough if the data changes.)

    Qt Code:
    1. def sizeHint(self, item, modelindex):
    2. val = modelindex.data()
    3. textwidth = item.fontMetrics.width(val)
    4. textheight = item.fontMetrics.height()
    5. bbox = item.fontMetrics.boundingRect(val)
    6. diameter = round(min(textwidth,textheight) * 1.6) #<----fudge factor
    7. newwidth = textwidth + diameter
    8. print('In sizeHint, textwidth={}, newwidth={}, diameter={}'.format(textwidth, newwidth, diameter))
    9. print('model_index.data={}, level ={}'.format(modelindex.data(), val))
    10. print('bbox width={}'.format(bbox.width()))
    11. return QSize(newwidth, item.fontMetrics.height())
    To copy to clipboard, switch view to plain text mode 

    Implemented with the decorator role, works fine. But, (and I assume I'm doing something wrong ) with the decorator role
    the app takes twice as long to start up.

    I assume this is because in the decorator implementation, it loads an icon rater than drawing an ellipse for each cell.

    I'd like to figure out what I'm doing wrong in the custom delegate, but, I have no particular need to have the custom delegate and the decorator way expands the cells fine.
    Having implemented the decorator I'd now like to know if
    there are ways to improve the icon loading (currently I load two different icons in the table model and return them as decorators, see below).
    (Or, maybe use something other than an icon as the decorator??)

    Qt Code:
    1. class MyTableModel(QtCore.QAbstractTableModel):
    2. def __init__(self, datain, leveldata, headerdata_horz, headerdata_vert, parent=None):
    3. """
    4. Args:
    5. datain: a list of lists\n
    6. headerdata: a list of strings
    7. """
    8. QtCore.QAbstractTableModel.__init__(self, parent)
    9. self.arraydata = datain
    10. self.leveldata = leveldata
    11. self.headerdata_horz = headerdata_horz
    12. self.headerdata_vert = headerdata_vert
    13. self.iconmute_on = QtGui.QIcon()
    14. self.iconmute_on.addPixmap(QtGui.QPixmap(":/icon/Mute_illum_64.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
    15. self.iconmute_off = QtGui.QIcon()
    16. self.iconmute_off.addPixmap(QtGui.QPixmap(":/icon/Mute_dark_64.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
    17.  
    18. def data(self, index, role): # Return data from the model
    19. if index.isValid():
    20. #print('Invalid index in MyModel>data')
    21. logging.info('Invalid index in MyModel>data')
    22. retval = QtCore.QVariant()
    23. if role == QtCore.Qt.BackgroundRole:
    24. cell_contents = self.arraydata[index.row()][index.column()]
    25. retval = QtCore.QVariant()
    26. # if cell_contents[-1] == '0':
    27. # #retval = QBrush(Qt.lightGray)
    28. # retval = QtCore.QVariant()
    29. # else:
    30. # retval = QBrush(Qt.red)
    31. elif role == QtCore.Qt.DisplayRole:
    32. retval = QtCore.QVariant(self.leveldata[index.row()][index.column()])
    33. # retval = QtCore.QVariant(self.leveldata[index.row()][index.column()])
    34. elif role == QtCore.Qt.DecorationRole:
    35. #retval = QtGui.QIcon("Mute_illum_64.png")
    36. #if index.column() != 0:
    37. try:
    38. if self.arraydata[index.row()][index.column()][-1] == '0':# or index.column() == 0:
    39. #return mute_btn_dark# QtGui.QIcon('Mute_dark_64.png')
    40. return self.iconmute_off
    41. else:
    42. #return mute_btn_illum #QtGui.QIcon('Mute_illum_64.png')
    43. return self.iconmute_on
    44. except IndexError:
    45. print('Bad index, Row: {}, Column:{}'.format(index.row(),index.column()))
    46.  
    47. else:
    48. retval = QtCore.QVariant()
    49.  
    50. return retval
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. TableView highlight column on mouse-over
    By KiNgFrUiT in forum Qt Quick
    Replies: 2
    Last Post: 5th December 2015, 11:43
  2. Replies: 1
    Last Post: 28th November 2015, 20:44
  3. Replies: 2
    Last Post: 8th December 2013, 05:53
  4. Replies: 0
    Last Post: 18th April 2011, 15:07
  5. Tableview - Three subcolumns inside one column?
    By qlands in forum Qt Programming
    Replies: 2
    Last Post: 24th March 2010, 15:04

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.