Enable a bool variable by pressing a button in Qt - c++

How to link a variable to a push button so it is enabled as true for first time when the push button is pressed, and made false when it is pressed for the second time, and so on?
I want to use it because in my program a certain loop should be executed when the push button is pressed so that the variable is enabled as true.
Can someone help me?

In order to achieve that, you need to connect the clicked() signal (inherent to a QPushButton) to a slot of yours. Then, in this slot, you just need to change a boolean of your object each time you enter this slot. This is the code you need.
In your .h file :
private:
bool bForButton;
QPushButton* m_button;
public slots :
void onClicked();
In your .cpp :
MyClass::MyClass()
{
bForButton = false;
m_button = new QPushButton(this);
connect(m_button , SIGNAL(clicked()), this, SLOT(onClicked()));
}
void MyClass::onClicked()
{
bForButton = !bForButton;
}
This way, you notice that we change the boolean to its opposite, so it will change each time you click the button, as required.

You can display a button that keeps the state (checked or not) so each time you click on it its state change and the user can see the current state.
You can achieve that by setting your button checkable setCheckable(true) and test in your loop the value of isChecked(). The button will keep the checked state and update on click automatically so you don't need any extra code.

The QPushButton has such variable, i.e. the checked property.
You can connect the loop you need run to the toggled signal:
auto button = new QPushButton(this);
button->setCheckable(true);
...
connect(button, &QAbstractButton::toggled,
this, &ThisClass::executeLoop);
...
void ThisClass::executeLoop(bool checked) {
if (!checked) return;
.... your function body
}
http://doc.qt.io/qt-5/qabstractbutton.html#checked-prop
This is more in the mindset of Qt: don't loop/spin/lock/..., just react to events triggered by the framework (i.e. connect signals to slots).

Related

How to catch information for Qt designer

I have created a Qdialog box using the Qt creator designer as shown below:
When I need to display it, I'm instantiate the class dialogoverwrite (.cpp, .h and .ui)
DialogOverwrite *OverwriteDialog = new DialogOverwrite;
OverwriteDialog->exec();
OverwriteOption = OverwriteDialog->result()
My issue is that I want to get the QDialogButtonBox result but I do not know how. the current code, returning the result of the OverwriteDialog but it's not returning any QDialogButtonBox::Yes, QDialogButtonBox::YesToAll ...
How to catch the QButtonGroup result and not the QDialog result.
In the same way, If I want to change the label value from "File(s) and/or Folder(s)" to another label, how to access to this QLabel ?
Thanks for your help
When you pressed QDialogButton it was emit signal clicked(QAbstractButton*) by catching this signal you can identify which action button pressed.
Please go through following link it would be help you.
Qt: How to implement QDialogButtonBox with QSignalMapper for non-standard button ??
Well the standard way to do this is to handle the result by connecting it. So you could do:
connect(this, SIGNAL(clickedDialogButton(QAbstractButton*)),
SLOT(dialogButton(QAbstractButton* aButton)));
Next you would create a function in your class called dialogButton (for example) and have that handle the result:
void MyUI::dialogButton(QAbstractButton* aButton) {
// Obtain the standard button
StandardButton button = buttonBox−>standardButton(button);
// Switch on the type of button
switch (button) {
case QDialogButtonBox::YesToAll:
// Do the thing you would like to do here
break;
// add some more cases?
}
}
You could also check for the signal given by the QButtonGroup. Something like: void QGroupButton::buttonClicked(QAbstractButton* button) would work in the same way.

QLineEdit editingFinished signal twice when changing focus?

I've found a few similar questions on this but these appear to refer to cases where a message box is used in the slot handler. In my case I am a bit stuck as I am getting the editFinished signal twice even when my slot handler is doing nothing.
For a test, I have an array of QLineEdit which use a signalMapper to connect the editingFinished() signals to a single slot. The signalMapper passes the array index so I can see where the signal came from.
eg:
testenter::testenter(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::testenter)
{
// setup the UI according to the .h file
ui->setupUi(this);
signalMapper = new QSignalMapper(this);
// init the labels and edit boxes
for (int i = 0; i < 10; i++)
{
pm_label[i] = new QLabel(ui->scrollArea);
QString text = QString("Number %1").arg(i);
pm_label[i]->setText(text);
pm_label[i]->setGeometry(10,20+i*30, 50, 20);
pm_label[i]->show();
pm_editBox[i] = new QLineEdit(ui->scrollArea);
pm_editBox[i]->setGeometry(80,20+i*30, 50, 20);
pm_editBox[i]->show();
signalMapper->setMapping(pm_editBox[i], int(i));
connect(pm_editBox[i], SIGNAL(editingFinished()), signalMapper, SLOT(map()));
}
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(data_entry(int)));
}
void testenter::data_entry(int entry)
{
//dummy
}
When run in the debugger, if I enter data into one box then either hit return or select another box with the mouse (ie change focus) , then it calls data_entry twice, the first time with index of the box that is losing focus and the 2nd time with the box which gets the focus.
So my question: Am I missing something? Is this expected behaviour or a bug?
If a bug, anyone know a way round it as I wanted to use this signal to do custom validation on data when it is entered (by either return, tab or mouse click to change focus).
First off, no this isn't expected behavior, i.e. selecting a QLineEdit should not cause it's editingFinished signal to be emitted.
There are a couple of possible things that may cause this problem:
You've accidentally connected a signal twice to a slot
The slot map() is causing the newly selected box to lose focus
In the same vain, if you're debugging and using a break point to detect when the slots are getting called you may be causing the QLineEdit to lose focus when the active application changes from your QWidget to your debugger, again causing the signal to be sent again.
If you're having problems because of a doubly connected slot, which doesn't seem to be the case because you're specifically getting a signal from two different QLineEdits, you can make sure that this isn't happening by specifying the connection type, the connect method actually has an additional optional argument at the end which allows you to change the type from a DefaultConnection to a UniqueConnection.
That being said, data validation is something that Qt has an established mechanism for, and I suggest that you use it if possible, look into extending the QValidator abstract base class Ref Doc. You then tell each of your QLineEdit's to use the same validator.
I have run into the same issue. It really does emit the signal twice, which is a known bug: https://bugreports.qt.io/browse/QTBUG-40 which however has not been addressed for a very long time.
Finally I found that the best solution in my case is to change the signal from editingFinished to returnPressed. As a side effect this behaves much more predictably from the user perspective. See also here: http://www.qtforum.org/article/33631/qlineedit-the-signal-editingfinished-is-emitted-twice.html?s=35f85b5f8ea45c828c73b2619f5750ba9c686190#post109943
The OP "found a few similar questions on this but these appear to refer to cases where a message box is used in the slot handler." Well, that is my situation also, and here is where I ended up. So, at the risk of going off topic...
In my situation, when my slot receives the editingFinished signal sent from the QLineEdit, I launch a modal QMessageBox to ask the user something. The appearance of that message box is what triggers the QLineEdit to send the second, undesirable editingFinished signal.
A post in the bug report (https://bugreports.qt.io/browse/QTBUG-40) mentioned by #V.K. offers a workaround which helped me. The following is my implementation of the workaround. I let Qt magic mojo automatically connect the QLineEdit signal to my MainWindow slot.
void MainWindow::on_textbox_editingFinished( void )
{
QLineEdit * pTextbox = qobject_cast<QLineEdit *>( QObject::sender() );
if ( !pTextbox->isModified() )
{
// Ignore undesirable signals.
return;
}
pTextbox->setModified( false );
// Do something with the text.
doSomething( pTextbox->text() );
}
void MainWindow::doSomething( QString const & text )
{
QMessageBox box( this );
box.setStandardButtons( QMessageBox::Yes | QMessageBox::No );
box.setText( "Are you sure you want to change that text value?" );
if ( box.exec() == QMessageBox::Yes )
{
// Store the text.
m_text = text;
}
}

How do I properly set up generic QT actions for a menu constructed at run time?

I am populating a sytem tray icon menu (QMenu) from entries in an xml file which is read when my application starts up.
I am unsure of how to properly set up the SLOT end of the action:
QList<CMenuItem> menuItems = m_layout->getMenuItems();
QListIterator<CMenuItem> iter(menuItems);
while (iter.hasNext())
{
CMenuItem menuItem = iter.next();
QAction *action = new QAction(menuItem.qsTitle, this);
connect(action, SIGNAL(triggered()), this, SLOT(launchMenuItem()));
trayIconMenu->addAction(action);
}
How does my "launchMenuItem()" SLOT know which menu item was triggered? I can't make a SLOT for each menu item as I don't know how many items will exist until run time.
I can think of some ugly ways to do this, but I am looking for the RIGHT way.
What I usually do is to use QAction::setData(const QVariant&) to store whatever action ID I need. Then on slot side I retrieve ID with QAction::data() and behave accordingly.
Note that QVariant obviously accepts much more than basic int (which is what I use to identify actions), you can pass any QVariant-compatible info.
edit : oh! btw, this is somehow ugly because I make use of QObject::sender() to cast triggered action back. Sorry for that, but it works anyway.

How to override default shortcuts in Qt

I have a widget which can contain one or more QTableView child widgets. By default, when I select a range in one of QTableViews and hit crtl+c only the leftmost uppermost cell gets copied to the clipboard. I would like to copy the entire range, so I implemented a copy() slot which does the job. I would like the copy slot to be accessible both from a context menu (when the user makes a selection and right clics the corresponding QTableView) and by the ctrl+c shortcut.
class Widget
{
Q_OBJECT
public:
void setupContextMenu();
private:
QMenu* contextMenu_;
QAction* copyAction_;
QTableView* tableView_;
private slots:
void copy();
}
void Widget::setupContextMenu()
{
contextMenu_ = new QMenu(this);
copyAction_ = contextMenu_->addAction("&Copy");
copyAction_->setShortcut(QKeySequence::Copy);
connect(copyAction_, SIGNAL(triggered()),
this, SLOT(copy()));
}
When I select a range and right click, the appropriate context menu pops up and it even contains the name of the shortcut. When I click the "Copy" action in the context menu, the copy() slot gets executed. However the ctrl+c shortcut just copies only the leftmost uppermost cell in the selection as before. Also, the copy() slot does not get executed.
How can I repair this?
I am not sure but maybe shortcut key doesn't work with contextual menus in Qt?
The handling of copy shortcut happens in QAbstractItemView::keyPressEvent(). You can install an event filter to your QTableView watching for KeyPress event and handle your copy there.

QAction shortcut doesnt always work

I have a Qaction on a menu item for deleting selected items in one of my views. Here is how i create the action:
deleteAct = new QAction( tr("Delete Selected"), this);
deleteAct->setShortcut(QKeySequence::Delete);
connect(deleteAct, SIGNAL(triggered()), this, SLOT(deleteSelected()));
I setup a keyboard shortcut (Delete Key) which should trigger the delectAct action. It works most of the time but at some points it stops working... Does anyone know why the shortcut would stop working?
Note: the action still works if i trigger it from the menu item. Its just the shortcut that doesn't...
You need to add the action to a widget, since it's the widget that will be listening for key events.
Assuming "this" is a mainwindow, simply do
addAction(deleteAct);
Note that you can add the same action to multiple widgets (that's the whole point of the separated action concept). So it's fine to add it to the mainwindow and to a menu.
Try changing the shortcut context of the action, for example:
deleteAct->setShortcutContext(Qt::ApplicationShortcut);
The shortcut works depending on the focus of the application views.
I wanted to have shortcuts working on buttons.
In my application I changed the shortcut context of the action,
added the action to the widget
and finally to the subviews of the application.
Then the necessary signals and slots of widget an action must be connected.
const QAbstractButton*button = dynamic_cast<QAbstractButton*>(widget);
action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
widget->addAction(action);
ui->textBrowser->addAction(action);
ui->treeSource->addAction(action);
if (button)
{
if (button->isCheckable())
{
action->setCheckable(true);
if (button->isChecked()) action->setChecked(true);
connect(action, SIGNAL(triggered(bool)), button, SLOT(setChecked(bool)));
connect(button, SIGNAL(clicked(bool)), action, SLOT(setChecked(bool)));
}
else
{
connect(action, SIGNAL(triggered()), button, SLOT(click()));
}
}
Without seeing the complete code, I'd hazard a guess that somewhere it gets enabled/disabled. Make sure that the shortcut is getting hit in the constructor and not 'disabled' somewhere else because of a setting perhaps.
You can use http://doc.qt.io/qt-5/qaction.html#shortcutVisibleInContextMenu-prop property since QT 5.10 for this:
deleteAct->setShortcutVisibleInContextMenu(true);