PDA

View Full Version : QTableView moving horizontal header to bottom -- possible?



alketi
9th October 2014, 19:01
Hi all,

I have a QTableView and would like to have the headers on the LEFT and BOTTOM, such as you would see in an x/y plot.

I've looked through the various APIs and haven't found anything that seems to make this option available...

Does anyone know if this is possible?

wysota
9th October 2014, 22:53
Sure. Use QAbstractScrollArea::setViewportMargins() to make some space below the viewport and reimplement resizeEvent to position the headers where you want them.

alketi
10th October 2014, 17:53
Sure. Use QAbstractScrollArea::setViewportMargins() to make some space below the viewport and reimplement resizeEvent to position the headers where you want them.

Hi wysota,

Thank you. I see how to set the viewport margins to create some space, but can you provide a little more detail on how to "position" the headers?

Does positioning the headers mean:

1.) Hiding the current headers
2.) Creating new headers
3.) Putting the new headers into a custom layout to fill the viewport space?

If that's the process, how will the new headers align with the cell edges?

Or, is there a simpler way?

Thank you again.

wysota
11th October 2014, 02:25
Positioning the headers mean using setGeometry() calls on existing headers to change their position and size to fit your needs.

alketi
15th October 2014, 23:05
Positioning the headers mean using setGeometry() calls on existing headers to change their position and size to fit your needs.
Thanks wysota.

Inside my QTableView class, I'm trying:



void PlotTableView::resizeEvent(QResizeEvent *event)
{
QRect horizGeo = horizontalHeader()->geometry();
QRect vertGeo = verticalHeader()->geometry();
// Set the viewport margins for the left & bottom
setViewportMargins(vertGeo.width(), 0, 0, horizGeo.height());

autoSizeCells();

horizontalHeader()->setGeometry(QRect(200,0,horizGeo.width(),horizGeo. height()));

QTableView::resizeEvent(event);
}

With this, I don't see the horizontal header move at all. In the case above, I was just trying to slide it right by 200px.

Does the header view need to be subclassed for this to work??

wysota
16th October 2014, 07:51
You are calling the base class implementation thus it overrides whatever positioning you did yourself. If you change the order of calls then it should be fine.

alketi
17th October 2014, 04:40
wysota, thank you. Re-ordering the calls did work, though there are still issues.

The horizontal header is at the bottom, but as I resize the TableView (it's in a splitter), most of the time the horizontal headers stays put, but sometimes it back to the top of the viewport, and sometimes disappears altogether.

I suppose there are some other issues at play, but I have not figured out how to solve them yet.

alketi
6th January 2015, 00:08
wysota, I could really use a pointer in the right direction :)

My setup is the following:

1. Table view is inside of a horizontal/vertical splitter
2. Table view setup includes both resizeColumnsToContents() and resizeRowsToContents()

The behavior I'm seeing:

1. When I drag the splitter, the horizontal header jumps to the bottom and mostly stays there (sometimes flickering between the bottom and the top).
2. When I stop dragging the splitter, the horizontal header jumps back to the top.

My code:


void PlotTableView::resizeEvent(QResizeEvent *event)
{
QTableView::resizeEvent(event);

QRect horizGeo = horizontalHeader()->geometry();
QRect vertGeo = verticalHeader()->geometry();

// Set the viewport margins for the left & bottom
setViewportMargins(
vertGeo.width(),
horizGeo.height(),
0,
horizGeo.height());

// Move the horizontal header to the bottom
horizontalHeader()->setGeometry(QRect(
vertGeo.width(),
this->viewport()->geometry().height() + horizGeo.height(),
horizGeo.width(),
horizGeo.height()));

}

The culprit in question is QTableView::resizeEvent() -- which if commented out, results in the horizontal header staying nicely at the bottom. However, without it, the cells do not resize to fill the available space.

Any ideas what is missing to keep the header at the bottom, and not have it flicker and jump back to the top when the resize event finishes?

wysota
6th January 2015, 01:56
It would help if you provided a minimal compilable example reproducing the problem.

alketi
8th May 2015, 22:57
wysota, the problem of not being able to move the horizontal header to the bottom is caused by:



view.verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
view.horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);
- I want the rows/columns to both automatically fill the space, and I also want the horizontal header on the bottom.
- Do I need to manually implement the "setSectionResizeMode(QHeaderView::Stretch)" code in my application?

Here is the full duplication to see the issue (drag the window larger and smaller to see the flicker):


#include <QtWidgets>
#include <QTableView>

class PlotTableView : public QTableView
{

public:
PlotTableView(QWidget *parent = NULL) : QTableView(parent) { };
virtual ~PlotTableView() {}

protected:
virtual void resizeEvent(QResizeEvent *event)
{
QTableView::resizeEvent(event);

QRect verticalHeaderRect = verticalHeader()->geometry();
QRect horizontalHeaderRect = horizontalHeader()->geometry();

setViewportMargins(
verticalHeaderRect.width(), // left
horizontalHeaderRect.height(), // top
0, // right
horizontalHeaderRect.height()); // bottom

// Move the horizontal header to the bottom
horizontalHeader()->setGeometry(QRect(
verticalHeaderRect.width(),
this->viewport()->geometry().height() + horizontalHeaderRect.height(),
horizontalHeaderRect.width(),
horizontalHeaderRect.height()));
}
};

int main(int argc, char **argv) {
QApplication app(argc, argv);

QStandardItemModel model(4,4);

QMainWindow *window = new QMainWindow();
QWidget *topWidget = new QWidget(window);
QWidget *bottomRightWidget = new QWidget(window);
bottomRightWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);

QWidget * q = new QWidget();
window->setCentralWidget(q);

PlotTableView view;
view.setModel(&model);
view.resizeColumnsToContents();
view.resizeRowsToContents();
view.setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);

// These two lines cause the horizontalHeader()->setGeometry request to flicker and fail
view.verticalHeader()->setSectionResizeMode(QHeaderView::Stretch);
view.horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch);

QHBoxLayout *hBox = new QHBoxLayout();
hBox->addWidget(&view);
hBox->addWidget(bottomRightWidget);

QSplitter *hSplitter = new QSplitter(Qt::Horizontal);
hSplitter->addWidget(&view);
hSplitter->addWidget(bottomRightWidget);

QList <int> sizes;
sizes << 1 << 1;
hSplitter->setSizes(sizes);

QVBoxLayout *vBox = new QVBoxLayout();
vBox->addWidget(topWidget);
vBox->addWidget(hSplitter);

q->setLayout(vBox);

window->show();

return app.exec();
}

wysota
9th May 2015, 00:00
Are you sure this value:


this->viewport()->geometry().height() + horizontalHeaderRect.height()

is correct for the top edge of the horizontal header? Shouldn't it be - instead of +?

alketi
9th May 2015, 00:30
No, that's correct as is...

The horizontal header wants to move to the right by the width of the vertical header.
The horizontal header wants to move down by the height of the viewport + the height of the horizontal header (so it's below the viewport).

But, regardless, that's not the issue -- the issue is that horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch) apparently fights the desire to move the header.

You can run the the complete example provided to see the behavior.

Thank you for any assistance.