Cell spacing and focus rectangle in QTableView - qt

I have a QTableView that shows some data from my custom subclass of QAbstractTableModel. The problem is that the text is pushed up against the left side of the cell. I found this question: How to set the padding of QTableView cells through CSS? It led me to try this:
self.tableView.setStyleSheet('QTableView::item {border: 0px; padding: 5px;} ')
That indented the text but introduced a new problem. Now when I click on a cell, the dotted focus rectangle is inset into the cell.
How can I have both cell spacing and a dotted focus rectangle that surrounds the entire cell (not inset)?

Using CSS is not the best way to do this, take 5 minutes of your time and write delegate, it's easy.
But you can try:
QTableView {
outline: 0; /* Disable focus rect*/
}
QTableView:item {
border: 0px;
padding: 0px 10px;
}
QTableView::item:focus { /*Emulate focus*/
color: black;
background-color: yellow;
border: 1px dashed black;
}

Here is what I was finally able to come up with. It puts the focus rectangle on the border of each cell, regardless of "padding" or "margin". It also preserves the stylesheet. At least it preserves background color and padding. I didn't test all stylesheet options. However, it does not preserve the text color in the cell with focus. (P.S. This is working with PySide 1.1.1)
class CellDelegate(QtGui.QStyledItemDelegate):
def __init__(self, parent):
super(CellDelegate, self).__init__(parent)
self._parent = parent
def paint(self, qPainter, option, qModelIndex):
v4Option = QtGui.QStyleOptionViewItemV4(option)
v4Option.index = qModelIndex
value = qModelIndex.data()
v4Option.text = str(value)
style = self._parent.style()
if (v4Option.state & QtGui.QStyle.State_HasFocus):
# --- The table cell with focus
# Draw the background
style.drawPrimitive(style.PE_PanelItemViewItem, v4Option, qPainter, self._parent)
# Draw the text
subRect = style.subElementRect(style.SE_ItemViewItemText, v4Option, self._parent)
alignment = qModelIndex.data(QtCore.Qt.TextAlignmentRole)
if not alignment:
alignment = int(QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)
if (v4Option.state & QtGui.QStyle.State_Enabled):
itemEnabled = True
else:
itemEnabled = False
textRect = style.itemTextRect(v4Option.fontMetrics, subRect, alignment, itemEnabled, value)
style.drawItemText(qPainter, textRect, alignment, v4Option.palette, v4Option.state, value)
# Draw the focus rectangle
focusOption = QtGui.QStyleOptionFocusRect()
focusOption.rect = v4Option.rect
style.drawPrimitive(style.PE_FrameFocusRect, focusOption, qPainter, self._parent)
else:
# --- All other table cells
style.drawControl(style.CE_ItemViewItem, v4Option, qPainter, self._parent)
Here is some example code showing how to use it. The goal is that the stylesheet would be set in a .ui file. This is just a self-contained example:
class TestTableModel(QtCore.QAbstractTableModel):
headerNames = ('Column 1', 'Column 2')
def __init__(self):
super(TestTableModel, self).__init__()
self._data = [['test', 'text'], ['yyy', 'zzz']]
#----- Overridden Functions ------------------------------------------------
def columnCount(self, parentIndex):
return len(self.headerNames)
def data(self, qModelIndex, role=QtCore.Qt.DisplayRole):
if qModelIndex.isValid():
if role in (QtCore.Qt.DisplayRole, QtCore.Qt.EditRole):
dataItem = self._data[qModelIndex.row()][qModelIndex.column()]
return dataItem
return None
def headerData(self, colNum, orientation, role):
if (orientation == QtCore.Qt.Horizontal) and (role == QtCore.Qt.DisplayRole):
return self.headerNames[colNum]
return None
def rowCount(self, parentIndex=QtCore.QModelIndex()):
return len(self._data)
#------------------------------------------------------------------------------
class TestTableViewSpacing(QtGui.QMainWindow):
def __init__(self, parent=None):
super(TestTableViewSpacing, self).__init__(parent)
self.tableView = QtGui.QTableView()
self.setCentralWidget(self.tableView)
tableModel = TestTableModel()
self.tableView.setModel(tableModel)
self.tableView.setStyleSheet('QTableView::item {border: 0px; padding: 5px; margin: 5px; color: yellow; '
'background-color: QLinearGradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #330055, stop: 1 #000000);} '
'QTableView::item:focus {border: 0px; background-color: darkred; color: yellow;}')
# VERY IMPORTANT!! Must pass the table view to the delegate, or it will not work!
newDelegate = CellDelegate(self.tableView)
self.tableView.setItemDelegate(newDelegate)

Related

QPalette and app.setStyleSheet() not impacting child Widget colors

I've got a pretty large PyQt5 application that I'm finally polishing with some colors. I've created a QPalette() and pass that to the app at launch. For the most part, it works (yay!). But not all of the child widgets are picking up the QPalette settings, and so I added a StyleSheet, but that again isn't working consistently. The only way I've been able to impact a widget color is by directly adding it when the widget is created, which is fine in something small.
The Main window:
class MyBigApplication(QMainWindow, QWidget):
def __init__(self):
super(MyBigApplication, self).__init__()
# ... load the various pieces, which include prompting user login and making some background connections.
# Build the GUI
def init_ui(self):
self.statusBar().showMessage('Welcome to MyBigApplication!')
self.grid_layout = QGridLayout()
# Initialize tab screen
self.tabs = QTabWidget()
self.tabs.setTabShape(QTabWidget.Triangular)
self.foo = fooTab(self, self.tabs)
self.bar = barTab(self, self.tabs)
self.baz = bazTab(self, self.tabs)
self.grid_layout.addWidget(self.tabs,0,1,4,1)
main_widget = QWidget()
main_widget.setLayout(self.grid_layout)
self.setCentralWidget(main_widget)
# Additional setup of menus and such
if __name__.endswith('__main__'):
app = QCoreApplication.instance()
while app is not None:
app.close()
app = QApplication(sys.argv)
app.setStyle('Fusion')
dark_palette = QPalette()
# Define some colors to get started
light_grey = QColor(243,243,243)
medium_grey = QColor(211,216,219)
dark_grey = QColor(52,59,64)
dark_palette.setColor(QPalette.Window, QColor(dark_grey))
dark_palette.setColor(QPalette.AlternateBase, QColor(medium_grey))
dark_palette.setColor(QPalette.Button, QColor(dark_grey))
dark_palette.setColor(QPalette.Base, QColor(25, 25, 25)) # almost black
dark_palette.setColor(QPalette.Link, QColor(green))
dark_palette.setColor(QPalette.Highlight, QColor(half_green))
dark_palette.setColor(QPalette.WindowText, QColor(light_grey))
dark_palette.setColor(QPalette.ToolTipBase, QColor(light_grey))
dark_palette.setColor(QPalette.ToolTipText, QColor(light_grey))
dark_palette.setColor(QPalette.Text, QColor(light_grey))
dark_palette.setColor(QPalette.ButtonText, QColor(light_grey))
dark_palette.setColor(QPalette.BrightText, Qt.red)
dark_palette.setColor(QPalette.HighlightedText, Qt.black)
app.setPalette(dark_palette)
app.setFont(QFont('Franklin Gothic Book', 9))
app.setStyleSheet("""
QMainWindow {
}
QToolTip {
color: #f3f3f3;
background-color: #2a82da;
border: 1px solid white;
}
QTableView { # This works
border: 1px solid #218a21
}
QPushButton { # And this works
padding: 10px 15px 10px 15px,
}
QPushButton:hover { # But this does not
background-color: red,
}
QTableView::item:alternate { # And this also does not
background-color: #d3d8db,
}
""")
execute = MyBigApplication()
sys.exit(app.exec_())
The fooTab includes tables of data:
class fooTab(QWidget):
def __init__(self, parent, tabs):
super(fooTab,self).__init__()
self.root = parent
self.tabs = tabs
def init_foo_one(self):
self.foo_tab = QWidget()
self.tabs.addTab(self.foo_tab, 'FOO')
tab_layout = QVBoxLayout()
foo_id_box = QGroupBox('FOO DATA')
clear_button = QPushButton('Clear Foo Data Table')
clear_button.clicked.connect(self.clear_foo_table)
# Set up the Table Model/View/Proxy
self.foo_id_table = QTableView()
self.foo_data_model = fooTableModel() # This is a QAbstractTableModel class
self.foo_data_model.setDataDict(data)
self.foo_id_table_columns = ['1','2','3','4']
self.foo_resizable_cols = [0,1,2,3,4]
self.foo_data_model.setDataHeader(self.foo_id_table_columns)
self.foo_table_proxy.setSourceModel(self.foo_data_model)
self.foo_id_table.setModel(self.foo_table_proxy)
self.foo_id_table.setSelectionBehavior(QAbstractItemView.SelectRows)
self.foo_id_table.setSortingEnabled(True)
self.foo_id_table.setWordWrap(False)
self.foo_id_table.setAlternatingRowColors(True)
# Create a layout for that box using a grid
foo_id_box_layout = QGridLayout()
# Add the widgets into the layout
foo_id_box_layout.addWidget(self.foo_id_table,0,0,1,5)
foo_id_box_layout.addWidget(clear_button,1,2,1,1)
# Setup the layout to be displayed in the box
foo_id_box.setLayout(foo_id_box_layout)
tab_layout.addWidget(foo_id_box)
self.foo_tab.setLayout(tab_layout)
The bazTab:
class BazTab(QWidget):
def __init__(self, parent, tabs):
super(BazTab,self).__init__()
self.root = parent
self.tabs = tabs
self.h1_font = QFont()
self.h1_font.setBold(True)
self.h1_font.setPointSize(16)
self.h2_font = QFont()
self.h2_font.setBold(False)
self.h2_font.setPointSize(12)
self.h3_font = QFont()
self.h3_font.setBold(True)
self.init_ui()
def init_ui(self):
self.component_tab = QScrollArea()
self.tabs.addTab(self.baz_tab, 'Baz')
self.tab_layout = QHBoxLayout()
self.component_tab.setLayout(self.tab_layout)
component_button_box = QGroupBox('Various Buttons')
component_button_layout = QVBoxLayout()
component_button_layout.setAlignment(Qt.AlignTop)
component_button_box.setLayout(component_button_layout)
self.tab_layout.addWidget(component_button_box)
first_button = QPushButton('Request #1')
first_button.clicked.connect(self.request_one)
component_button_layout.addWidget(first_button)
second_button = QPushButton('Request #2')
second_button.clicked.connect(self.request_two)
component_button_layout.addWidget(second_button)
# Several more buttons created in here
# None of these buttons look like the buttons in the info dialog (which have a color from the QPalette)
I can manually edit the QTableView to show alternating colors, only if I add it to each instance.
I cannot get some of the QPushButtons to change, even when I add each instance's styleSheet.
Using the QPalette has saved a ton, by not having to modify widget by widget. For the extra details, I'm fine to use the app.setStyleSheet except that it doesn't always work.
Is it me, or is this just the way it is?

How To implementing multi layer frame or widget in Qt?

How can I implement this in Qt, I am using PyQt and Qt Designer but confusing how to use layering like in the following image.
I want to first layer in index 0 to show the image or video,
then the second layer in index 2 is media control which can hide when no move from mouse,
and layer 3 in index 3 when change the volume in example
layer 4 in index 4 for notification etc.
is possible to do this in Qt?
There is a simple way to implement "layers" - you can add child widgets without any layout and resize/move them on resize event of host widget (using event filter). First layer can be organized with any layout as usual.
from PyQt5 import QtWidgets, QtCore, QtGui
from PyQt5.QtCore import Qt
class Layer(QtCore.QObject):
def __init__(self, host, child, alignment = Qt.AlignLeft, setWidth = False, setHeight = False, parent = None):
super().__init__(parent)
self._host = host
self._child = child
self._alignment = alignment
self._setWidth = setWidth
self._setHeight = setHeight
child.setParent(host)
host.installEventFilter(self)
def eventFilter(self, watched, event):
if watched != self._host or event.type() != QtCore.QEvent.Resize:
return False
hostSize = event.size()
childSize = self._child.sizeHint()
alignment = self._alignment
x = 0
y = 0
dWidth = max(0, hostSize.width() - childSize.width())
dHeight = max(0, hostSize.height() - childSize.height())
if alignment & Qt.AlignRight:
x = dWidth
elif alignment & Qt.AlignHCenter:
x = dWidth / 2
if alignment & Qt.AlignVCenter:
y = dHeight / 2
elif alignment & Qt.AlignBottom:
y = dHeight
width = hostSize.width() if self._setWidth else childSize.width()
height = hostSize.height() if self._setHeight else childSize.height()
self._child.setGeometry(x, y, width, height)
return False
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
widget = QtWidgets.QWidget()
label1 = QtWidgets.QLabel("right label")
label2 = QtWidgets.QLabel("bottom label")
layer1 = Layer(widget, label1, Qt.AlignRight)
layer2 = Layer(widget, label2, Qt.AlignBottom | Qt.AlignHCenter, True)
widget.show()
sys.exit(app.exec_())
This is one of the very few cases for which using a layout is not suggested, as the visible widgets are "floating" and should be possibly moved around.
The solution is to create a "container" widget that has all those controls as children.
Then, some widgets will need some repositioning and resizing (for instance, the control bar should always be on bottom and occupy the whole width), and that can be implemented in the resizeEvent().
from PyQt5 import QtCore, QtGui, QtWidgets
class ControlBar(QtWidgets.QFrame):
def __init__(self, parent):
super().__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
self.slider = QtWidgets.QSlider(QtCore.Qt.Horizontal)
layout.addWidget(self.slider)
buttons = QtWidgets.QHBoxLayout()
layout.addLayout(buttons)
buttons.addWidget(QtWidgets.QToolButton(text='play'))
buttons.addWidget(QtWidgets.QToolButton(text='stop'))
buttons.addStretch()
class VolumeWidget(QtWidgets.QFrame):
def __init__(self, parent):
super().__init__(parent)
layout = QtWidgets.QVBoxLayout(self)
layout.setContentsMargins(2, 2, 2, 0)
layout.setSpacing(1)
handle = QtWidgets.QFrame()
handle.setFixedHeight(12)
handle.setStyleSheet('''
QFrame {
border: 1px solid darkGray;
border-radius: 2px;
background: #aa646464;
}
''')
layout.addWidget(handle)
volumeLayout = QtWidgets.QHBoxLayout()
layout.addLayout(volumeLayout)
for i in range(4):
volumeLayout.addWidget(QtWidgets.QSlider(QtCore.Qt.Vertical))
def mousePressEvent(self, event):
if event.button() == QtCore.Qt.LeftButton:
self.startPos = event.pos()
def mouseMoveEvent(self, event):
if event.buttons() == QtCore.Qt.LeftButton:
delta = event.pos() - self.startPos
self.move(self.pos() + delta)
class Notification(QtWidgets.QFrame):
def __init__(self, parent):
super().__init__(parent)
layout = QtWidgets.QHBoxLayout(self)
self.label = QtWidgets.QLabel('Notification', alignment=QtCore.Qt.AlignCenter)
layout.addWidget(self.label)
class PlayerWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.video = QtWidgets.QLabel(self)
self.video.setPixmap(QtGui.QPixmap('movie.png'))
self.video.setScaledContents(True)
self.controlBar = ControlBar(self)
self.notification = Notification(self)
self.volumeWidget = VolumeWidget(self)
self.volumeWidget.move(30, 30)
self.setStyleSheet('''
VolumeWidget, ControlBar {
border: 1px outset darkGray;
border-radius: 4px;
background: #aad3d3d3;
}
VolumeWidget:hover, ControlBar:hover {
background: #d3d3d3;
}
Notification {
border: 1px outset darkGray;
border-radius: 4px;
background: #aa242424;
}
Notification QLabel {
color: white;
}
''')
def sizeHint(self):
if self.video.pixmap() and not self.video.pixmap().isNull():
return self.video.pixmap().size()
return QtCore.QSize(640, 480)
def resizeEvent(self, event):
# set the geometry of the "video"
videoRect = QtCore.QRect(
QtCore.QPoint(),
self.video.sizeHint().scaled(self.size(), QtCore.Qt.KeepAspectRatio))
videoRect.moveCenter(self.rect().center())
self.video.setGeometry(videoRect)
# control panel
controlHeight = self.controlBar.sizeHint().height()
controlRect = QtCore.QRect(0, self.height() - controlHeight,
self.width(), controlHeight)
self.controlBar.setGeometry(controlRect)
# notification
notificationWidth = max(self.notification.sizeHint().width(), self.width() * .6)
notificationRect = QtCore.QRect(
(self.width() - notificationWidth) * .5, 20,
notificationWidth, self.notification.sizeHint().height()
)
self.notification.setGeometry(notificationRect)
def paintEvent(self, event):
qp = QtGui.QPainter(self)
qp.fillRect(self.rect(), QtCore.Qt.black)
Note that in this simple case I only used an image. If you want to play video, you should use the Qt Multimedia module, and in order to correctly have transparency of controls a QGraphicsView with a QGraphicsVideoItem must be used.
In this case, PlayerWidget can directly be a subclass of QGraphicsView.

PyQt5 QGroupBox - how to display title in line with the top outside line for the QGroupBox?

This example:
# test1.py
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QRadioButton, \
QGroupBox, QButtonGroup
from PyQt5.Qt import Qt
def main():
app = QApplication([])
mainForm = MainForm()
mainForm.show()
app.exec()
# end function
class MainForm(QWidget):
def __init__(self):
super().__init__()
self.rdoRed = QRadioButton('Red')
self.rdoGreen = QRadioButton('Green')
self.rdoBlue = QRadioButton('Blue')
self.vblColor = QVBoxLayout()
self.vblColor.addWidget(self.rdoRed)
self.vblColor.addWidget(self.rdoGreen)
self.vblColor.addWidget(self.rdoBlue)
self.gbColor = QGroupBox('Choose Color')
self.gbColor.setStyleSheet('QGroupBox:title {'
'subcontrol-origin: padding; }')
self.gbColor.setLayout(self.vblColor)
self.vboxLayout = QVBoxLayout()
self.vboxLayout.addWidget(self.gbColor)
self.setLayout(self.vboxLayout)
# end function
# end class
if __name__ == '__main__':
main()
Renders like this on Ubuntu 18.04:
I'd like the Choose Color text currently just above the top of the QGroupBox boundary line to instead be in line with the top of the QGroupBox boundary, like the Qt docs show:
Notice how Package selection is in line with the top boundary line of the QGroupBox, I'd like to do the same with the Choose Color title in the example I have above.
Is this an operating system limitation and what I'm asking isn't possible? I'm using Ubuntu 18.04.
Or is there a setStyleSheet parameter I can pass in to achieve this? As you can see in the example above I attempted to set some style sheet properties to achieve this but I was unable to find such a property. Or is there some other means with which this can be achieved?
Try it:
from PyQt5.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout, QVBoxLayout, QPushButton, QRadioButton, \
QGroupBox, QButtonGroup
from PyQt5.Qt import *
class MainForm(QWidget):
def __init__(self):
super().__init__()
self.rdoRed = QRadioButton('Red')
self.rdoGreen = QRadioButton('Green')
self.rdoBlue = QRadioButton('Blue')
self.vblColor = QVBoxLayout()
self.vblColor.addWidget(self.rdoRed)
self.vblColor.addWidget(self.rdoGreen)
self.vblColor.addWidget(self.rdoBlue)
self.gbColor = QGroupBox('Choose Color')
self.gbColor.setStyleSheet('''
QGroupBox {
background-color: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1,
stop: 0 #E0E0E0, stop: 1 #FFFFFF);
border: 2px solid #999999;
border-radius: 5px;
margin-top: 2ex; /*leave space at the top for the title */
font-size: 13px;
color: black;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center; /* position at the top center */
padding: 0 3px;
font-size: 13px;
color: black;
}
''')
self.gbColor.setLayout(self.vblColor)
self.vboxLayout = QVBoxLayout()
self.vboxLayout.addWidget(self.gbColor)
self.setLayout(self.vboxLayout)
def main():
app = QApplication([])
mainForm = MainForm()
mainForm.show()
app.exec()
if __name__ == '__main__':
main()

How to build a flat groupbox in PyQt5?

I found the flat property of the QGroupbox Class in the Qt-docs, where it says:
A group box usually consists of a surrounding frame with a title at the top. If this property is enabled, only the top part of the frame is drawn in most styles; otherwise, the whole frame is drawn.
I'm trying to build such a flat QGroupBox, but it doesn't seem to work, as you can see in this picture. In the docs it also says:
Note: In some styles, flat and non-flat group boxes have similar representations and may not be as distinguishable as they are in other styles.
That leads me to the QStyle Class, which overstrains me a little, as I have no idea how to change the Style of the QGroupBox. I'm not even sure, if this is the real problem here. As you can see in my code below, I don't assign a specific style to the QGroupBox. So, it should use some sort of standard style, i guess...
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import QApplication, QWidget, QGroupBox,
QVBoxLayout, QLabel
class WidgetWithFlatGroupBox(QWidget):
def __init__(self):
QWidget.__init__(self, flags=Qt.Widget)
self.init_ui()
def init_ui(self):
self.setGeometry(300, 300, 300, 100)
self.setWindowTitle('PyQt5 Window')
layout = QVBoxLayout()
layout.addWidget(self.create_groupbox(), alignment=Qt.AlignCenter)
self.setLayout(layout)
def create_groupbox(self):
groupbox = QGroupBox('Flat Groupbox')
layout = QVBoxLayout()
label = QLabel('This Groupbox should be flat.')
layout.addWidget(label, alignment=Qt.AlignCenter)
groupbox.setLayout(layout)
groupbox.setFlat(True)
return groupbox
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = WidgetWithFlatGroupBox()
ex.show()
sys.exit(app.exec_())
I had a look at the internet, also here at stackoverflow of course, but were not able to find something useful. Is there anyone who knows how to use the flat property of the QGroupBox Class properly?
Sorry, but I do not understand how you need to do:
border: None;
border: 1px solid #76797C;
Try it:
import sys
from PyQt5.QtCore import Qt
from PyQt5.QtWidgets import (QApplication, QWidget, QGroupBox,
QVBoxLayout, QLabel, QPushButton)
class WidgetWithFlatGroupBox(QWidget):
def __init__(self):
QWidget.__init__(self, flags=Qt.Widget)
self.init_ui()
def init_ui(self):
self.setGeometry(300, 300, 300, 100)
self.setWindowTitle('PyQt5 Window')
layout = QVBoxLayout()
layout.addWidget(self.create_groupbox(), alignment=Qt.AlignCenter)
self.setLayout(layout)
def create_groupbox(self):
groupbox = QGroupBox('Flat Groupbox')
layout = QVBoxLayout()
label = QLabel('This Groupbox should be flat.')
button = QPushButton("This Button !!!")
button.setFlat(True)
layout.addWidget(label, alignment=Qt.AlignCenter)
layout.addWidget(button, alignment=Qt.AlignCenter)
groupbox.setLayout(layout)
# groupbox.setFlat(True)
return groupbox
style = '''
QGroupBox {
border: None; /*<----- None */
/* border: 1px solid #76797C; <----- 1px solid #76797C */
border-radius: 2px;
margin-top: 20px;
}
QGroupBox::title {
subcontrol-origin: margin;
subcontrol-position: top center;
padding-left: 10px;
padding-right: 10px;
padding-top: 10px;
}
'''
if __name__ == '__main__':
app = QApplication(sys.argv)
app.setStyleSheet(style)
ex = WidgetWithFlatGroupBox()
ex.show()
sys.exit(app.exec_())
self.groupBox_33.setFlat(True)

Is it possible to set the text of the QTableView corner button?

QTableView has a corner button, occupying the intersection between the horizontal and the vertical header. Clicking this will select all cells in the table. What I'm wondering is if it's possible to set this button's text, and if so, how?
I have implemented a working solution with PyQt 5.3, and it took surprisingly little code. My solution is based on code posted in this question at Qt Centre.
from PyQt5 import QtWidgets, QtCore
class TableView(QtWidgets.QTableView):
"""QTableView specialization that can e.g. paint the top left corner header.
"""
def __init__(self, nw_heading, parent):
super(TableView, self).__init__(parent)
self.__nw_heading = nw_heading
btn = self.findChild(QtWidgets.QAbstractButton)
btn.setText(self.__nw_heading)
btn.setToolTip('Toggle selecting all table cells')
btn.installEventFilter(self)
opt = QtWidgets.QStyleOptionHeader()
opt.text = btn.text()
s = QtCore.QSize(btn.style().sizeFromContents(
QtWidgets.QStyle.CT_HeaderSection, opt, QtCore.QSize(), btn).
expandedTo(QtWidgets.QApplication.globalStrut()))
if s.isValid():
self.verticalHeader().setMinimumWidth(s.width())
def eventFilter(self, obj, event):
if event.type() != QtCore.QEvent.Paint or not isinstance(
obj, QtWidgets.QAbstractButton):
return False
# Paint by hand (borrowed from QTableCornerButton)
opt = QtWidgets.QStyleOptionHeader()
opt.initFrom(obj)
styleState = QtWidgets.QStyle.State_None
if obj.isEnabled():
styleState |= QtWidgets.QStyle.State_Enabled
if obj.isActiveWindow():
styleState |= QtWidgets.QStyle.State_Active
if obj.isDown():
styleState |= QtWidgets.QStyle.State_Sunken
opt.state = styleState
opt.rect = obj.rect()
# This line is the only difference to QTableCornerButton
opt.text = obj.text()
opt.position = QtWidgets.QStyleOptionHeader.OnlyOneSection
painter = QtWidgets.QStylePainter(obj)
painter.drawControl(QtWidgets.QStyle.CE_Header, opt)
return True
You can add text on the corner button by finding a child from QTableWidget and add a QLabel to it by using the vertical layout as below.
QAbstractButton* button = qFindChild< QAbstractButton* >(TableWidget);
if (button)
{
QVBoxLayout* lay = new QVBoxLayout(button);
lay->setContentsMargins(0, 0, 0, 0);
QLabel* label = new QLabel("No");
label->setStyleSheet("QLabel {font-face: ArialMT; font-size: 10px; color: #FFFFFF; font-weight: bold; }""QToolTip { color: #ffffff; background-color: #000000; border: 1px #000000; }");
label->setAlignment(Qt::AlignCenter);
label->setToolTip("Text");
label->setContentsMargins(2, 2, 2, 2);
lay->addWidget(label);
}

Resources