I would like to change text orientation of tablewidget's vertical header. I intend to change it from the default horizontal to vertical . Bottom to top.
1 Answers
Displaying vertical text in table headers
Unfortunately, QHeaderView
does not support custom delegates. However, we can subclass QHeaderView
and override paintSection
and sectionSizeFromContents
and paint the text vertically there. Note that we can reuse the same base implementation that takes various factors into account while rendering (e.g. if the mouse pointer is over the header, if the user is clicking on the header, ...) and get all of these considerations for free. Here is how I would implement such a class:
//a header view that renders text vertically
class VerticalHeaderView : public QHeaderView {
public:
explicit VerticalHeaderView(Qt::Orientation orientation, QWidget *parent = nullptr)
: QHeaderView(orientation, parent) {}
void paintSection(QPainter *painter, const QRect &rect,
int logicalIndex) const override {
QPointF rectCenter = QRectF(rect).center();
painter->save();
//rotate around rectCenter
painter->translate(rectCenter.x(), rectCenter.y());
painter->rotate(-90.0);
painter->translate(-rectCenter.x(), -rectCenter.y());
//apply the same transformation on the rect
QRect rectCopy = painter->worldTransform().mapRect(rect);
//use base paintSection method after applying required transformations
QHeaderView::paintSection(painter, rectCopy, logicalIndex);
painter->restore();
}
QSize sectionSizeFromContents(int logicalIndex) const override {
//get sizeHint from base sizeHint method
QSize val = QHeaderView::sectionSizeFromContents(logicalIndex);
//swap height and width
return QSize(val.height(), val.width());
}
};
To use the above class, we need to set it on our QTableView
/QTableWidget
using setVerticalHeader()
(it can be used as the table's horizontal header too, but this doesn't make sense in most of the cases). Here is a complete example that shows the above class in action:
#include <QtWidgets>
//a header view that renders text vertically
class VerticalHeaderView : public QHeaderView {
public:
explicit VerticalHeaderView(Qt::Orientation orientation, QWidget *parent = nullptr)
: QHeaderView(orientation, parent) {}
void paintSection(QPainter *painter, const QRect &rect,
int logicalIndex) const override {
QPointF rectCenter = QRectF(rect).center();
painter->save();
//rotate around rectCenter
painter->translate(rectCenter.x(), rectCenter.y());
painter->rotate(-90.0);
painter->translate(-rectCenter.x(), -rectCenter.y());
//apply the same transformation on the rect
QRect rectCopy = painter->worldTransform().mapRect(rect);
//use base paintSection method after applying required transformations
QHeaderView::paintSection(painter, rectCopy, logicalIndex);
painter->restore();
}
QSize sectionSizeFromContents(int logicalIndex) const override {
//get sizeHint from base sizeHint method
QSize val = QHeaderView::sectionSizeFromContents(logicalIndex);
//swap height and width
return QSize(val.height(), val.width());
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
//setup model with dummy data
QStandardItemModel model(0, 1);
for(int i=0; i<5; i++) {
model.appendRow(new QStandardItem(QStringLiteral("Lorem ipsum dolor sit "
"amet, consectetur adipiscing elit, sed do eiusmod tempor "
"incididunt ut labore et dolore magna aliqua. Ut enim ad "
"minim veniam, quis nostrud exercitation ullamco laboris "
"nisi ut aliquip ex ea commodo consequat.")));
model.setHeaderData(i, Qt::Vertical,
QDate::currentDate().toString("dd-MM-yyyy"),
Qt::DisplayRole);
model.setHeaderData(i, Qt::Vertical, Qt::AlignCenter, Qt::TextAlignmentRole);
}
//setup view
QTableView view;
VerticalHeaderView headerView(Qt::Vertical);
view.setVerticalHeader(&headerView); //set our custom headerview
view.verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
view.setModel(&model);
view.show();
return a.exec();
}
Displaying vertical text in table cells *
You can write a delegate class that renders text vertically. You would need to override paint
and sizeHint
and provide your code there. It is also possible to reuse the same base implementation after applying the required transformations. Here is how I would implement such a class:
//a delegate that renders text vertically
class VerticalTextDelegate : public QStyledItemDelegate {
public:
explicit VerticalTextDelegate(QObject *parent = nullptr)
: QStyledItemDelegate(parent){}
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QStyleOptionViewItem optionCopy = option;
QPointF rectCenter = QRectF(option.rect).center();
painter->save();
//rotate around rectCenter
painter->translate(rectCenter.x(), rectCenter.y());
painter->rotate(-90.0);
painter->translate(-rectCenter.x(), -rectCenter.y());
//apply the same transformation on the rect
optionCopy.rect = painter->worldTransform().mapRect(option.rect);
//use base paint method after applying required transformations
QStyledItemDelegate::paint(painter, optionCopy, index);
painter->restore();
}
virtual QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
//get sizeHint from base sizeHint method
QSize val = QStyledItemDelegate::sizeHint(option, index);
//swap height and width
return QSize(val.height(), val.width());
}
};
Here is a complete example that uses the above class:
#include <QtWidgets>
//a delegate that renders text vertically
class VerticalTextDelegate : public QStyledItemDelegate {
public:
explicit VerticalTextDelegate(QObject *parent = nullptr)
: QStyledItemDelegate(parent){}
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
QStyleOptionViewItem optionCopy = option;
QPointF rectCenter = QRectF(option.rect).center();
painter->save();
//rotate around rectCenter
painter->translate(rectCenter.x(), rectCenter.y());
painter->rotate(-90.0);
painter->translate(-rectCenter.x(), -rectCenter.y());
//apply the same transformation on the rect
optionCopy.rect = painter->worldTransform().mapRect(option.rect);
//use base paint method after applying required transformations
QStyledItemDelegate::paint(painter, optionCopy, index);
painter->restore();
}
virtual QSize sizeHint(const QStyleOptionViewItem &option,
const QModelIndex &index) const override {
//get sizeHint from base sizeHint method
QSize val = QStyledItemDelegate::sizeHint(option, index);
//swap height and width
return QSize(val.height(), val.width());
}
};
int main(int argc, char *argv[]) {
QApplication a(argc, argv);
//setup model with dummy data
QStandardItemModel model(0, 2);
for(int i=0; i<5; i++) {
model.appendRow({new QStandardItem(QDate::currentDate().toString("dd-MM-yyyy")),
new QStandardItem(QStringLiteral("Lorem ipsum dolor sit "
"amet, consectetur adipiscing elit, sed do eiusmod tempor "
"incididunt ut labore et dolore magna aliqua. Ut enim ad "
"minim veniam, quis nostrud exercitation ullamco laboris "
"nisi ut aliquip ex ea commodo consequat."))});
model.setData(model.index(i, 0), Qt::AlignCenter, Qt::TextAlignmentRole);
}
//setup view and delegate
QTableView view;
VerticalTextDelegate delegate;
view.verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
view.setItemDelegateForColumn(0, &delegate);
view.setModel(&model);
view.show();
return a.exec();
}
Apparently, I misinterpreted the question when I first answered it, but I am leaving this as a separate section as it might be useful for future readers.