Two Buttons in Qt Gui - qt

I've written a program with different functions in Qt. Now I want to make a Gui. For example I have two buttons, button1 and button2. I open the application, i see button1 first. Then I click button1, it executes its function (like "start") and disappears. Then button2 should appear and when I click button2 it executes its function (like "stop") and disappears and button1 shows up again to be clicked to execute start.
My question now is, how to solve this in an easy way?
void gui::on_pushButton_clicked()
{
//execute start, switch to be button2
}
void gui::on_pushButton_2_clicked()
{
//execute stop, switch to be button 1
}

The following seems to be the easiest solution, but a bit cumbersome in case you want to add more buttons. In that case you might want to consider storing them in a list and iterating the list.
void gui::on_pushButton_clicked()
{
//execute start, switch to be button2
ui->pushButton->hide();
ui->pushButton_2->show();
}
void gui::on_pushButton_2_clicked()
{
//execute stop, switch to be button 1
ui->pushButton->show();
ui->pushButton_2->hide();
}
If you further on decide to implement even more logic, you should consider using QStateMachine and setting certain buttons to visible or hidden when entering or exiting certain states.

Related

How to find subsequent (all) SLOT from a subclass

I need to block specific buttons on an MMI.
I implemented a button blocking function in a subclass of QPushButton.
For this, I used the clicked() signal and blocked the button with blockSignals(true).
This means that with each button clicked on my MMI, 2 SLOTS are always called.
But when calling the blocking of a specific button, I get the first SLOT (clicked()) of my subclass, in which I block the button, then I then arrive in the original SLOT linked to this button, which is still called despite the blocking (the first time only).
How can I in my QPushButton subclass know the subsequent SLOTs linked to this button and avoid them (delete them)?
void QbtnStandardButton::slotButtonClicked(void)
{
if (modeProtection)
{
// Special mode to protect/unprotect the button
if (isProtected())
{
// Reset the protection
this->blockSignals(false);
}
else
{
// Set the protection: button will be unclickable
this->blockSignals(true);
}
modeProtection = false;
}
if (isProtected())
{
QMessageBox *pMsgBox = new QMessageBox(QMessageBox::Information,
"Protection",
"This button is protected!",
QMessageBox::Ok);
pMsgBox->exec();
pMsgBox->deleteLater();
// Here: remove subsequent SLOT of this button ?
}
}
I think it's very difficult if not impossible to find SLOTS linked to a button.
I worked around the problem by using an eventFilter() instead of a SIGNAL() in my base class.
In this case, I can filter the "clicked()" event before it is reissued.

Triggering an action based on its custom shortcut

Suppose I have some action to happen. For that I can create a QAction object and connect its triggered() signal to the slot that executes the desired function. Also, I can have a shortcut associated with the action; by changing the shortcut I'll be able to execute the same action with that shortcut.
My problem now is that the "shortcut" I wanna set to the action, contains also a mouse button press (and mouse events cannot be assigned to action shortcuts); say I want Shift+Left mouse button. Maybe this sounds a little bit harsh but bear with me.
What do I need? Well, I have a button, and an action (say "execute a script"). I want the script to execute when Shift+Left click is clicked, and I want this "shortcut" to be customized, i.e. the user should be able to change to shortcut to, say Ctrl+Left click (from some GUI element, e.g. button text), and now Ctrl+Left click should execute the script.
How can I achieve this?
Note: I as a user would expect an action triggered by a mouse button to be position dependent. If so, the following gets a bit simpler.
Qt doesn't have an option to specify such a shortcut.
You can roll your own by reacting to mouse events:
Maybe you have an event handler mousePressEvent(),
or a generic eventFilter(QObject *obj, QEvent *evt),
or utilize QApplication::notify
Whichever, at some place you need to catch a QMouseEvent *mouseEvt.
Choose the widget (or qApp) that is as outmost as needed.
There, compare mouseEvt->button() and mouseEvt->modifiers() to your list of actions and trigger the selected action. When the user chooses another trigger method, adjust your list of actions.
Let's put this to practice:
class MainWindow : public QWidget {
Q_OBJECT
public:
QMap<QPair<Qt::MouseButton, Qt::KeyboardModifiers>, QAction*> mapMouseShortcuts;
QAction *pLaunchScript;
MainWindow() : QWidget() {
mapMouseShortcuts.insert(qMakePair(Qt::LeftButton, Qt::ControlModifier), pLaunchScript);
}
void mousePressEvent(QMouseEvent *me) {
QAction *action = mapMouseShortcuts.value(qMakePair(me->button(), me->modifiers()), Q_NULLPTR);
if(action != Q_NULLPTR) {
action->trigger();
me->accept(); // optional
}
// optional:
if(!me->isAccepted()) {
QWidget::mousePressEvent(me);
}
}
};

Dragging a radio button performes the action but doesn't set the check

I am creating an application that should work on desktop and some mobile platforms.
The following example creates and connects my portrait/landscape buttons, in a group, to a slot, on the release signal.
m_landscapeRadio = new QRadioButton(QObject::tr("Landscape "));
m_portraitRadio = new QRadioButton(QObject::tr("Portrait "));
m_orientationGroup.addButton(m_landscapeRadio, 0);
m_orientationGroup.addButton(m_portraitRadio, 1);
m_orientationGroup.setExclusive(true);
m_landscapeRadio->setChecked(true);
connect(&m_orientationGroup, SIGNAL(buttonReleased(int)), this, SLOT(orientationSlot(int)));
But I found a weird situation:
Assume landscape button is checked. If I press and drag away from the portrait radio button, the slot action is performed (for the portrait option) but the portrait button is not checked.
I would like the action not to be performed.
For now...
In the orientationSlot I test the argument and set the checked value myself... Though I really expected the buttons to know to do that themselves.
But I think it is more expected by users that, if the press a button and change their mind, to be able to drag away from the button and not have the action be performed.
I can handle verifying if the check really happened in the action slot, and either check or discard the action depending on how I will think the user experience is better...
If I want the buttons to be checked and to perform the action as well:
void MyWidget::orientationSlot(int checked)
{
if(checked) m_portraitRadio->setChecked(true);
else m_landscapeRadio->setChecked(true);
.... actual actions
}
If I want the action not to be performed when the user drags away from the button (my preferred option):
void MyWidget::orientationSlot(int checked)
{
if(m_orientationGroup.checkedId() != checked) return;
.... actual actions
}
I use QRadioButton and handle mouse button being released event for reacting
on radio button being switched. It causes problems altogether with dragging event. I would like to either get the button
to be checked, or the action not to be performed.
http://doc.qt.io/qt-5/qradiobutton.html
Whenever a button is switched on or off, it emits the toggled()
signal. Connect to this signal if you want to trigger an action each
time the button changes state. Use isChecked() to see if a particular
button is selected.
Either you connect the radio button to the handler explicitly or the whole group: http://doc.qt.io/qt-5/qbuttongroup.html#buttonToggled
void QButtonGroup::buttonToggled(QAbstractButton *button, bool
checked)
This signal is emitted when the given button is toggled. checked is
true if the button is checked, or false if the button is unchecked.
Note: Signal buttonToggled is overloaded in this class. To connect to
this one using the function pointer syntax, you must specify the
signal type in a static cast, as shown in this example:
connect(buttonGroup, static_cast<void(QButtonGroup::*)
(QAbstractButton *, bool)>(&QButtonGroup::buttonToggled),
[=](QAbstractButton *button, bool checked) {
if (button == m_portraitRadio) {
// Portrait (un)checked
if (checked)
{
// checked!
}
}
/* ... */ });

Enable button function inside backgroundWorker

I am using windows form application to create gui. I have create a form with several button. The functionality of the first button called button1 is to read a video from hard disk and display it to a picturebox. The last line of button1 code is to enable another button:
button2->Enabled = true;
Button1 code is inside a backgroundworker. The result of this, it works fine, however it doesnt enable the button2. Is there issue using button properties inside backgroundworker?
You have to use BeginInvoke method and use Action delegate because backgroundworker DoWork doesn't modify UI.
private:
void DoWork(Object^ /*sender*/, EventArgs^ /*e*/ )
{
// some code
button2->BeginInvoke(gcnew Action(this, &MyForm::ModifyButton) );
}
void ModifyButton()
{
button2->Enabled = true;
}

Cannot change cursor in Qt main window from menu action

In my MainWindow, I have a push button and a menu bar item whose signals are both connected to the same slot. In the slot function, I have written:
mainWindow->setCursor(QCursor(Qt::WaitCursor));
This works as expected when the slot function is invoked via the button; however, when the same function is invoked from the menu, the wait cursor doesn't appear. Any idea why?
I also considered using QApplication::setOverrideCursor; however, that causes other problems.
Any recommendations? Thanks!
(I am using Qt 4.7 and doing my development on Windows 7 using Qt Creator with the default MinGW compiler.)
Here's more detail.
in MainWindow constructor: this->setCursor(Qt::CrossCursor);
signal/slot connections:
QObject::connect(button, SIGNAL(clicked()), MainWindow, SLOT(showMessageBox()));
QObject::connect(action, SIGNAL(triggered()), MainWindow, SLOT(showMessageBox()));
showMessageBox function:
void MainWindow::showMessageBox()
{
this->setCursor(Qt::WaitCursor);
// display wait cursor briefly before showing message box
for (int i = 0; i < 1<<30; ) {++i;}
QMessageBox msgBox;
msgBox.setText("Hello!");
msgBox.setStandardButtons(QMessageBox::Ok);
msgBox.setCursor(Qt::PointingHandCursor);
msgBox.exec();
this->setCursor(Qt::CrossCursor);
}
When showMessageBox is invoked with 'button', the wait cursor is displayed as expected.
When showMessageBox is invoked through 'action', the wait cursor does not appear; instead the cursor changes from Qt::CrossCursor to a Qt::ArrowCursor as soon as the user selects the 'action' menu item, and then changes to Qt::PointingHandCursor once the message box opens. The wait cursor never appears.
Your code is synchronous and uses a delay loop. When you're in the delay loop, there's no way for any Qt code to execute. A cursor change requires the event loop to be spinning -- so it appears from the symptoms you give.
Here's how to do it correctly -- remember, if you use delays/sleeps and other blocking calls in your GUI code, your users will hate you, and rightly so. Using exec() in message/dialog boxes is also bad style. Your application is asynchronous, code it so. Make sure your slots are declared as such (in the protected slots: section of MainWindow declaration).
void MainWindow::showMessageBox()
{
this->setCursor(Qt::WaitCursor);
QTimer::singleSlot(200, this, SLOT(slot1()); // fire slot1 after 200ms
}
void MainWindow::slot1()
{
QMessageBox * msgBox = new QMessageBox(this);
msgBox->setText("Hello!");
msgBox->setStandardButtons(QMessageBox::Ok);
msgBox->setCursor(Qt::PointingHandCursor);
msgBox->show();
connect(msgBox, buttonClicked(QAbstractButton*), SLOT(slot2(QAbstractButton*)));
}
void MainWindow::slot2(QAbstractButton* button)
{
// a button was clicked on the message box
this->setCursor(Qt::CrossCursor);
}

Resources