Search code examples
qtqtablewidget

How to detect QTableWidget scroll source (code itself/user (wheel)/user (scrollbar))?


I'm writing a program using Qt 4.8 that displays a table (QTableWidget) filled with filenames and file's params. First an user adds files to the list and then clicks process. The code itself updates the contents of the table with simple progress description. I want the table by default to be scrolled automatically to show the last processed file and that code is ready.

If I want to scroll it by hand the widget is being scrolled automatically as soon as something changes moving the viewport to the last element. I want to be able to override the automated scroll if I detect that it was the user who wanted to change view.

This behavior can be seen in many terminal emulator programs. When there's a new line added the view is scrolled but when user forces the terminal to see some previous lines the terminal does not try to scroll down.

How could I do that?

Solution:

I created an object which filters event processed by my QTableWidget and QScrollBar embedded inside. If I spot the event that should turn off automatic scrolling I just set a flag and stop scrolling view if that flag is set.

Everything is implemented inside tableController class. Here are parts of three crucial methods.

bool tableController::eventFilter(QObject* object, QEvent* event)
{
  switch (event->type())
  {
    case QEvent::KeyPress:
    case QEvent::KeyRelease:
    case QEvent::Wheel:
    case QEvent::MouseButtonDblClick:
    case QEvent::MouseButtonPress:
    case QEvent::MouseButtonRelease:
      _autoScrollEnabled = false;
    default:
      break;
  }
  return QObject::eventFilter(object, event);
}

void tableController::changeFile(int idx)
{
  [...]
  if (_autoScrollEnabled)
  {
    QTableWidgetItem* s = _table.item(_engine.getLastProcessed(), 1);
    _table.scrollToItem(s);
  }
  [...]
}

void tableController::tableController()
{
   [...]
   _autoScrollEnabled = true;
   _table.installEventFilter(this);
   _table.verticalTableScrollbar()->installEventFilter(this);
   [...]
}

Thanks for all the help. I hope somebody will find it useful :)


Solution

  • Subclass QTableWidget and overload its wheelEvent. You can use the parameters of the supplied QWheelEvent object in order to determine if the user scrolled up or down.

    Then use a simple boolean flag which is set (or reset) in your wheelEvent override. The method which is responsible for calling scrollToBottom() should then consider this boolean flag.

    You will have to find a way to figure out when to set or reset that flag, e.g. always set it when the user scrolls up and reset it when the user scrolls down and the currently displayed area is at the bottom.