How to Set the Padding of Qtableview Cells Through CSS

How to set the padding of QTableView cells through CSS?

I know this is an old question but I've been struggling with this recently.

I found out that by setting

tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);

the padding set in your CSS will then be applied to the top and bottom of the cell, too!

Cell spacing and focus rectangle in QTableView

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)

QTableView row styling

You don't need stylesheet to do this, styleshhet is not so powerful to do all things that developer wants. Use more powerful thing - delegate. I will show you main idea and working example. Header:

#ifndef ITEMDELEGATEPAINT_H
#define ITEMDELEGATEPAINT_H

#include <QStyledItemDelegate>

class ItemDelegatePaint : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit ItemDelegatePaint(QObject *parent = 0);
ItemDelegatePaint(const QString &txt, QObject *parent = 0);

protected:
void paint( QPainter *painter,
const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
QSize sizeHint( const QStyleOptionViewItem &option,
const QModelIndex &index ) const;
QWidget* createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const;
void setEditorData(QWidget * editor, const QModelIndex & index) const;
void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const;
void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const;

signals:

public slots:

};

#endif // ITEMDELEGATEPAINT_H

There are many methods here but I will show you only paint, because it is the most important thing for you. Description about another methods you can find in web

cpp:

void ItemDelegatePaint::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QString txt = index.model()->data( index, Qt::DisplayRole ).toString();

if(index.row() == 0)//green row
painter->fillRect(option.rect,QColor(0,255,0));
else
if(index.row() == 1)//blue row
painter->fillRect(option.rect,QColor(0,0,255));
else
if(index.row() == 2)//red row
painter->fillRect(option.rect,QColor(255,0,0));
//and so on

if( option.state & QStyle::State_Selected )//we need this to show selection
{
painter->fillRect( option.rect, option.palette.highlight() );
}

QStyledItemDelegate::paint(painter,option,index);//standard processing
}

Usage:

ui->tableView->setItemDelegate(new ItemDelegatePaint);

Result:

Sample Image

How can I style the cells of a QTableWidget in PyQt5?

I answer the question myself. I found the solution with the help of the comment of @musicamante above.

Setting the margin to 0 did the trick:

view.setStyleSheet("QTableWidget::item {border: 0px; padding: 5px;}")

Now the cells have a padding of 5px.

border and text qss settings at QTableView

Note : I haven't verified, these are just suggestions to try, please upload the output if needed

1 - What do you mean by "it changed for all QHeaderView not only QHeaderView's Text"?

Maybe you expected to set margin only to the headerview's content (text) : in that case use the padding not margin.

QHeaderView::section{
/* your style */
padding-bottom:5px;
padding-top:5px;
}

2 - Every row has a right ,left even top border. I dont want that.

QTableView {
/* sone additional style */
gridline-color: cyan
background-color: cyan
}

QTableView::item
{
border-style: none;
border-bottom: 1px solid rgb(0,0,0);
}

I would try to use the border-style (set to none) as you did in QHeaderView's style.

Edit : You certainly must disable the showgrid's option of your QTableView by code to make it a working solution

tableView.setShowGrid(false);

Adjust indents in QTableWidget cells and header items

For the indents, the QSS Reference suggests that it should be possible to use the QTableWidget::item and QHeaderView::section selectors:

self.tableWidget.setStyleSheet("""
QTableWidget::item {padding-left: 5px; border: 0px}
""")

self.tableWidget.horizontalHeader().setStyleSheet("""
QHeaderView::section {padding-left: 5px; border: 0px}
""")

However, I tried all the various combinations of padding, margin and border settings, and found that they either don't work at all, or have weird and ugly side-effects. After looking at several similar questions on SO and elsewhere, it seems that the exact behaviour of these stylesheet settings depends on what plaform you are on and/or what widget-style you are using. Hopefully they will work okay for you, but don't be surprised if you find a few glitches.

If the stylesheet solution doesn't work out, most people use a custom item-delegate. This usually involves reimplementing the paint method. However, an alternative approach would be to reimplement the displayText method and pad the returned text with spaces. This does not affect the underlying data at all, and gives completely equivalent results in a much simpler way. It is also quite simple to reimplement the createEditor method so that the left margin is adjusted when editing cells. The complete custom item-delegate would then look like this:

class PaddingDelegate(QtWidgets.QStyledItemDelegate):
def __init__(self, padding=1, parent=None):
super(PaddingDelegate, self).__init__(parent)
self._padding = ' ' * max(1, padding)

def displayText(self, text, locale):
return self._padding + text

def createEditor(self, parent, option, index):
editor = super().createEditor(parent, option, index)
margins = editor.textMargins()
padding = editor.fontMetrics().width(self._padding) + 1
margins.setLeft(margins.left() + padding)
editor.setTextMargins(margins)
return editor

and it can be used like this:

self.delegate = PaddingDelegate()
self.tableWidget.setItemDelegate(self.delegate)

The final piece of the puzzle is the indent for the header items. For this, it would seem simplest to just add some spaces to the label text:

self.tableWidget.setHorizontalHeaderLabels([' col_1', ' col_2'])

And the alignment of the header labels can be set like this:

self.tableWidget.horizontalHeader().setDefaultAlignment(
QtCore.Qt.AlignLeft | QtCore.Qt.AlignVCenter)

QTableView/QTableWidget grid stylesheet - grid line width

The trick is border-style: none; in QHeaderView::section after witch border-left, border-right, border-top and border-bottom starts working. Correct style for QHeaderView::section should be

QHeaderView::section {
background-color: #646464;
padding: 4px;
font-size: 14pt;
border-style: none;
border-bottom: 1px solid #fffff8;
border-right: 1px solid #fffff8;
}

QHeaderView::section:horizontal
{
border-top: 1px solid #fffff8;
}

QHeaderView::section:vertical
{
border-left: 1px solid #fffff8;
}


Related Topics



Leave a reply



Submit