I want to set the visibility of some buttons automatically. For example, I have some buttons and I want to set them visible or invisible when an action is triggered. I have used an action trigger signal and connected it to a slot to set the buttons visibility base on the triggered action, my code is:
void MainWindow::setBtnVisibility(bool toggled)
{
ui->btn1->setVisible(!toggled);
ui->btn2->setVisible(!toggled);
}
I have many actions so I should write different functions. Is there a better way to connect this function (action trigger and setvisibility function) together?
Related
My application supports the IE (InternetExplorer) browser. When the back/forward buttons are clicked and there is nothing to go back or forward to, Webbrowser.GoBack() and Webbrowser.GoForward() are causing a crash.
Is there any way to know if I can go back before I actually call GoBack()? I took a look at the CWebBrowser2 class functions, but I couldn't find anything as such.
Is there any API to help on this, or any alternative approach to handle this?
Is there any way to know if I can go back before I actually call GoBack()?
Per the IWebBrowser2::GoBack() documentation:
Use the DWebBrowserEvents2::CommandStateChange event to check the enabled state of backward navigation. If the event's CSC_NAVIGATEBACK command is disabled, the beginning of the history list has been reached, and the IWebBrowser2::GoBack method should not be used.
And likewise in the IWebBrowser2::GoForward documentation:
Use the DWebBrowserEvents2::CommandStateChange event to check the enabled state of forward navigation. If the event's CSC_NAVIGATEFORWARD command is disabled, the end of the history list has been reached, and the IWebBrowser2::GoForward method should not be used.
And per this discussion thread:
Create a couple of BOOL member variables in the class that processes the
ON_UPDATE_COMMAND_UI notifications for the 'back' and 'forward' toolbar
buttons -- one for each button state. Initialize them both to FALSE in
the ctor. Handle the OnCommandStateChange event, and watch for the
CSC_NAVIGATEBACK and CSC_NAVIGATEFORWARD values in the 'nCommand'
parameter. When you get the CSC_NAVIGATEBACK value store the 'Enable'
parameter value into your BOOL member variable for the 'back' button
state. Do the same thing for the 'forward' button state variable when
you get CSC_NAVIGATEFORWARD value. In your OnUpdateButtonForward and
OnUpdateButtonBack handlers, call pCmdUI->Enable using the corresponding
button state member variable.
So, use the browser's CSC_NAVIGATE... state changes to know when it is safe to call GoBack()/GoForward()`. These are the same events that IE uses to enable/disable its own Back/Forward UI toolbar buttons.
I want to create a menu whose content is determined dynamically (through some data received from the network). How would I go about implementing such a menu in Qt?
The network should be queried for the content to be shown whenever the menu is opened.
assuming you have a menu bar somewhere:
QMenu* m = new QMenu(this);
m->setTitle("click here");
m->setIcon(QIcon());
ui->menuBar->addMenu(m);
I think you are looking for QMenu::aboutToShow signal. This signal is emitted when the user opens the menu and it is the perfect moment to re-populate your menu.
Nevertheless, you have to take following things into consideration:
The signal is emitted synchronously respect the rest of the UI, it means that once the slot handling it finishes the menu will be shown. So you have to populate the menu before returning from that function.
This signal is emitted in the main thread (the one that handles the GUI), so the rest of the interface will be blocked until it finishes. This is important if your network connections depends on the events loop. You may use QApplication::processEvents to be sure events are consumed.
Basic example
The following example uses a timer instead of a network connection for the sake of simplicity, but illustrates my point:
In some initialization function (such as the constructor). The menu is assumed to already exists (similar case for context menu):
connect(ui.menuDynamicMenu, &QMenu::aboutToShow, this, &MainWindow::onMenuAboutToShow);
The slot (m_waiting should be an atomic boolean or similarly protected flag, in the case you want to handle the network connection using multi-threading):
void MainWindow::onMenuAboutToShow()
{
// Here your _synchronous_ network query
// Probably you'll have to use some kind of barrier
m_waiting = true;
QTimer::singleShot(2000, this, [this]() {
ui.menuDynamicMenu->clear();
ui.menuDynamicMenu->addAction("Some action from network query");
ui.menuDynamicMenu->addAction("Another action from network query");
m_waiting = false;
});
while (m_waiting) {
qApp->processEvents(QEventLoop::WaitForMoreEvents);
}
}
The full code of this example is available in GitHub.
I have a CDialogEx Class called Properties in which I handle the ON_COMMAND message. Now, ON_COMMAND should get called when I click the menu item ID_EDIT_PROPERTIES (as a submenu from main menu). The event handler wizard wrote that code for me, but when I start the Application the menu item remains grayed out. I've tried to manually activate it by calling EnableMenuItem when ON_UPDATE_COMMAND_UI happens, but to no avail.
Any help would be greatly appreciated.
You just need to understand how menu items enabling/disabling is handled:
If there is neither ON_COMMAND nor ON_UPDATE_COMMAND_UI handler the item is disabled.
If there exists no ON_UPDATE_COMMAND_UI handler but there is an ON_COMMAND one in the currently active document or view (or even the "mainframe"), the item is enabled.
If there exists a ON_UPDATE_COMMAND_UI handler, en-/disabling the item is determined by the handler (pCmdUI->Enable(bEnableState)).
Also keep in mind that:
You may not call EnableMenuItem() yourself, instead call pCmdUI->Enable(bEnableState) in an ON_UPDATE_COMMAND_UI handler. This affects not only the menu item, but any other "command"-type item (with the same ID), eg main menu, context menu, toolbar or rebar button.
Where to put the handler, is a matter of application design and depends on the data you are processing or representing. It can be put in the mainframe class (if it depends on some "global" data or setting), in the document class (if it depends on or changes some data or setting in the document - possibly affecting all views), or in the view class(-es) (depending on or affecting the current view only).
In your case, if I understand correctly, the item is disabled because the handler is in the CDialogEx-derived class, but no instance of this class has been created yet, ie there exists no ON_COMMAND handler for your ID_EDIT_PROPERTIES command.
Per m_bAutoMenuEnable, When this data member is enabled (which is the default), menu items that do not have ON_UPDATE_COMMAND_UI or ON_COMMAND handlers will be automatically disabled when the user pulls down a menu.
I admit that I don't know ii it is different for CDialogEx, But for CDialog I found that the UPDATE_COMMAND_UI didn't ever work unless I handled the WM_KICKIDLE event.
In your OnKickIdle event handler make a call to:
CWnd::UpdateDialogControls
There is a short tutorial on it here.
Forgive me if CDialogEx supercedes this information and I will remove the answer.
In my application, there are a few QPushButtons that I need to handle "invalid release" and "click" differently.
By "invalid release" I mean a release that happens outside the button (following a press within the button).
So I'm trying to inherit from QPushButton and implement my own signal void released(bool validClick);.
I'm thinking about using mouseReleaseEvent to check whether it's in the button's rect() to infer if a clicked() signal will follow the released() signal. Is this a good way to do it?
Update::background:
I have a group of three buttons, each of which can start the same action to the backend (with different configurations). However the backend can not handle multiple successive start commands without already started ones being cleaned up, so I have to prevent such a case in the button group.
This application is multi-touch, which makes it very easy to click all three buttons at the same time.
What I want to do:
1) When one of the buttons is pressed, disable others. This is essential because this is a multi touch GUI and multiple buttons being clicked at the same time is the first thing I need to avoid.
2) When the backend informs the button group that all previously started services has been closed and cleaned up and it's ready for next button click, button group unlocks all buttons.
3) If the user triggers a invalid release (press on the button, release outside it), all buttons should be unlocked immediately.
4) If the user triggers a valid release (click), the button group should also disable the button that the user has clicked so that it can not be clicked again until allowed by the backend.
If I can not differentiate between valid and invalid release, then I would have to treat case 4) and case 2) the same way as case 3). This is not desirable.
You don't care about presses nor releases, only about clicks and indications that tasks are done by the backend. You have two states: idle and busy. When idle, buttons are enabled. When any button is clicked() you transition to the busy state until the backend signals that it's not busy anymore. This is trivial to implement using the state machine framework.
You could also have three states to make failure handling easier: idle, pending, and busy. When any button is clicked() you transition to the pending state and request the work by the backend. When the backend signals that it has accepted the request, transition to busy, until the backend has signaled that it has done processing the request, whereas you transition to idle.
I need to get the list of all events fired in a Qt Widget ( Qt C++) like an utility which can capture all events or some function which will be called and the event details to be passed to the function every time an event is fired.
Can somebody tell me how to do this or is there any free utility available for this purpose ?
QObject::installEventFilter is what you want. You can see all events coming into an object.
If you need to see all events for everything, you can install event filter on QApplication, see documentation to QCoreApplication::notify:
Installing an event filter on QCoreApplication::instance(). Such an
event filter is able to process all events for all widgets, so it's
just as powerful as reimplementing notify(); furthermore, it's
possible to have more than one application-global event filter. Global
event filters even see mouse events for disabled widgets. Note that
application event filters are only called for objects that live in the
main thread.
If you make a class derived from QWidget (let's call it RecordingWidget) you can reimplement it's event() function to record in whatever manner you'd like (maybe keep a log in a static member of RecordingWidget) and then continue to pass the event to QWidget's default event function:
bool RecordingWidget::event(QEvent *event)
{
// Record stuff
...
// Send the event through QWidget's default event implementation
return QWidget::event(event);
}