0
votes

you might be able to tell that I'm pretty new to QT...

My program contains a window with several Widgets in a QGridLayout. Some of these Widgets have a layout and child widgets themselves. Pressing the Tab key moves the focus like I expect it to, in the order I created the widgets.

Problems occur when a widget changes it's content (I do that by deleting all child widgets and then constructing new ones.) If I do that, new widgets are moved to the end of the tab chain (that indicates to me, that tab order is kind of global for a window). I have tried to use QWidget::setTabOrder() to reorder all widgets (I tried both, setting tab order for only the contends of the main window and setting it for the children too) but the actual order doesn't change. I did this by emitting a signal when the contend of a widget changes and connecting that to a slot on my main Window. I think I understand the way the setTabOrder() function should work. I do something similar to this:

QWidget* a = firstWidget;
QWidget* b = secondWidget;
QWidget::setTabOrder(a,b);
for (int i = 0; i < widgets.size(); ++i) {
  a = b;
  b = widgets[i];
  QWidget::setTabOrder(a,b);
}

Is there anything special one has to do when changing the tab order?

I also tried to reimplement focusNextPrevChild(bool next) and focusInEvent(QFocusEvent* e) similar to what can be found at this site. 1

I managed to mess up tab order a lot more like this... is this approach a step in the right direction?

I'm sorry if this is something simple that I managed to miss, but I'm struggling for a while now and I can't find a solution. Any help is very appreciated.

1
I'm not sure if this solves the problem, but if firstWidget is the same as widgets[0], your loop should start at 1Tim Meyer
How is widgets filled and which widgets does it contain? Only the children of the widget which changed its content, or all widgets of the master layout?Tim Meyer
You have some is deleted widgets, and some new widgets. For example you had 1, 2, 3, 4, 5 widgets, but next you have 1, 2, 5 widgets and 6, 7 is new widgets. What if set tab order as 1, 2, 6, 7, 5?synacker
@TimMeyer I tried both, and also pulling the widgets from the layout. (I used QGridLayout::itemAtPosition() and then QLayoutItem::Widget(), and the same for the children.)R. Edward
@Milovidov That is what i try to do but I cant get it to work.R. Edward

1 Answers

1
votes

I had the same problem, and resolved it using the info Tim Meyer provided in the comments.

Tab order is not hierarchical - calling setTabOrder on a parent widget that doesn't accept focus will not cause the focus to be passed to the child. You will need to fetch the appropriate children from the widget and set the order on them

In my case, a dynamically constructed QTreeWidget contained editable widgets, and I needed to reset setTabOrder to account for widgets being created out-of-order.

The following code is (most) of the implementation

// Perform a depth-first gather of the child widgets of this item
void gatherTabWidgets( QObject* item, QWidgetList& tabWidgets )
{
  if (item->isWidgetType())
  {
    QWidget* itemWidget = static_cast<QWidget*>(item);
    if (itemWidget->focusPolicy() & Qt::TabFocus)
      tabWidgets.push_back( itemWidget );
  }
  const QObjectList& children = item->children();
  for (QObjectList::const_iterator itr = children.begin(); itr != children.end(); itr++)
  {
    gatherTabWidgets( const_cast<QObject*>(*itr), tabWidgets );
  }
}

// Perform a depth-first gather of the child items widgets;
void gatherTabWidgets( QTreeWidgetItem* item, QWidgetList& tabWidgets )
{
  QWidget* itemWidget = fetchWidgetForItem( item );
  gatherTabWidgets( itemWidget, tabWidgets );

  for (int i = 0; i < item->childCount(); i++)
  {
    gatherTabWidgets( item->child( i ), tabWidgets );
  }
}

void VETreeWidget::sortTree()
{
  // Ensure ordering is maintained.
  sortItems( 0, Qt::AscendingOrder );

  // Once the items have been re-ordered, re-create the tab ordering
  QTreeWidgetItem* baseItem = topLevelItem( 0 );
  QWidgetList tabWidgets;
  gatherTabWidgets( baseItem, tabWidgets );

  if (!tabWidgets.empty())
  {
    QWidget* lastWidget = tabWidgets.first();
    // Connect this treeview to the first widget.  This ensures
    // if the treeview is tabbed-to, it will tab to the correct sub-widget
    setTabOrder( this, lastWidget );
    for (QWidgetList::iterator itr = tabWidgets.begin() + 1; itr != tabWidgets.end(); itr++)
    {
      setTabOrder( lastWidget, *itr );
      lastWidget = *itr;
    }
  }
}