I have a button named 'Start', and when it's clicked, a lengthy operation starts and I want it to change to a button named 'Stop'. The behavior when you click it obviously changes as well. What is the best way to implement this - by changing the button's text and reconnecting the 'clicked()' signal to a different slot, or by having two buttons and then hiding 'Start' and showing 'Stop'.
Both of your options work. A simple third alternative is to change the button text (changing the icon would be a good idea too), and saving the "state" (playing/not playing) somewhere. In your connected slot, just do the Right Thing depending on current state. (That way you don't have to reconnect anything).
Another option is to use the push button with setCheckable(true) set. This way the button acts more like a toggle-button (stays depressed when first clicked, raises back with second click), and combining that with your dynamic text/icon change.
If you use this, you should use the toggled(bool) signal rather than the clicked() one. The slot argument tells you whether the button is "active" or not. (This can also be queried with isChecked().)
Related
Ubuntu 22.04, Qt 6.4.0.
I have some QPushButtons that belong to the same parent.
I set all of them with checkable and autoExclusive properties to true.
The doc about the latter states:
If auto-exclusivity is enabled, checkable buttons that belong to the
same parent widget behave as if they were part of the same exclusive
button group. In an exclusive button group, only one button can be
checked at any time;
Emphasis is mine.
From what I understand, they say that only one button "can" be checked. This means that more than one button can never be checked. But it allows to no buttons checked. Otherwise I was expecting something like: "only one button must be checked at any time".
Anyway, my problem is I cannot uncheck a button after it was checked.
It remains checked no matter I click on it.
I also tried programmatically:
ui->myCheckableButton->setChecked(false);
no way.
Disabling the autoExclusive property I can disable them, but of course is not the intended behavior.
What am I missing here?
How to uncheck a button when autoExclusive property is active?
Sadly, you are experiencing the intended behavior of Qt.
The source code for QAbstractButton::setChecked contains lines that makes it clear a button belonging to an exclusive group cannot be unchecked (unless it is the only button in that group).
if (!checked && d->queryCheckedButton() == this) {
// the checked button of an exclusive or autoexclusive group cannot be unchecked
#if QT_CONFIG(buttongroup)
if (d->group ? d->group->d_func()->exclusive : d->autoExclusive)
return;
if (d->group)
d->group->d_func()->detectCheckedButton();
#else
if (d->autoExclusive)
return;
#endif
}
d->queryCheckedButton() returns nullptr if only 1 button belongs to the group. The rest is straight forward:
If Qt was compiled to use button groups and the button group is exclusive, do not uncheck the button (return; instead).
Otherwise, if the button itself is autoexclusive, do not uncheck it.
I checked the exclusive property of QButtonGroup, the description makes the behavior clear:In an exclusive group, the user cannot uncheck the currently checked button by clicking on it; instead, another button in the group must be clicked to set the new checked button for that group..
It is unfortunate the description for QAbstractButton does not contain that sentence too, although I will say it is not incorrect since 0 buttons may initially be checked (then, when 1 is checked, it will never allow to uncheck everything, which is the missing part).
Your modified sentence using must would have a meaning in the lines of:When using the QAbstractButton class, you must make sure not to allow more than 1 button to be checked.There are several instances of sentences built this way and AFAICT, all of them describe things you must do for your implementation to work.
The good news in all of that is that your solution of disabling the autoExclusive property seems no have no impact whatsoever on the signals emitted by the button.You may for instance create a subclass of QPushButton (if that is what you are using), remove the autoExclusive property, first thing in the mousePressEvent and re-enable it last thing in the mouseReleaseEvent.
Alternatively, you can make your button non autoexclusive and connect signals when it is toggled (to true) to unckeck the other buttons.This is probably how I would do it.
I have a dialog based application. I have one static text control and a button on this, both of which I have made invisible in the beginning. I want to show both the controls on reaching a certain condition. When I click this button, again I want to make both the controls invisible.
However, I am able to show and hide the control and also captured the button click event like this:
ON_BN_CLICKED(IDC_MY_BUTTON, &MyDlg::OnBnClickedMyButton)
and defined OnBnClickedMyButton().
But when I press the button, it is not pressed and the event is also not generated.
Any suggestions?
First check if the IDC_MY_BUTTON exists and is valid.
Remember to add DECLARE_MESSAGE_MAP() at the header file.
Also check at the BEGIN_MESSAGE_MAP(MyClass,MyParentClass) if the class
and the parent class you write are right.
I hope this helps.
I think the IDC_MY_BUTTON maybe is invalid or other control has the same ID.
Well, finally I have come to know that though the button was visible but on clicking it was not taking control, hence I used BringWindowToTop() to draw it on top. Now it is being clicked and OnBnClickedMyButton() is also being called.
But now the issue is that after calling BringWindowToTop() the button is not shown. It is shown only when I take the mouse pointer on it. Not able to understand what is the issue.
What is the difference between the toggled and triggered signals in QAction? I don't know when to use one over the other or how they relate.
Moreover, in the documentation for the triggered signal, what does "activated" mean? Is it the same as getting focus?
Thank you...
The difference lies in what type of widget the action is associated with. For example, the toggled signal applies when you have an action connected to a (binary) checkbox. It lets you know whenever the checkbox has been changed from 'on' to 'off' or 'off' to 'on. The triggered signal, however, applies to transient actions without the requirement that there be an 'on' and 'off' state (i.e. clicking on a menu item or clicking a button). The usage of 'activated' vs. 'triggered' here is not important, you can think of them as synonyms for a signal without this extra state.
In my application, I have one tableview of items, and a side-panel "preview":ing the latest selected item.
I want clicking on an item to change the selection, and double-clicking to cause a "run"-action to be performed. More specifically, I want the "run"-action (including key-navigation and pressing enter) to be bound to the "activation" of the item in the table-row.
My problem is; single-clicks does not only change the selection, but fires the "activated" signal on the item. I would like to tweak it such that:
Navigation Keys, Single Mouse Click: Selection-change, update preview-panel
Enter Key, Double Mouse Click: Activate/run/open action triggered.
Is there a nice clean way to do it, or are overriding the onclick/doubleclick events my best option? Or is there some other tabular list-widget better suiting my needs?
I would connect the slot for the preview action to the currentChanged() signal of the table view's selectionModel(). This covers single clicks and key navigation.
Then there's two options for the double clicks and Enter key presses:
Subclass your tableview, override doubleClickEvent() and keyPressEvent() and fire your custom signal in there, with maybe the model index or something else as an argument. Then just connect your run method to your own signal as you have full control over when it is fired.
If you don't want to subclass, you can use the installEventFilter() mechanism.
Either I'm getting your approach wrong or I'm too tired, but if you want to trigger a run event you should avoid the activated signal completely. Set the signal slot mechanism so that your double click and Enter key press event trigger your run() function, and then the single click/nav buttons should trigger the 'activated' slot which will return your index in the tableview.
I'm pretty certain Qt wants you to be explicit about which signal points to which slot or it'll ignore it or point to a default.
I am trying to use QSystemTrayIcon for my application and i am facing some problems.
It is the first time i use qt so i am not really used to it.
I followed this tutorial to make a system tray icon but i fail to customize it.
I want to have a button show/hide and not 3 show, hide, restore. These actions are really confusing for a newbie and i dont know what to do and what to connect.
I tried some things but with no luck.
Also when the system tray menu appears if you click somewhere else, the menu stays open.
Any way to solve this thing too?
If you want to remove one of the menu items, modify the createTrayIcon function so that it only adds the actions you need (and clean up the unused members once you get it to work). It's that simple.
If you want a single menu item or button to toggle between visible and hidden, you'll need to create a custom slot that calls show() or hide() (or setVisible(bool)) depending on whether the widget is hidden or not (use isVisible() for that for example). Then connect your action to that slot.
Read the Signals and Slots documentation and examples for information about how to create a new slot.