Results 1 to 14 of 14

Thread: Quick way for QWidget in QHeaderView's columns?

  1. #1
    Join Date
    Dec 2009
    Posts
    24
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Lightbulb Quick way for QWidget in QHeaderView's columns?

    I am tying to implement a custom widget for each column in QHeaderView.

    As the QHeaderView is an extension of the QAbstractItemView, the obvious choice would be to implement a custom delegate. But, for QHeaderView, the delegate is explicitely deleted in the source code, so that doesn't (?) seem a viable option.

    An other possible method that could work is to reimplement QHeaderView::paintSection() (and maybe even QHeaderView::paintEvent().

    My question is whether this latter method is the one to go, or am I overlooking an other obvious method? Some people (for example) are speaking about QWidgets in QHeaderView's constructors, but that doesn't seem to work well, especially if one wants QWidgets for every columnheader as in my case.

    Any suggestions?

  2. #2
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Quick way for QWidget in QHeaderView's columns?

    I would skip QHeaderView completely and use a completely custom widget possibly with a layout and position it on the view using setViewportMargins() and reimplementing resizeEvent() of the view to move the "header" around when size of the view changes.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  3. #3
    Join Date
    Dec 2009
    Posts
    24
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Lightbulb Re: Quick way for QWidget in QHeaderView's columns?

    Thanks for the answer Wysota. In the meantime, I have researched a bit more and implemented tree workable solutions which seem bit more simple. (Primarily because the number of columns should be changeable on the fly, and thereby the headers too.)

    FIRST and SECOND:
    Forget about QHeaderView, and use the main View. In Qt examples you can find how to lock rows/columns. So, the first way is the most simple one: just use the QAbstractItemView::setIndexWidget(). But this seems a convenience function, given the MVC/MVD paradigm. So in my second try I tried the same with the delegate:

    Qt Code:
    1. #include <QtGui>
    2.  
    3. class HeaderObject : public QWidget{
    4. public:
    5. HeaderObject(QWidget *parent = 0) : QWidget(parent){
    6. QComboBox *c = new QComboBox(this);
    7. QCheckBox *cb = new QCheckBox(this);
    8. c->addItem("test");
    9. c->addItem("test2");
    10. l->addWidget(c);
    11. l->addWidget(cb);
    12. setLayout(l);
    13. }
    14. };
    15.  
    16. class HeaderDelegate : public QStyledItemDelegate{
    17. public:
    18. HeaderDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {
    19. for(int i = 0; i < 5; i++){
    20. headerSections.insert(i,new HeaderObject(qobject_cast<QTableView*>(parent)->viewport()));
    21. headerSections[i]->hide();
    22. }
    23. }
    24.  
    25. void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const {
    26. if (index.row() == 0){
    27. qDebug() << "QRect: " << option.rect;
    28. headerSections[index.column()]->setGeometry(option.rect);
    29. headerSections[index.column()]->show();
    30. }
    31. }
    32.  
    33. QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const {
    34. qDebug() << "Asking for SIZEHINT: " << headerSections[0]->sizeHint();
    35. return headerSections[0]->sizeHint();
    36. }
    37.  
    38. private:
    39. QVector< QPointer <HeaderObject> > headerSections;
    40. };
    41.  
    42. class CustomModel : public QAbstractTableModel{
    43. public:
    44. CustomModel() : QAbstractTableModel(){}
    45.  
    46. int rowCount(const QModelIndex &parent = QModelIndex()) const{return 5;}
    47. int columnCount(const QModelIndex &parent = QModelIndex()) const {return 5;}
    48. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const{
    49. if (role == Qt::DisplayRole) return QVariant();
    50. return QVariant();
    51. }
    52.  
    53. private:
    54. };
    55.  
    56. int main(int argc, char *argv[])
    57. {
    58. QApplication a(argc, argv);
    59.  
    60. CustomModel *model = new CustomModel;
    61. QTableView *view = new QTableView();
    62. view->setModel(model);
    63. view->setItemDelegateForRow(0, new HeaderDelegate(view));
    64. view->resizeColumnsToContents();
    65. view->resizeRowsToContents();
    66. view->show();
    67. return a.exec();
    68. }
    To copy to clipboard, switch view to plain text mode 

    This surprisingly works very well. With some more tweaking it could be made nice. A proxy could be made to supply the widgets for the “header”-row, thereby holding to the MVD paradigm. But then I thought, wouldn't something similar also be possible with the QHeaderView? That's my third try, and also where the problems started to pop up. Here is the code:

    THIRD:
    Qt Code:
    1. #include <QtGui>
    2.  
    3. class HeaderObject : public QWidget{
    4. public:
    5. HeaderObject(QWidget *parent = 0) : QWidget(parent){
    6. QComboBox *c = new QComboBox(this);
    7. QCheckBox *cb = new QCheckBox(this);
    8. c->addItem("test");
    9. c->addItem("test2");
    10. l->addWidget(c);
    11. l->addWidget(cb);
    12. setLayout(l);
    13. }
    14. };
    15.  
    16. class CustomHeader : public QHeaderView{
    17. public:
    18. CustomHeader(QWidget *parent = 0):QHeaderView(Qt::Horizontal, parent){
    19.  
    20. for(int i = 0; i<5; i++){
    21. headerSections.insert(i,new HeaderObject(this));
    22. headerSections[i]->hide();
    23. }
    24. setFont(QFont("Helvetica [Cronyx]", 32));
    25. setMinimumSectionSize(headerSections[0]->minimumSizeHint().width());
    26. setDefaultSectionSize(headerSections[0]->minimumSizeHint().width());
    27. }
    28. protected:
    29. void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const {
    30.  
    31. if (!rect.isValid())
    32. return;
    33. qDebug() << logicalIndex;
    34. qDebug() << "QRect: " << rect << " AND OFFSET:" << offset();
    35. headerSections[logicalIndex]->setGeometry(rect);
    36. headerSections[logicalIndex]->show();
    37. }
    38.  
    39. private:
    40. QVector< QPointer <HeaderObject> > headerSections;
    41. };
    42.  
    43.  
    44. class CustomModel : public QAbstractTableModel{
    45. public:
    46. CustomModel() : QAbstractTableModel(){
    47. }
    48.  
    49. int rowCount(const QModelIndex &parent = QModelIndex()) const{return 5;}
    50. int columnCount(const QModelIndex &parent = QModelIndex()) const {return 5;}
    51. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const{
    52. if (role == Qt::DisplayRole) return QVariant();
    53. return QVariant();
    54. }
    55. };
    56.  
    57. int main(int argc, char *argv[])
    58. {
    59. QApplication a(argc, argv);
    60.  
    61. CustomModel *model = new CustomModel;
    62. QTableView *view = new QTableView();
    63. view->setModel(model);
    64. view->setHorizontalHeader(new CustomHeader(view));
    65. view->show();
    66. return a.exec();
    67. }
    To copy to clipboard, switch view to plain text mode 

    The main problem here is the horizontal QHeaderViews height. Guess what, you can not adjust it. Notice the setFont(). Up till now, that's the only way I have found to adjust the QHeaderView's height. I have tried setGeometry on both QHeaderView and it's viewport(), but none work. For some reason (which I can't figure out from the sourcecode) it always reverts to size 100x30. Only by explicitly catching viewport resize events did I manage to get the widgets to the required size (without the QFont hack), but the header remained the same size (so the widgets overlapped with the columns). This still seems to me the desirable way to go, but I do not see how to adjust the height. Any suggestions? You can also criticize my whole approach.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Quick way for QWidget in QHeaderView's columns?

    I think the last approach is wrong (especially the part with showing widgets inside reimplementation of paintSection). The first two are ok but I'd make the "header view" a separate widget from the main view.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  5. #5
    Join Date
    Jan 2009
    Location
    The Netherlands and Spain
    Posts
    150
    Thanks
    6
    Thanked 18 Times in 18 Posts
    Qt products
    Qt4
    Platforms
    Unix/X11

    Default Re: Quick way for QWidget in QHeaderView's columns?

    @Davor:
    Did you also try to use setSizePolicy() to allow the QHeaderView to change its height?
    Because, iirc, a 'horizontal' QHeaderView can, by default, only expand in horizontal direction.

  6. The following user says thank you to boudie for this useful post:

    Davor (14th January 2010)

  7. #6
    Join Date
    Dec 2009
    Posts
    24
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Quick way for QWidget in QHeaderView's columns?

    @ Boudie
    Thanks for the suggestion. It made me re-implement sizeHint() of QHeaderView, which made my third approach work:

    Qt Code:
    1. #include <QtGui>
    2.  
    3. class HeaderObject : public QWidget{
    4. public:
    5. HeaderObject(QWidget *parent = 0) : QWidget(parent){
    6. QComboBox *c = new QComboBox(this);
    7. QCheckBox *cb = new QCheckBox(this);
    8. c->addItem("test");
    9. c->addItem("test2");
    10. l->addWidget(c);
    11. l->addWidget(cb);
    12. setLayout(l);
    13. }
    14. };
    15.  
    16. class CustomHeader : public QHeaderView{
    17. public:
    18. CustomHeader(QWidget *parent = 0):QHeaderView(Qt::Horizontal, parent){
    19.  
    20. for(int i = 0; i<5; i++){
    21. headerSections.insert(i,new HeaderObject(this));
    22. headerSections[i]->hide();
    23. }
    24. //setFont(QFont("Helvetica [Cronyx]", 32));
    25. //setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
    26. setMinimumSectionSize(headerSections[0]->minimumSizeHint().width());
    27. setDefaultSectionSize(headerSections[0]->minimumSizeHint().width());
    28. }
    29. protected:
    30. void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const {
    31. if (!rect.isValid())
    32. return;
    33. //qDebug() << logicalIndex;
    34. //qDebug() << "QRect: " << rect << " AND OFFSET:" << offset();
    35. headerSections[logicalIndex]->setGeometry(rect);
    36. headerSections[logicalIndex]->show();
    37. }
    38.  
    39. QSize sizeHint() const {
    40. QSize s = size();
    41. s.setHeight(headerSections[0]->minimumSizeHint().height());
    42. return s;
    43. }
    44.  
    45. private:
    46. mutable QVector< QPointer <HeaderObject> > headerSections;
    47. };
    48.  
    49.  
    50. class CustomModel : public QAbstractTableModel{
    51. public:
    52. CustomModel() : QAbstractTableModel(){
    53. }
    54.  
    55. int rowCount(const QModelIndex &parent = QModelIndex()) const{return 5;}
    56. int columnCount(const QModelIndex &parent = QModelIndex()) const {return 5;}
    57. QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const{
    58. if (role == Qt::DisplayRole) return QVariant();
    59. return QVariant();
    60. }
    61.  
    62. private:
    63. };
    64.  
    65. int main(int argc, char *argv[])
    66. {
    67. QApplication a(argc, argv);
    68.  
    69. CustomModel *model = new CustomModel;
    70. QTableView *view = new QTableView();
    71. view->setModel(model);
    72. view->setHorizontalHeader(new CustomHeader(view));
    73. view->show();
    74. return a.exec();
    75. }
    To copy to clipboard, switch view to plain text mode 

    @Wysota: I don't see any other option than to re-implement the paint-sections (if one insists to subclass QHeaderView.) I my second approach I am also showing widgets from inside QItemDelegate's paint() member function. The delegate only allows widgets for editing, but not for showing. This seems logical, but in a sense also limiting.

  8. #7
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Quick way for QWidget in QHeaderView's columns?

    Quote Originally Posted by Davor View Post
    @Wysota: I don't see any other option than to re-implement the paint-sections (if one insists to subclass QHeaderView.)
    But not this way. You are simply covering the header with other widgets and at the same time you do it in a very wrong way.

    Do it properly - provide your own header widget but don't derive it from QHeaderView.

    Edit: A dirty example attached...
    Attached Files Attached Files
    Last edited by wysota; 11th January 2010 at 10:48.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  9. The following user says thank you to wysota for this useful post:

    Davor (14th January 2010)

  10. #8
    Join Date
    Dec 2009
    Posts
    24
    Thanks
    3
    Qt products
    Qt4
    Platforms
    Windows

    Default Re: Quick way for QWidget in QHeaderView's columns?

    Thanks for the example Wysota.

    Quote Originally Posted by wysota View Post
    But not this way. You are simply covering the header with other widgets and at the same time you do it in a very wrong way.
    It was just an example for one to start with. On the net, you can find many questions on this issue, but no examples.

    Furthermore, I don't see what's wrong with covering a widget with other widgets, as long as they remain in the hierarchy. Furthermore, the header isn't painting anything. A better way to do it would be to put them on the viewport:
    Qt Code:
    1. headerSections.insert(i,new HeaderObject(this.viewport()))
    To copy to clipboard, switch view to plain text mode 

    The paintSection() should arrange all the widgets on the viewport, and they would be in sync all the time with the columns. So basicly, it only paints once, when new columns are added. Other times, it just checks whether widget is in the correct position.
    Here a quick sample code:
    Qt Code:
    1. protected:
    2. void paintSection(QPainter *painter, const QRect &rect, int logicalIndex) const {
    3. if (headerSections[logicalIndex]->geometry() != rect) {
    4. qDebug() << "WRONG!";
    5. for(int i = 0; i < model()->columnCount(); i++){
    6. QRect newRect(sectionViewportPosition(i) ,rect.y(), sectionSize(i), rect.height());
    7. headerSections[i]->setGeometry(newRect);
    8. if (!headerSections[i]->isVisible()) headerSections[i]->show();
    9. }
    10. }
    11. }
    To copy to clipboard, switch view to plain text mode 

    Do it properly - provide your own header widget but don't derive it from QHeaderView.
    For one, that's a lot of work for something that is already there, which is (between other things) keeping the header columns in sync with the rest. For two, doesn't the Object oriented paradigm say to reuse the items, instead of to hide them? QHeaderView is there, like it or not.

  11. #9
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Quick way for QWidget in QHeaderView's columns?

    Quote Originally Posted by Davor View Post
    Furthermore, I don't see what's wrong with covering a widget with other widgets, as long as they remain in the hierarchy.
    If you do it in paintEvent() then it's terribly wrong. If not then it's still more logical to hide the header first and then replace it with something of your own.

    Furthermore, the header isn't painting anything. A better way to do it would be to put them on the viewport:
    Qt Code:
    1. headerSections.insert(i,new HeaderObject(this.viewport()))
    To copy to clipboard, switch view to plain text mode 
    No. The header is above the viewport, not inside it.

    The paintSection() should arrange all the widgets on the viewport, and they would be in sync all the time with the columns. So basicly, it only paints once, when new columns are added. Other times, it just checks whether widget is in the correct position.
    I think at least one of us doesn't understand how repainting widget in Qt works and what does QWidget::show() do. In essence it does something different that QWidget::render()
    For one, that's a lot of work for something that is already there,
    Not really. QHeaderView is a very stupid class, it's very easy to replace it.

    which is (between other things) keeping the header columns in sync with the rest.
    That's very easy. All the required signals are already there.

    For two, doesn't the Object oriented paradigm say to reuse the items, instead of to hide them? QHeaderView is there, like it or not.
    The thing is it is mostly a stub, not a real class. And you are not using the header view if you just put a widget over it.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  12. #10
    Join Date
    Oct 2007
    Posts
    11
    Thanks
    3
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Quick way for QWidget in QHeaderView's columns?

    Dear wysota!

    Could you please repost the attachment because I could download it but the archive seems to be malformed.

    Thanks in avance!

  13. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Quick way for QWidget in QHeaderView's columns?

    It's probably double-gzipped. I don't know why that happens but that's often the case with my attachments here.
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  14. #12
    Join Date
    Oct 2007
    Posts
    11
    Thanks
    3
    Thanked 3 Times in 2 Posts
    Qt products
    Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Symbian S60 Maemo/MeeGo

    Default Re: Quick way for QWidget in QHeaderView's columns?

    Thanks! You are right, it seems to be a gz file which contains a tar.gz.


    Added after 1 2 minutes:


    I have checked both code, and I would like to warm up this thread a little bit.

    I would like to show a QComboBox in a headerview. No not for sorting reasons, but for selecting the column's function in a CSV import dialog. The column count is dynamic, and the columnd width is user changable, and the table can be scrolled vertically.

    I have tried to improve the wysota's example. I have connected a lot of signals from the original headerview so now my widgets are properly resized, but I cannot deal anything with the scrolling. I do not want to get my tableview to the game, so from my point of view the first implementation seems to be more suitable even if it has technical problems. Do you have any suggestions about the topic?
    Last edited by martonmiklos; 19th April 2012 at 19:22.

  15. #13
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    33,359
    Thanks
    3
    Thanked 5,015 Times in 4,792 Posts
    Qt products
    Qt3 Qt4 Qt5 Qt/Embedded
    Platforms
    Unix/X11 Windows Android Maemo/MeeGo
    Wiki edits
    10

    Default Re: Quick way for QWidget in QHeaderView's columns?

    What do you mean regarding scrolling? What's the problem?
    Your biological and technological distinctiveness will be added to our own. Resistance is futile.

    Please ask Qt related questions on the forum and not using private messages or visitor messages.


  16. #14

    Default Re: Quick way for QWidget in QHeaderView's columns?

    This helped me a lot ... Thanks for the post..

Similar Threads

  1. Replies: 8
    Last Post: 14th August 2008, 16:48
  2. How to adjust the a QHeaderView's width
    By culgi in forum Qt Programming
    Replies: 2
    Last Post: 31st January 2008, 09:35
  3. Quick help on QProcess
    By devilj in forum Newbie
    Replies: 4
    Last Post: 17th July 2007, 23:16
  4. Quick Test Pro and Qt
    By tstankey in forum Newbie
    Replies: 1
    Last Post: 19th April 2007, 21:27
  5. Moving columns/hiding columns in QTreeView
    By yogeshm02 in forum Qt Programming
    Replies: 4
    Last Post: 14th March 2007, 17:22

Tags for this Thread

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
Digia, Qt and their respective logos are trademarks of Digia Plc in Finland and/or other countries worldwide.