4

the documentation of void QAbstractScrollArea::setViewportMargins(int left, int top, int right, int bottom) says:

Sets the margins around the scrolling area to left, top, right and bottom. This is useful for applications such as spreadsheets with "locked" rows and columns. The marginal space is is left blank; put widgets in the unused area. Note that this function is frequently called by QTreeView and QTableView, so margins must be implemented by QAbstractScrollArea subclasses. Also, if the subclasses are to be used in item views, they should not call this function.

First of all, I got confused with description itself. The function is not virtual so it is not the case when I should re-implement it to supply my margins. If I should call it than when, at what points? And if QTreeView is calling it internally with its own values than how our calls will cooperate? Looking at Qt sources I have found that QTreeView::updateGeometries() does call it with parameters (essentially) 0, headerHeight, 0, 0. So should I re-implement updateGeometries()?

Googling further I found that other people call setViewportMargins() from overridden resizeEvent(). So I also did so and this works BUT:

  1. I am wondering how this technique co-exist with internal QTreeView::updateGeometries() that calls setViewportMargins() with essentially hard-coded parameters (only headerHeight is changed to 0 if header is hidden)?
  2. Although it works the "unused area" appears above header. But to implement "locked" rows mentioned by documentation one needs this area to be under header

I have got unused area below header by overriding updateGeometries() and moving header() to the top (after calling QTreeView::updateGeometries();). But I am not sure that this is right thing to do.

So my question is: What way to implement "locked" rows is meant by setViewportMargins() documentation and how should they actually be implemented?

Note that I am aware about another way to implement frozen rows (or columns) - Frozen Column Example. But this is not exactly what I need because this technique hides first row(column) of main table(tree) widget and shows it in overlay (static) widget. In my case I need a different info in the area below header and main widget should be actually moved down to show all rows

mvidelgauz
  • 2,176
  • 1
  • 16
  • 23

1 Answers1

2

Actually that's very good question. Personally I dont think that setViewportMargins() is a way to go. By playing with viewportMargins only thing you can achieve is to 'shift' borders of where QTableView will draw attached model and then you have to deal with empty spaces around by drawing 'frozen' rows etc. Making those empty spaces 'owner-draw' you should always look for grid style, fonts size etc of the 'main grid' to make your 'frozen' rows/columns looks the same as main grid.

I tried several approaches to make it decently nice and convenient to write code around. At the end I end up with making widget which combines main grid (no headers), top and left grids WITH headers + corner widget. By doing that I've got pretty straight way to handle frozen parts with model filters on top of a main grid model as well as easy way to have splitters for 'frozen' parts etc..

evilruff
  • 3,947
  • 1
  • 15
  • 27
  • Thanks evilruff for your answer. I wasn't going to implement 'owner-drawn' stuff of course. Both documentation and sample plus own thinking are about placing another widget/view on that free space. And that what I did also. In my case main view is QTreeView and 'frozen' view is QTable view so I had to align row height only, which i one line of code. But the question still remains: what is the right way to create that empty space for extra widget. But I really like your idea to have that widget with header and hide main header instead of moving it up!!! – mvidelgauz Aug 05 '13 at 11:29
  • the way I proposed it also has a benefit that you are pretty flexible or layouts.. so you don't actually put widget on top of empty space but keep everything in pretty QT'ish way by combining controls in something more complex that you need.. – evilruff Aug 05 '13 at 12:25
  • Thanks evilruff. I'll keep your suggestion for a case when I need something more complex. But as currently I need just one simple row between QTreeView header and its content installing layout there is not (yet) necessarily. Just freeing space for that row should be enough. Actually, I already got what I wanted. But I am still interested what Qt designers had in mind and how setViewportMargins() is intent to be used maybe in a different situations – mvidelgauz Aug 05 '13 at 22:39
  • I was able to create the space by overriding the resize event in QTableView, but how do you put a table view control in that space? – Alex Feb 12 '14 at 15:15
  • If you have several grids implementing different sections, how do you keep them in sync? I.e. if somebody calls `setUniformRowHeights` on one of the views, it should be propagated to the left locked view too, how do you do that? Note, I tried handling dynamicPropertyChanged events, but they are only triggered when setProperty is called, not when the individual setter is. – Serge Nov 30 '15 at 17:12
  • @Serge Is question addressed to me or to @evilruff? In my case I am working not on a library (that someone can later call setUniformRowHeight), but on final application and yes I need to sync two grids when end user drags something in one of them. Did I understand you question correctly? – mvidelgauz Dec 02 '15 at 15:23
  • Yes @mvidelgaus, you got it right. I wonder if there is a good way to manage these synchronizations automatically - I opened a separate question for that: http://stackoverflow.com/questions/34004673/what-is-the-good-way-to-lock-freeze-columns-in-qtreeview – Serge Dec 02 '15 at 18:06