Results 1 to 11 of 11

Thread: QListView and column moving

  1. #1
    Join Date
    Jan 2006
    Location
    Sofia, Bulgaria
    Posts
    24
    Thanks
    1
    Qt products
    Qt3
    Platforms
    Unix/X11

    Default QListView and column moving

    Hi there,
    I don't know how to import the thread from your old site(qtforum.org), so I'm asking here:
    Is there a way to move columns of a list view programatically?
    Basically, here's what I do:
    I change the list view header's columns with
    Qt Code:
    1. list_view->header()->moveColumn( column_no, to_idx );
    To copy to clipboard, switch view to plain text mode 
    but that does not change the contents.
    Having looked through the QT sources, the ListView connects to the moved() signal emitted from the QHeader and in the slot that handles the signal triggerUpdate() is called.
    I have tried this myself, e.g.
    Qt Code:
    1. list_view->header()->moveColumn( column_no, to_idx );
    2. list_view->triggerUpdate();
    To copy to clipboard, switch view to plain text mode 
    No success, though. At some reason, the list view does not want to repaint its contents.
    So, how the hell can i swap/move columns without iterating through all the items and swapping text as a mad one (that is stupid and slow enough, i want the operation to be faster).
    Pleeeeeeease help!

  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: QListView and column moving

    Try emitting indexChange(...) from QHeader.

    void QHeader::indexChange ( int section, int fromIndex, int toIndex ) [signal]
    This signal is emitted when the user moves section section from index position fromIndex, to index position toIndex.

  3. #3
    Join Date
    Jan 2006
    Location
    Sofia, Bulgaria
    Posts
    24
    Thanks
    1
    Qt products
    Qt3
    Platforms
    Unix/X11

    Default Re: QListView and column moving

    Ok, HOW to do that? How to emit a signal from another class?
    (Sorry for the might-be silly question, though, but the QListView has its own header and I do not know how to make it emit the wanted signal)
    Last edited by gadnio; 5th January 2006 at 15:35.

  4. #4
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView and column moving

    Quote Originally Posted by gadnio
    So, how the hell can i swap/move columns without iterating through all the items and swapping text as a mad one (that is stupid and slow enough, i want the operation to be faster).
    First of all, try disabling updates (using QWidget::setUpdatesEnabled()) while you switch columns. This should reduce the flicker.

    Another way you could try requires subclassing QListViewItem. You will also need a mapping that maps logical columns (those which you use in your program) to physical ones (those that are visible in the view). This map should be shared among all items.

    Now YourViewItem::paintCell() should be somthing like this:
    Qt Code:
    1. void YourViewItem::paintCell ( QPainter * p, const QColorGroup& cg, int column, int width, int align )
    2. {
    3. QListViewItem::paintCell( p, cg, _map[ column ], width, align );
    4. }
    To copy to clipboard, switch view to plain text mode 
    Probably you will have to change other methods too (AFAIR similar solution was discussed at QtForum).

    Now if you want to switch columns, all you have to do is to update the map and redraw QListView contents.

    You could also experiment with drag & drop mechanism (something tells me that you can use it to switch columns, but I'm not sure if it works).
    Last edited by jacek; 5th January 2006 at 15:42.

  5. #5
    Join Date
    Jan 2006
    Location
    Sofia, Bulgaria
    Posts
    24
    Thanks
    1
    Qt products
    Qt3
    Platforms
    Unix/X11

    Default Re: QListView and column moving

    Okay, the best thing to do here is to swap the text of the columns as a mad man...
    WHY the hell is it so hard? I have examined most of the QHeader's source and the QListView's source and didn't find a reason why
    Qt Code:
    1. list_view->moveSection( section, pos );
    2. list_view->triggerUpdate();
    To copy to clipboard, switch view to plain text mode 
    does not work! No matter what I do, I cannot change this behaviour. Any ideas? (The map example does not work, though, it gets very messy when the user starts to move the sections, etc. and the QHeader does not handle drag and drop, but change the columns by doing some strange things in responce to mouse events). Although reviewed most of that things, didn't find a real reason why the above code does not work.
    Any help will be appreciated.

  6. #6
    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: QListView and column moving

    Quote Originally Posted by gadnio
    Ok, HOW to do that? How to emit a signal from another class?
    Subclass QHeader. Of course you'll have to attach the new header class to the list view for it to work, probably also by subclassing. QListView should be able to drag&drop columns. You could look at the code which does that to see how it is done internally. Or see what is conencted to that indexChange() signal and call that method directly.

  7. #7
    Join Date
    Jan 2006
    Location
    Sofia, Bulgaria
    Posts
    24
    Thanks
    1
    Qt products
    Qt3
    Platforms
    Unix/X11

    Default Re: QListView and column moving

    I can subclass QHeader and make moveSection to emit the signal when done, but setting it to the list view -- that's the problem. I cannot access the QListViewPrivate class which holds the header (the QListView itself has some private members attatched to the QHeader's signals. And, some code from the QListView itself:
    Qt Code:
    1. //this is from QHeader::mouseReleaseEvent
    2. void QHeader::mouseReleaseEvent( QMouseEvent *e )
    3. {
    4. if ( e->button() != LeftButton )
    5. return;
    6. int oldOldHandleIdx = oldHandleIdx;
    7. State oldState = state;
    8. state = Idle;
    9. switch ( oldState ) {
    10. case Pressed: {
    11. int section = d->i2s[handleIdx];
    12. emit released( section );
    13. if ( sRect( handleIdx ).contains( e->pos() ) ) {
    14. oldHandleIdx = handleIdx;
    15. emit sectionClicked( handleIdx );
    16. emit clicked( section );
    17. } else {
    18. handleIdx = oldHandleIdx;
    19. }
    20. repaint(sRect( handleIdx ), FALSE);
    21. if ( oldOldHandleIdx != handleIdx )
    22. repaint(sRect(oldOldHandleIdx ), FALSE );
    23. } break;
    24. case Sliding: {
    25. int c = orient == Horizontal ? e->pos().x() : e->pos().y();
    26. c += offset();
    27. if ( reverse() )
    28. c = d->lastPos - c;
    29. handleColumnResize( handleIdx, c - d->pressDelta, TRUE );
    30. } break;
    31. case Moving: {
    32. #ifndef QT_NO_CURSOR
    33. unsetCursor();
    34. #endif
    35. int section = d->i2s[handleIdx];
    36. if ( handleIdx != moveToIdx && moveToIdx != -1 ) {
    37. moveSection( section, moveToIdx );
    38. handleIdx = oldHandleIdx;
    39. //---------------------------------------------------------------------
    40. // looks like all we do here is call moveSection and then emit signals and everyone is happy
    41. //---------------------------------------------------------------------
    42. emit moved( handleIdx, moveToIdx );
    43. emit indexChange( section, handleIdx, moveToIdx );
    44. emit released( section );
    45. repaint(); // a bit overkill, but removes the handle as well
    46. } else {
    47. if ( sRect( handleIdx).contains( e->pos() ) ) {
    48. oldHandleIdx = handleIdx;
    49. emit released( section );
    50. emit sectionClicked( handleIdx );
    51. emit clicked( section );
    52. } else {
    53. handleIdx = oldHandleIdx;
    54. }
    55. repaint(sRect( handleIdx ), FALSE );
    56. if(oldOldHandleIdx != handleIdx)
    57. repaint(sRect(oldOldHandleIdx ), FALSE );
    58. }
    59. break;
    60. }
    61. case Blocked:
    62. //nothing
    63. break;
    64. default:
    65. // empty, probably. Idle, at any rate.
    66. break;
    67. }
    68. }
    69. //-----------------------------------------------------------------------------
    70. //this is inside the QListView's constructor
    71. //-----------------------------------------------------------------------------
    72.  
    73. connect( d->h, SIGNAL(sizeChange(int,int,int)),
    74. this, SLOT(handleSizeChange(int,int,int)) );
    75. connect( d->h, SIGNAL(indexChange(int,int,int)),
    76. this, SLOT(handleIndexChange()) );
    77. connect( d->h, SIGNAL(sectionClicked(int)),
    78. this, SLOT(changeSortColumn(int)) );
    79. connect( d->h, SIGNAL(sectionHandleDoubleClicked(int)),
    80. this, SLOT(adjustColumn(int)) );
    81. connect( horizontalScrollBar(), SIGNAL(sliderMoved(int)),
    82. d->h, SLOT(setOffset(int)) );
    83. connect( horizontalScrollBar(), SIGNAL(valueChanged(int)),
    84. d->h, SLOT(setOffset(int)) );
    85.  
    86. //-----------------------------------------------------------------------------
    87. //this is the handleIndexChange() method
    88. //-----------------------------------------------------------------------------
    89. /*!
    90.   \internal
    91.   Handles renaming when sections are being swapped by the user.
    92. */
    93.  
    94. void QListView::handleIndexChange()
    95. {
    96. if ( isRenaming() ) {
    97. if ( d->defRenameAction == QListView::Reject ) {
    98. currentItem()->cancelRename( currentItem()->renameCol );
    99. } else {
    100. currentItem()->okRename( currentItem()->renameCol );
    101. }
    102. }
    103. triggerUpdate();
    104. }
    To copy to clipboard, switch view to plain text mode 
    Apparently, all it does is some checks that I know in my case are all true (they PASS when checked by hand) and calls triggerUpdate(). When I call triggerUpdate after the column has moved, nothing happens.

  8. #8
    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: QListView and column moving

    You could just copy this column moving code to your own (public?) method and attach the header to the list view.

    How to do it (three ways):
    • Subclass QListView and create a copy of your own header instead of QHeader.
    • Use QObject::child() to grab a pointer to the header and modify it
    • <hackish>Use header() method of QListView and cast it to (QHeader*) to remove the const constraint. I don't know if it'll work, but you might try it.</hackish>


    Whichever way you use, make sure to connect all the proper signals and slots.

  9. #9
    Join Date
    Jan 2006
    Location
    Sofia, Bulgaria
    Posts
    24
    Thanks
    1
    Qt products
    Qt3
    Platforms
    Unix/X11

    Default Re: QListView and column moving

    Can you help me get working the following sollution to the problem?
    Can it be done this way?
    Qt Code:
    1. //-----------------------------------------------------------------------------
    2. void nListView::move_column( int column_index, int position )
    3. {
    4. QHeader * h = header();
    5. QPoint start_pos( h->sectionRect( column_index ).top() + 1, h->sectionRect( column_index ).left() + 1 );
    6. QPoint end_pos( h->sectionRect( h->sectionAt( position ) ).top() + 1, h->sectionRect( h->sectionAt( position ) ).left() + 1 );
    7. start_pos = header()->mapFromGlobal( mapToGlobal( start_pos ) );
    8. end_pos = header()->mapFromGlobal( mapToGlobal( end_pos ) );
    9. QMouseEvent * mouse_event = new QMouseEvent( QEvent::MouseButtonPress, start_pos, LeftButton, NoButton );
    10. qApp->postEvent( h, mouse_event );
    11. mouse_event = new QMouseEvent( QEvent::MouseMove, end_pos, LeftButton, LeftButton );
    12. qApp->postEvent( h, mouse_event );
    13. mouse_event = new QMouseEvent( QEvent::MouseButtonRelease, end_pos, NoButton, LeftButton );
    14. qApp->postEvent( h, mouse_event );
    15. // int old_pos = header()->mapToIndex( column_index );
    16. // header()->moveSection( column_index, position );
    17. // column_moved( column_index, old_pos, position );
    18. // triggerUpdate();
    19. }
    To copy to clipboard, switch view to plain text mode 

  10. #10
    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: QListView and column moving

    The funny thing is that calling triggerUpdate() should be sufficient.

  11. #11
    Join Date
    Jan 2006
    Location
    Warsaw, Poland
    Posts
    5,372
    Thanks
    28
    Thanked 976 Times in 912 Posts
    Qt products
    Qt3 Qt4
    Platforms
    Unix/X11 Windows

    Default Re: QListView and column moving

    The solution is far more easier than I thought (tested under Qt 3.3.5 on PLD Linux):
    Qt Code:
    1. #include <qapplication.h>
    2. #include <qheader.h>
    3. #include <qlistview.h>
    4. #include <qpushbutton.h>
    5. #include <qvbox.h>
    6.  
    7. class Test : public QVBox
    8. {
    9. Q_OBJECT
    10. public:
    11. Test() : idx( 2 )
    12. {
    13. _lv = new QListView( this );
    14. _lv->addColumn( "A" );
    15. _lv->addColumn( "B" );
    16. _lv->addColumn( "C" );
    17.  
    18. new QListViewItem( _lv, "a1", "b1", "c1" );
    19. new QListViewItem( _lv, "a2", "b2", "c2" );
    20. new QListViewItem( _lv, "a3", "b3", "c3" );
    21.  
    22. QPushButton *pb = new QPushButton( "Switch", this );
    23. connect( pb, SIGNAL( clicked() ), this, SLOT( switchColumns() ) );
    24. }
    25.  
    26. private slots:
    27. void switchColumns()
    28. {
    29. _lv->header()->moveSection( 0, idx );
    30. _lv->triggerUpdate();
    31. _lv->header()->update();
    32.  
    33. idx = 2 - idx;
    34. }
    35.  
    36. private:
    37. QListView *_lv;
    38. int idx;
    39. };
    40.  
    41. int main( int argc, char **argv )
    42. {
    43. QApplication app( argc, argv );
    44.  
    45. Test mw;
    46.  
    47. app.setMainWidget( &mw );
    48. mw.show();
    49.  
    50. return app.exec();
    51. }
    52.  
    53. #include "main.moc"
    To copy to clipboard, switch view to plain text mode 

Similar Threads

  1. Subclass QListView to show two colums in one
    By Mookie in forum Qt Programming
    Replies: 2
    Last Post: 23rd June 2007, 03:12
  2. Replies: 0
    Last Post: 10th November 2006, 14:46
  3. Editable QListView Column ??
    By darpan in forum Qt Programming
    Replies: 1
    Last Post: 3rd May 2006, 19:55
  4. hidden QListView column suddenly visible
    By edb in forum Qt Programming
    Replies: 10
    Last Post: 27th January 2006, 09:00

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.