Implementing a QAction in the menu bar - c++

I am trying to implement something like the below in Qt:
Basically the user can click on the empty box (to the left of "Average") to spawn a new dialog box. And also the user can click on "Average" to perform another function.
I understand that QWidgetAction can achieve this, but I was wondering if there is any simpler way to achieve this; or does QAction itself already has such a functionality.

Related

How to avoid Qt to execute QAbstractButton::nextCheckState() when checkable button is clicked?

When you click a checkable button. The checkstate always inverts:
on to off
off to on
This is because when a checkable button is clicked Qt calls the nextcheckstate function.
QAbstractButton::nextCheckState()
Is there a way to avoid that? (I would like to decide check state by myself)
In my mind I would have to do the following steps to avoid that:
Create a MyPushButton Class which inherits QPushButton
Declare in mypushbutton.h an override function which overwrites the function when a checkable button is clicked
Somehow suppress calling QAbstractButton::nextCheckState() in that overriding function
Does somebody know which function to override?
Try:
Checkablebutton->blockSignals(true); // Maybe nextCheckState() is not call from now on until BlockSingls(false)
//some code
Checkablebutton->blockSignals(false);

Custom menu actions in Qt Designer

I'm currently trying to use Qt Designer to build a GUI and I would like to customize slots of my menu actions.
E-g: I'd like the user to press a menu action and it'd show a widget if it is hidden or hide it if it is already visible.
Basically, what I want to do is execute some code of mine and not the default actions such as show() or hide().
So I'm wondering if I should create a subclass of QMenuBar, add custom slots to it, then create a plugin to use it inside Qt Designer or if I should create a subclass for QMenu or QAction ? Or maybe it isn't the right way to do that ?
I'm working under Visual Studio and I'm only using Qt Designer, not Qt creator.
I'm new to GUI and Qt programming and I'm a bit lost here.
Thanks in advance :)
You have basically 2 options:
Implement the custom logic in the Mainwindow sublcass.
For this, you simply add the slots required for your handling in the class, and make them available in Qt Designer. You can do this:
either in the Signal/Slot editor and click "Modify" and then click on the + Symbol. By this you make new slots available in QtDesigner;
or when your slot is called on_(senderName)_(signalName), Qt autowiring will automatically connect the signals, and you don't have to do this in code or desinger.
Create a QMenuBar subclass and implement the custom logic there.
Your case tell Qt Designer to select your specific subclass as replacement for the default QMenuBar by right-clicking on it, and select "Promote to...". In the new dialog, you can specify your custom class that will be used as replacement in actual code, but in design time a QMenuBar is used. With this mehtod, you don't have to write a separate plugin to make your class available in Qt Designer.
Note that with the second option, your custom logic will only be called when the actions are triggered through the menu bar, not by shortcuts or tool buttons
Create a slot in your class:
onMenuActionTriggered()
Use the connect() to react on action's signal:
connect(ui.myAction, SIGNAL(triggered()), this, SLOT(onMenuActionTriggered()));
In your slot you can do whatever you want.
Another solution (not my favourite one, but possible) is to use the auto-connect functionality, which means, by declaring a slot 'on_myAction_triggered()' (where myAction is the name of your QAction) you don't need to use the connect() since it is automatically connected by Qt
The menu bar is automatically added to any new form derived from QMainWindow (the default when creating a gui application, but you can create new main windows using file->new file or project... and selecting Qt->Qt Designer Form Class ).
To add options to it you simply click in the area labeled "Type here" and write your option text. When you do so an action will appear in a list in the lower part of Qt Designer. Right click on that action and select "go to slot". It will pop up a dialog with "triggered()" already selected for you. Simply click "Ok" and Qt Creator will take care of all the details and transport you to the body of the slot function.

Change text in a QAction that's inside of a QMenu

I have a QMenu objects to which I've added several QAction objects with a certain text. All works well, except that I would like to change the text of those QActions at runtime. I've looked at the QMenu API and didn't find any way to to get them. I also tried actions.at(x) and a few other things. What's the right way to do this?
It really depends on how you are structuring your app. In some circumstances you might be saving your QAction's as members, to which you could access directly. Or you might just be saving the QMenu and populating it with QAction's. Either way, once you have your action, you just call setText(QString) on it:
// init
menu = new QMenu(this);
...
menu->addAction("foo");
// later on
QAction *action = menu->actions().at(0); // access just the first QAction
action->setText("bar");
QMenu also allows you to look up actions by a QPoint location. Again, it really depends on exactly how you will be determining which action you want to change.

How to prevent closing QMessageBox after clicking a button

I have 3 buttons on QMessageBox added by QMessageBox::addButton() method. Is it possible to prevent closing the message box if a button has been clicked? By default every button closes the window, but I don't want to do it for one button.
One interesting way to approach it that worked for me is to completely disconnect the signals for the target button created, and then re-add the intended functionality. This won't work for everyone, especially if the button isn't created this way and/or you still want to close the dialog correctly. (There might be a way to add it back and/or simulate the behavior with QDialog::accept, QDialog::reject, QDialog::done - haven't tried yet.)
Example:
QMessageBox *msgBox = new QMessageBox(this);
QAbstractButton *doNotCloseButton = msgBox->addButton(tr("This button will not close anything"), QMessageBox::ActionRole);
// Disconnect all events - this will prevent the button from closing the dialog
doNotCloseButton->disconnect();
connect(doNotCloseButton, &QAbstractButton::clicked, this, [=](){ doNotCloseButton->setText("See? Still open!"); });
If you can get a pointer to the QMessageBox widget, you can try to install a QObject::eventFilter on it which filters the QEvent::Close.
Just had the same problem but I wanted to add a checkbox and it kept closing the dialog on clicked even with the ButtonRole set to QMessageBox::ActionRole (tried others too). For this scenario I just called blockSignals(true) on the QCheckBox and now it allows check/uncheck behaviour without closing the dialog. Luckily QCheckBox works fine without signals but assume you want a signal from your button.
They should likely add a new role that doesn't close the dialog as it's a pain to derive a class for simple customizations.
I looked through the addButton() functions overloads, but there is no custom behavior for the buttons you add with this method. They will behave like the standard buttons on a messagebox should.
However if you want to create a fully customizable dialog, then your best option is to extend the QDialog class and use whatever controlls you like on it.
Thanks to #Albert's Answer, I found that this also possible in python:
messagebox = QMessageBox()
button = QPushButton("This button will not close anything")
messagebox.addButton(button, QMessageBox.ButtonRole.NoRole)
button.disconnect()

Callback for button in Qt Designer?

I just started using QtCreator tonight, and it seems it puts all of the interface stuff inside of the ui file. I followed a tutorial to create a resource for my icons, then I added them to a menu bar at the top.
I need to make a connection when one of them is clicked though, and cannot figure out how to make a callback for it.
Am I going to have to completely create them through code or is there some way to add a callback for them (rather than just making them interact with other objects).
Menu bar items are action objects. To do something when they are clicked, you need to catch the triggered() signal from the action. Read more about signals and slots here.
To do this, you need to declare a new slot in your MainWindow class. Qt also supports doing this automatically, without the need to connect anything, but I prefer doing it myself. If you're not interested, just skip this part.
First, we declare a new slot in your window class:
private slots:
void clickMenuButton();
Then, in your constructor, you need to connect the triggered signal to your new slot:
connect(ui.actionObject, SIGNAL(triggered()), this, SLOT(clickMenuButton()));
The first argument is the object that holds the signal we'll listen to (your menu button). The second is the name of the signal. The third is the object that holds the receiving slot (in this case, our window). The fourth is the slot.
And just like that, clickMenuButton() will be called whenever the action is clicked.
As I said before, Qt can also automatically connect signals to slots. The disadvantage here seems to be that you can't change the slot's name, but you don't need to connect it either.
Qt Creator supports creation of slots for widgets: in the case of your menu action, you should go to the form designer, and you should see a list of actions in your form (if you don't, find the Action Editor). Right click the action you want, and push Go to slot.... There, double click triggered().
Qt Creator will then open the new slot in your code editor, and you can do whatever you want to here!
To do that you'll need to add a QAction, add it to the menu, associate an icon with it and then create a callback for it. I'm using the VS Integration so I don't know the details of how to do it in Creator but it should be possible without creating stuff in code.
There should be somewhere an actions editor. from there you add an action, then right-click it or something to add an icon to it, then drag it do the menu and then possibly double click it to create a slot for it. This is how it works in the VS Integration atleast.