1
votes

enter image description here

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
You may be interested in this: qt-apps.org/content/show.php/…drescherjm
Works great. Had to do a little upgrade from qt 4 to qt 5James Njoroge

1 Answers

2
votes

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:

screenshot

#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:

screenshot

#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.