How to know parent menu of a given QAction? - c++

I have a list of QActions, some are added to the top level menu and few are added to submenus of top level.
Is there any way to know parent menu name of each actions?
QAction *act;
I'm trying act->parentWidget(). But how can I get menu name from this?

You can check if the result of act->parentWidget() if it is a valid pointer, if so you can manipulate as a normal widget.
To get the menu name, it depends on which widget you are using.
If is QMenu, you can retrieve the menu title via the title function.
QAction *act;
...
QWidget *widget = act->parentWidget();
if (widget) {
QMenu *menu = dynamic_cast<QMenu*>(widget);
menu->title();
}

Related

QT context menu not aligned with cursor

When I right click, a context menu appears but it is not aligned with the cursor. I want the corner of the context menu to appear right where the cursor is. Here you can see it is quite far off to the right:
Here is the method where the context menu is shown:
void MainWindow::on_listWidget_customContextMenuRequested(const QPoint &pos)
{
QMenu menu("contextMenu", this);
QAction deleteItem("Delete", this);
menu.addAction(&deleteItem);
connect(&deleteItem, SIGNAL(triggered()), this, SLOT(deleteItem()));
menu.exec(mapToGlobal(pos));
}
Thanks for the help!
The pos variable is relative to the viewport() of the QListWidget so you must use the mapToGlobal() method of the QListWidget:
menu.exec(ui->listWidget->viewport()->mapToGlobal(pos));

Which UI item allows dynamic expansion on the go in Qt?

Suppose I have a single text box and a radio button placed below the text box .
What I want is that if the user enters some text and ALSO clicks the radio button a similar text box and a radio button should appear just below. And similar thing should happen if the user does that for new UI items.
Any suggestions what classes I should be looking for?
The relevant class you need to handle the inserting of new widgets is one of the QLayout subclasses, most likely QVBoxLayout it sounds like. This will allow you to insert a new textbox and radio button at the bottom of the layout, which will then automatically expand to fit these new widgets.
Inserting the new objects is pretty straightforward. Connect a slot to a signal of the QRadioButton that's at the bottom of the layout, like the QRadioButton::toggled or QRadioButton::clicked signals. This slot will check if the above textbox has any text in it, and, if so, insert a new textbox/radio button pair below them.
To be clear, this slot should be a method of the widget that uses the layout to arrange its sub-widgets. For example, if you're putting all these objects in a QGroupBox, then that's the object to which you'd add the slot I'm describing.
Here is an (untested) example:
class Group : public QGroupBox {
Q_OBJECT
public:
Group(QWidget* parent = nullptr) : QGroupBox(parent)
{
layout = new QVBoxLayout(this);
insertNewRow();
}
private slots:
void insertNewRow(bool checked = true) {
/* You might want to make this remove the row if the button is unchecked */
if (!checked)
return;
/* Only add row if text box is non-empty */
if (textBoxes.isEmpty() || textBoxes.last()->text().isEmpty())
return;
/* Disconnect slot for previous radio button */
QObject::disconnect(radioButtons.last(), 0, 0, 0);
/* Add new text box and button, labeled Button 1, Button 2, etc. */
textBoxes.append(new QLineEdit("", this));
radioButtons.append(new QRadioButton(QString("Button %1").arg(textBoxes.size())), this));
/* Connect signal/slot to add new row when clicked */
QObject::connect(radioButtons.last(), &QRadioButton::toggled, this, &Group::insertNewRow);
}
private:
QVBoxLayout* layout;
QList<QLineEdit*> textBoxes;
QList<QRadioButton*> radioButtons;
};

Close button only on active tab of QTabWidget

To save space in a QTabWidget, I would like to show the close icon only for the current tab, like e.g. Firefox is doing:
Is there a simple way using a style sheet, some thing like (not working like this)
QTabBar::tab::!selected::close-button {visible: false;}
or do I have to subclass QTabWidget to get the desired behavior?
You won't need to subclass anything, you can use QTabWidget::tabBar() method to obtain a reference (i.e. QTabBar *) to the tab bar associated with your QTabWidget. (Note that this method is no longer protected, so it can be accessed without subclassing the class)
QTabBar *tabBar = tabWidget->tabBar();
You can now use tabBar reference to hide close buttons on non-current tabs. For example to hide ith button, you can do:
tabBar->tabButton(i, QTabBar::RightSide)->hide();
So a simple workflow could be as follows:
Connect QTabWidget::currentChanged(int index) signal to a slot.
In that slot hide all close buttons other than the button at index.
You can subclass QTabWidget to get access to the QTabBar widget using protected method QTabWidget::tabBar. Then you can connect to the QTabBar::currentChanged signal and hide close button for not selected tabs manually:
QTabBar::ButtonPosition closeSide =
(QTabBar::ButtonPosition)style()->styleHint(QStyle::SH_TabBar_CloseButtonPosition, 0, this);
for (int i = 0; i < toolbar->count(); ++i)
{
if (i != toolbar->currentIndex())
{
QWidget *w = toolbar->tabButton(i, closeSide);
w->hide();
}
}
hide() leaves empty space for the invisible close button. This looks funny.
Set the width to 0 instead.

Adding menu on QPushButton using QComboBox

I am trying to implement a popup menu on QPushButton using QComboBox popup function.
When I click on the button a menu appears but their is some space between the button and the menu. How do I remove that?
I also want the text color to remain fixed when I hover on an item in the menu.
How do i do that?
I am trying to solve this already for 3 days but not getting any solution by CSS nor any QComboBox function.
Thank you.
You can use a QToolButton instead of QPushButton and add actions to the QToolButton. You should create your custom QWidgetAction to add to the popup menu.
This is sample QWidgetAction:
#include <QWidgetAction>
class myCustomWidgetAction: public QWidgetAction
{
Q_OBJECT
public:
explicit myCustomWidgetAction(QWidget * parent);
protected:
QWidget * createWidget(QWidget *parent);
};
myCustomWidgetAction::myCustomWidgetAction(QWidget * parent):QWidgetAction(parent) {
}
QWidget * myCustomWidgetAction::createWidget(QWidget *parent){
myCustomWidget * widget=new myCustomWidget(parent);
return widget;
}
You can then add your widget to the toolButton to be diaplayed in a popup menu:
myCustomWidgetAction * widgetAction = new myCustomWidgetAction(this);
ui->toolButton->addAction(widgetAction);
Your custom widget can be a list containing different elements or it can be any other widget. You can also add multiple instances of myCustomWidgetAction to the toolButton.

Disabling a QCheckbox in a tricky way

I want to make a QCheckBox named "Show Captions" disable another QCheckBox named "Show captions if no title" when the first is checked, but my problem is that how I can make it disabled immediately when the user checks the first checkbox.
SetupSlideShow::SetupSlideShow(QWidget* parent)
: QScrollArea(parent), d(new SetupSlideShowPriv)
{
QWidget* panel = new QWidget(viewport());
setWidget(panel);
setWidgetResizable(true);
QVBoxLayout* layout = new QVBoxLayout(panel);
d->showComment = new QCheckBox(i18n("Show captions"), panel);
d->showComment->setWhatsThis( i18n("Show the image caption at the bottom of the screen."));
d->showTitle = new QGroupBox(i18n("Show title"), panel);
d->showTitle->setWhatsThis( i18n("Show the image title at the bottom of the screen."));
d->showTitle->setCheckable(true);
d->showCapIfNoTitle = new QCheckBox(i18n("Show captions if no title"), panel);
d->showCapIfNoTitle->setWhatsThis( i18n("Show the image caption at the bottom of the screen if no titles existed."));
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(d->showCapIfNoTitle);
d->showTitle->setLayout(vbox);
layout->addWidget(d->showLabels);
layout->addWidget(d->showComment);
layout->addWidget(d->showTitle);
}
Doesn't this work?
connect(d->showComment, SIGNAL(toggled(bool)), d->showCapIfNoTitle, SLOT(setDisabled(bool)));
The call to paintEvent() isn't really doing anything for you regarding immediacy. Nothing will be repainted until control returns to the event loop (after your constructor exits). It is more typical to call update() but even this is unnecessary when changing the properties of built in widgets.
To link the check boxes, define a slot for the stateChanged() signal of showComment, connect the signal to your slot in your constructor above (by calling connect(), and in that slot, call d->showCapIfNoTitle->setCheckState(d->showComment->checkState()).