PDA

View Full Version : Problem with customized QTabWidget



SeanM
17th April 2014, 22:53
I’m trying to duplicate the functionality of how many other applications handle tabs where the last tab is treated as a special case and is used solely to create new tabs. So when my widget launches it looks like:
\ Tab 1 /\ + /
With “Tab 1” set as the current index. Left clicking on the ‘+’ will add a new tab called ”Tab 2”, and sets “Tab 2” as the current index, like so:
\ Tab 1 /\ Tab 2 /\ + /

To achieve this, I’ve connected the currentChanged(int index) signal to a slot that checks to see if the current index is the last index, and if so it adds a new tab, and sets the newly created one as current. If any other tab is the current index, the slot does nothing. Here’s the code for the slot:

void customTabWidget::slotTabBarClicked(int index)
{
if (index != (count() - 1))
{
// if it's not the last one, we don't need to do anything
return;
}

// if it's the last tab, we add a new tab
slotAddTab();
}
This works great when the user left-clicks on the ‘+’ tab.

I’ve also added a contextual menu that allows the user to rename or delete a tab by right-clicking one of the tabs. I’m handling that in mousePressEvent(). This functionality should work for all tabs EXCEPT the final tab; the user should never be able to rename or delete the ‘+’ tab, since it’s a special case. In mousePressEvent(), I’m attempting to detect which index the user right-clicked on so that I can put the contextual menu in the right place as well as rename/delete the correct tab. Here’s the code for mousePressEvent:

void customTabWidget::mousePressEvent(QMouseEvent *event)
{
QTabWidget::mousePressEvent(event);
if (event->button() == Qt::RightButton)
{
for (int i=0; i < tabBar()->count()-1; i++)
{
QPoint clickPos = mapToGlobal(event->pos());
if (tabBar()->tabRect(i).contains(tabBar()->mapFromGlobal(clickPos)))
{
qDebug("Tab count %d, right click on %d", tabBar()->count(), i);
setCurrentIndex(i);
slotShowContextualMenu(clickPos);
}
}
}
}

Since there’s no reason to show that contextual menu on the ‘+’ tab, I’d like to disable the right click functionality just on the last tab, which I’m trying to do in the mousePressEvent for loop, by only looping to bar->count() – 1. But the problem I’m having is that the right-click on the ‘+’ tab emits currentChanged(int) BEFORE mousePressEvent() is called, causing creation of a new tab in slotTabBarClicked(). Before the user right clicks, count() is 2, current index is 0, and the ‘+’ is at index 1. Once the user right clicks on the ‘+’ tab, by the time we get to mousePressEvent(), count() is 3, current index is 1, and the ‘+’ tab is at index 2. So the mapping doesn’t work and I end up displaying a contextual menu on the newly created “Tab 2”, even though the user right-clicked on the ‘+’ tab.

The behavior I want is right-clicking on the ‘+’ tab should do nothing; it shouldn’t add a new tab, it shouldn’t show a contextual menu. Right-clicking on any other tab should bring up the contextual menu. Left-clicking on the '+' tab should add a new tab.

What am I missing, or how should I be trying to do this? If there was a separate signal for left vs. right clicks, it’d be easy. But I don’t see a way to easily detect in slotTabBarClicked(int) that it was a right-click that caused currentChanged(int) to be emitted, or that that right-click was on the '+' tab and that I shouldn't do anything...

anda_skoa
18th April 2014, 09:31
But the problem I’m having is that the right-click on the ‘+’ tab emits currentChanged(int) BEFORE mousePressEvent() is called, causing creation of a new tab in slotTabBarClicked().

The cause this is most likely that the tab widget is not the actual receiver of the mouse event, its QTabBar child is. So th tab bar reacts to the event first and you see it when it propagates upwards.

My suggestion would be to access the tab bar and its tab buttons.
For all tab buttons that you want a context menu, set the same context actions using addAction() and set the button's contextMenuPolicy to ActionsContextMenu.

You should then only have to react to the actions' triggered() signals.

Another option you could investigate is to use QTabBar's corner widgets.

Cheers,
__

SeanM
18th April 2014, 19:18
Ok, I hadn't dug down into the QTabBar class, I'm not sure why I didn't think to do that. I'll poke around in it and see what works best.