Why is the signal for the QCheckBox not emitted? - c++

I am trying to insert in my UI a check box which can set a boolean variable from another class true or false according to its checked status. The problem is that the signal is not emitted.
The variable is defined in the header file of my 1st class (renderarea.h) as public:
bool selectionMode;
The slot is defined in the 2nd class' header file as void
protected slots:
void setSelectionMode(bool mode);
And the signal is connected to the slot in my 2nd class source file in the constructor as:
PaintWidget::PaintWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::PaintWidget)
{
connect(ui->selectionModeCheckBox, SIGNAL(toggled(bool)), this, SLOT(setSelectionMode(bool)));
}
void PaintWidget::setSelectionMode(bool mode)
{
ui->displayWidget->selectionMode = mode;
QMessageBox msgbox;
if (ui->displayWidget->selectionMode == true)
msgbox.setText("selection mode is true");
else
msgbox.setText("selection mode is false");
}
I am using the QMessageBox here only for testing reasons. But when debugging I saw that the signal is not emitted. What am I doing wrong?

You'll want to make sure a number of things are in place:
setupUi
connect succeeded
checkbox value really changed
First, I don't see where you called setupUi. You'll want to do this in the constructor:
PaintWidget::PaintWidget(QWidget *parent) :
QWidget(parent),
ui(new Ui::PaintWidget)
{
ui->setupUi(this);
connect(ui->selectionModeCheckBox,
SIGNAL(toggled(bool)), this, SLOT(setSelectionMode(bool)));
}
Second, make sure that the return value of connect indicates it succeeded.
Third, I presume you're manually clicking the checkbox, but for sake of testing you could do that after the connect in your constructor:
ui->selectionModeCheckBox->setChecked(true);

Just to clarify, when you say the slot is in the header file, you do mean after the slots: label, right?

You should rather use the stateChanged() signal, emitted by the checkbox when its status changes. It gives you an integer, because checkboxes can also be tristate (but you can just use that int value as a boolean, in your case).

well,I often use the checkbox in the Dialog(settingDialog, selectionDialog,etc), so signal-slot is not need in this situation,just check the checkbox state when the "OK" button is clicked, and deal with it in the accept function.In your situation, I don't think checkbox is a good choice.

Related

How to add hyperlinks in Qt without QLabel?

I have some labels and layouts nested inside a QWidget to build a part of a sidebar. Each QWidget is its own section and one component currently looks like this:
To my understanding, you can only set hyperlinks with QLabel, but I'm trying to get the whole area between the white lines clickable. This is including the icon and the whitespace. Is there any way to achieve this?
This got marked as a duplicate to the opposite of what I was asking, so I'd like to reiterate that I'm trying to implement a hyperlink without QLabel.
You can easily have a widget open a link on click:
class Link : public QWidget {
Q_OBJECT
public:
Link(QUrl url, QWidget p = nullptr) : QWidget(p), _url(url) {}
QUrl _url;
void mouseReleaseEvent(QMouseEvent *) { QDesktopServices::openUrl(_url); }
}
You can avoid any extra signals and connections, and have each link widget store its own link internally, the url can be set on construction and changed at any time. Not using signals and slots makes it easier to change the link too, without having to disconnect previous connections.
IMO going for a signals and slots solution is only justified when you want different arbitrary behavior. In this case you always want the same - to open a particular link, so you might as well hardcode that and go for an easier and more computationally efficient solution.
I would just manually catch the SIGNAL for clicked() and use desktop services to open the url in code.
bool QDesktopServices::openUrl ( const QUrl & url ) [static]
Opens the given url in the appropriate Web browser for the user's desktop environment, and returns true if successful; otherwise returns false.
http://doc.qt.io/qt-4.8/signalsandslots.html
Using this type of syntax, or in the designer, you can also connect a signal to a slot.
connect(widgetThatRepresentsURL, SIGNAL(clicked()),
handlerThatWillOpenTheURL, SLOT(clicked_on_url()));
For widgets that don't have a signal set up for clicked (or whatever event you are interested in), you can subclass the widget in question and reimplement...
void QWidget::mousePressEvent ( QMouseEvent * event ) [virtual protected]
Specifically for creating a signal, there is emit. I've used this in the past like the following
void Cell::focusInEvent(QFocusEvent *e)
{
emit focus(this, true);
QLineEdit::focusInEvent(e);
}
with the following in the header
signals:
void focus(Cell *, bool);

Enable a bool variable by pressing a button in Qt

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).

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;
}
}

Creating signals and slots qt4 gui builder

Hi im brand new to c++ and trying to get my head around the concepts.
I am creating a very simple app to get going with the help of the tutorials, so im trying to do my own first try.
I'm having problems with the file.h and file.cpp the one besides main.cpp
I would like to click the button in the button box "ok" and have text come up in the text box.
Here is MainWindow.h first
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include "ui_MainWindow.h"
class MainWindow: public QMainWindow, private Ui::MainWindow
{
Q_OBJECT
public:
MainWindow(QMainWindow *parent = 0);
private slots:
//here is where im tyring to add a slot.
void on_buttonbox_buttonClicked ( QAbstractButton * );
// void on_inputSpinBox2_valueChanged(int value);
private:
Ui::MainWindow ui;
};
#endif
Next is the MainWindow.cpp
#include <QtGui>
#include "MainWindow.h"
MainWindow::MainWindow(QMainWindow *parent)
: QMainWindow(parent)
{
ui.setupUi(this);
}
//This is where i would like to catch the clicked signal from the ok button and add the text to the text box.
void MainWindow::on_buttonbox_buttonClicked ( QAbstractButton * ){
ui.textEdit->setText(QString::number(16));
}
Im trying to be as simple as posible to just to get it going, it will compile but i can't get the signals and slots to talk, where am i going wrong.... remember brand new.
You have to connect your Slots to the Signals, add this into your constructor:
this->connect(this->ui.yourButton, SIGNAL(clicked()), this, SLOT(on_buttonbox_buttonClicked(QAbstractButton*)));
// ^
// |
// The name of your Button here ...
Also please see here: http://qt-project.org/doc/qt-4.8/signalsandslots.html
Edit:
MainWindow.cpp
MainWindow::MainWindow(QMainWindow *parent) : QMainWindow(parent)
{
ui.setupUi(this);
// Connect Signals-Slots
this->connect(this->ui.yourButton, SIGNAL(clicked()), this, SLOT(on_buttonbox_buttonClicked(QAbstractButton*)));
}
// ...
But don't forget to change yourButton to whatever you've named yours.
Alright, you have to connect the signal to the slot somewhere. You should do this on the constructor,
connect(button, SIGNAL(clicked()), this, SLOT(on_buttonbox_buttonClicked(QAbstractButton *)));
Just remember that the slot only will be called if there is a signal connect to it. Otherwise your button won´t be able to know where to go.
The mechanism of SIGNAL and SLOT is very simple and is used to register a widget(buttons, spinbox etc..) to an event. For example "when I click that button a new window will show up."
That being said, let's see how can we register our SLOT(what to do after receiving the signal) to his SIGNAL(an event: a click, a selection, an edit of a form etc..)
QObject::connect( button , SIGNAL( click()), this , SLOT( openWindow() ))
button is the widget that will throw the signal.
SIGNAL( click()) you are telling that clicking(press and release) button an action will be performed
this is the object that declare the slot
SLOT( openWindow() ) is the method(slot) will be called clicking button
Signals and slots must have same parameters!!
So to answer your question you have to declare a slot with same parameters as the signal. click() has no parameter so you have to declare your slot as:
void on_buttonbox_buttonClicked ()
PS: as I remember there is an issue naming a slot with the prefix on. But I have to do a little search because I don't remember very well.
update: I made a little test and naming the slot with the prefix on_ gives an error message at run time QMetaObject::connectSlotsByName: No matching signal for on_ClickChangeBack() but the slot execute.

QT Creator Main window - how to change the interface for each element from the menu?

I am new to QT Creator. I did create a menu: Login || Open. When login is clicked I would like to see a line edit and a press button. When Open is clicked I would like to see a picture in the window. Can I change the interface of the same window depending on what I click in the menu bar? How can I do that?
I did something similar to this - an app with several major areas, toggled by an icon bar at the top.
I used a QStackWidget to stack the different application areas on top of each other, a set of QActions that I created using the designer, and a QActionGroup to implement the toggling.
When the actions are marked as "checkable" and grouped in a QActionGroup, theQToolBar only lets one be active at the time.
Here's a simplified extract of my code:
// MyApp.h
#include <QMainWindow>
class QAction;
class QActionGroup;
namespace Ui {
class MyApp;
}
class MyApp: public QMainWindow
{
Q_OBJECT
public:
explicit MyApp(QWidget *parent = 0);
~MyApp();
public slots:
void showSection(QAction* a);
private:
Ui::MyApp *ui;
QActionGroup* sections;
};
//MyApp.cpp
#include "structureapp.h"
#include "ui_structureapp.h"
#include <QActionGroup>
MyApp::MyApp(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MyApp),
sections(new QActionGroup(this)),
{
ui->setupUi(this);
/* Populate section list */
/* Page indices for the stack widget*/
ui->actionSectionOne-> setData(0);
ui->actionSectionTwo-> setData(1);
ui->actionSectionThree-> setData(2);
sections->addAction(ui->actionSectionOne);
sections->addAction(ui->actionSectionTwo);
sections->addAction(ui->actionSectionThree);
ui->mainToolBar->addSeparator();
connect(sections, SIGNAL(triggered(QAction*)), this, SLOT(showSection(QAction*)));
/* Show the default section */
ui->actionContentSection->trigger();
}
MyApp::~MyApp()
{
delete ui;
}
void MyApp::showSection(QAction *a)
{
ui->mainArea->setCurrentIndex(a->data().toInt());
}
Yes, you can. As I explained earlier, each menu entry is a signal, and that's connected to a slot. With two different menu entries, you have two signals, and you'd connect them to two different slots. So, you could name your first slot onLogin, and the second slot onOpen. (It helps to choose descriptive names, so you'll understand your program when you come back on mondays).
Now, it the slot onLogin, you put the code for login. In the slot onOpen, you put the other code. But do consider what happens if you click the two menu entries one after another. Should that even be possible? If not, you may need another solution. It's quite common to use a QDialog for a login. When a dialog is active, you can't use the menu of the main application, so you can't accidentily hit onOpen when you're busy with the login.