C++ QT5 TextEdit append - c++

connect
{connect(ui->add, SIGNAL(clicked()),ui->text,SLOT(text.append(line)));}
question
I want to add a function that is appended to the lower text window when I enter a string in the upper line window and click Add, but the function does not work.

You can connect your button to a lambda slot to do what you want in Qt5 style like this:
connect(ui->add, &QPushButton::clicked, this, [this]() {
ui->text->append(line);
} );

I assume your 'ui->add' is the button and 'ui->text' is the QTextEdit? If that's the case, as suggested by Farshid616, you need to use a lambda. Why? two reasons:
In Qt's Signals & Slots, if you want to pass an argument to the SLOT, you need to return it in the SIGNAL. In your case, clicked() doesn't return anything (see function signature here), while append(const QString &text) takes a string (see here).
Lambdas are an easy way to overcome this issue by using connect(const QObject *sender, PointerToMemberFunction signal, Functor functor), where we use a lambda as the functor (see an example bellow). This is an overloaded connect call (see the signature here).
QObject::connect(your_button, &QPushButton::clicked, [this]() {
your_text_edit->append(your_line_edit->text());
} );
Note: you need to "capture" this (current object pointer) in the lambda in order to be allowed to access your_text_edit and your_line_edit, which are members of this (i.e. this->your_text_edit and this->your_line_edit). The capture of this is by reference. You can see this more clearly if we write a bit more explicitly the code above:
QObject::connect(this->your_button, &QPushButton::clicked, [this]() {
this->your_text_edit->append(this->your_line_edit->text());
} );

Related

Senders objectName is absent | QT & Cpp

I have created a little UI with a simple toolbar. I am initing the toolbar within the initToolbarfunction. This function is within a Class inheriting from QMainWindow.
void Main_Frame::initToolBar() {
rectangle.setText(rectangle_text);
circle.setText(circle_text);
triangle.setText(triangle_text);
triangle.setObjectName(triangle_id);
circle.setObjectName(circle_id);
rectangle.setObjectName(rectangle_id);
toolBar.addAction(&triangle);
toolBar.addAction(&circle);
toolBar.addAction(&rectangle);
connect(
&toolBar, &QToolBar::actionTriggered, this, [=]() {
process_toolbar_ac_evt(*sender());
});
}
I want any tool bar events to be processed through process_toolbar_ac_ect(QObject obj). Within that method, I want to decide what action (within the toolbar) has been triggered.I want to do this by the objectname. Therefore I have given any action an object name. But when I call sender().objectName() I get an empty QString.
My suggestion is, that sender returns a pointer to on of my actions that I put to the toolbar. If this is the case, why I get an empty QString on the sender()?
void Main_Frame::process_toolbar_ac_evt(QObject &evt) {
if (evt.objectName() == circle_id) {
// If circle action has clicked, to this ...
}
}
As you are connecting to one of QToolBar's signals the sender() will be your tool bar object.
Simply use the QAction argument that is passed in the QToolBar::actionTriggered signal. That's what it is for.
NB: Avoid QObject::sender() wherever possible. It virtually breaks the desired decoupling achieved by signals and slots.

Determine which Shortcut is pressed in Qt

I have a QAction which I've assigned multiple shortcuts to it
test = new QAction();
this->addAction(test);
QList<QKeySequence> shortcuts;
shortcuts << QKeySequence(Qt::Key_N) << QKeySequence(Qt::Key_T);
test->setShortcuts(shortcuts);
connect(test,SIGNAL(triggered()),this,SLOT(SomeFucntion()))
In SomeFucntion I need to know which shortcut was pressed....Is there anyway of knowing that ?
You could try a more elaborate pattern with QSignalMapper that avoids the need to define as many actions as many shortcut you need, but requires c++11 (at least this implementation).
In the constructor of your window use the following code to declare your QShortcut objects and a QSignalMapper:
QSignalMapper* signalMapper = new QSignalMapper(this);
QShortcut* sc1 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_N), this);
QShortcut* sc2 = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_T), this);
connect(sc1, &QShortcut::activated, signalMapper, static_cast<void (QSignalMapper::*)(void)>(&QSignalMapper::map));
connect(sc2, &QShortcut::activated, signalMapper, static_cast<void (QSignalMapper::*)(void)>(&QSignalMapper::map));
signalMapper->setMapping(sc1, sc1);
signalMapper->setMapping(sc2, sc2);
QAction* action = new QAction();
connect(signalMapper, static_cast<void (QSignalMapper::*)(QObject*)>(&QSignalMapper::mapped),
[action](QObject *object){
QShortcut* sc = qobject_cast<QShortcut*>(object);
if (sc)
{
action->setData(sc->key().toString());
action->trigger();
}
});
connect(action, &QAction::triggered, this, &MainWindow::doStuff);
The 3rd connection is required because of the way QSignalMapper works: when a shortcut is activated, it will be notified to the QSignalMapper thanks to the 1st and 2nd connections, that will trigger the map() slot.
The QSignalMapper::map() slot will scan its mappings, made with the setMapping() API, whose first argument is the mapped object, and the second one is the parameter that will be used to emit the mapped() slot of the QSignalMapper, once the emitting object is identified. To do so, it uses the sender() method and simply compares the pointer returned to the mapped QObject pointers you provided as mappings.
Once the QObject is identified, QSignalMapper will emit the QSignalMapper::mapped(QObject*) signal, whose argument is the second argument given to setMapping, and in this case it the same as the first one, that is again a pointer to the QShortcut that was activated.
I used a lambda to catch this signal, and inside this lambda I simply check that the parameter given is a QShortcut pointer, and store its key sequence inside the data member of the QAction before triggering the action itself. The QAction::trigger() slot will then emit the QAction::triggered() signal that will in turn invoke your custom slot, in this case doStuff(). There you can retrieve the key sequence and do what you want with it.
So your slot implementation should look similar to this one:
void MainWindow::doStuff()
{
// use sender() to fetch data from action
QAction* act = qobject_cast<QAction*>(sender());
if (act)
{
QString sequence = act->data().toString();
// debug output will show you the triggering key sequence
qDebug() << sequence;
// use sequence string to determine which shortcut was used
// On Mike hint: better to reset data after use :)
act.setData(QVariant());
}
}
Note that I'm using a mapping based on QObject pointers. In this way you can reuse the signalMapper instance to connect events from other kind of QObjects (e.g. QPushButtons) and identify them in your custom slot as well setting a proper value for the QAction data member, that can store a generic QVariant istance.
Also when using QShortcut, be aware of their contex, that is when they are active, as it could be at widget or a window scope.
Unfortunately this pattern violates pure oop principles, but could be better than managing many actions (icon, text, tooltip etc...) for the same purpose.
EDIT: to answer comments
First of all, let me clarify that you can of course skip the use of QSignalMapper at all. This is just a possible solution (not the better, maybe an overkill... but not really worse in terms of performance).
A simpler way, as pointed by Mike in the comments consists in using lambdas for each QShotcut::activated signal, but this will result in copy/paste code, that I always try to avoid.
You can instead define a custom slot inside the MainWindow and use sender() to catch the QShortcut and prepare the action before triggering it.
Anyway, QSignalMapper IMHO, better explains what you are doing (from a semantic point of view) and is more flexible in case you need to expand the connection to other QObjects, supporting also other type of mappings.
Furthermore, but this is related to my personal taste, I like the idea to have fragments of code that are logically tied condensed into small snippets, instead of have it sparse among several slot/functions because it makes it easier to read and to trace back when I need to change it, of course only if this does not hurt the quality of code itself.
You should create a separate QAction for each shortcut and group them using a QSignalMapper.

Qt custom QPushButton clicked signal

I want to send two integers, string and fret, to a SLOT that will process the location of the button that was pressed. The SIGNAL and SLOT argument have to match so I am thinking I need to reimplement the QPushButton::clicked event method. Problem is I am new to Qt and could use some direction.
connect(&fretBoardButton[string][fret], SIGNAL(clicked()), this, SLOT (testSlot()));
If you use the C++11 connection syntax you can use a lambda with calls testSlot with your string and fret arguments:
connect(&fretBoard[string][fret], &QPushButton::clicked, [this, string, fret]() {
testSlot(string, fret);
});
This code creates a lambda using the [captures, ...](arguments, ...) { code } syntax. When you make the connection it captures the string and fret variable values, and will then pass them on to testSlot when the button is clicked.
There are Two approaches you could use to add the string and fret information. one is to use the sender() function to get the button which emitted the signal. you can the access fret and string if they are members of your button class so in the SLOT you would have.
MyPushButton *button = (MyPushButton *)sender();
button.getFret();
button.getString();
However since you are already subClassing QPushButton you could use a private SLOT to catch the buttonClicked signal and re-emit a signal with the right values.
In the constructor
connect(this, SIGNAL(clicked()), this, SLOT(reemitClicked()));
and then the reemit SLOT
void MyPushButton::reemitClicked()
{
emit clicked(m_fret, m_string);
}
be sure to add the appropriate private slot and public signal to you class
https://doc.qt.io/archives/qq/qq10-signalmapper.html see this artical for a good discussion on various ways to add an argument to signal.

How do I get a signal to call a function with certain arguments?

I want to get a signal to call a function with certain arguments, like the example below.
QPushButton *yes = new QPushButton("Yes");
yes->connect(yes, SIGNAL(clicked()), NULL, SLOT(printf("You pressed a button")));
How do I accomplish this?
An often overlooked way to reverse signal/slot relationships is QObject::sender. You can call it in the receiving slot to get a handle on the QPushButton (using qobject_cast) and get the text from there. Alternatively you can use QSignalMapper to augment signals.
It seems very inefficient but you could create a new signal with a QString argument, which you connect to your pushbutton. The text contained will be defined on your emit call.
eg.
connect(yes, SIGNAL(clicked()), this, SLOT(emitHelloWorldText());
connect(this, SIGNAL(emitText(QString)), receiver, SLOT(dostuffWithText(QString)));
then your emitHelloWorldText method can be something like
void emitHelloWorldText() {
emit emitText("Hello world");
}
Then this can be picked up by your receiver class
void doStuffWithText(const QString &text) {
Unfortunately, the slot and the signal must have matching arguments. If you really need to stick with this interface, you could create an intermediary slot to propagate the received signal, but there’s no real way around.

Qt: connecting signal to slot having more arguments

I want to connect a signal clicked() from the button to a slot of different object.
Currently I connect signal to helper method and call desired slot from there:
connect(button, SIGNAL(clicked()), this, SLOT(buttonClicked()));
void buttonClicked() { // Helper method. I'd like to avoid it.
someObject.desiredSlot(localFunc1(), localFunc2());
}
But maybe there is a more simple and obvious way to do this?
is this what you want to do:
the signal clicked should be connected to the "desiredSlot" which takes two arguments that are returned by localFunc1 & 2 ??
this is not possible, as you can read in the QT docs. A slot can take less arguments than provided by the signal - but not the opposite way! (The documentation says "This connection will report a runtime error")
This ought to work with the new signal/slot mechanism in qt 5:
connect( button, &QPushButton::clicked, [&](){ someObject.desiredSlot( localFunc1(), localFunc2() ); } );
You will need to adjust the lambda capture to your needs.
In some cases, default arguments may help, e.g. declare desiredSlot as:
desiredSlot(int a=0, int b=0)
You cannot access members in default argument though.
That is not the way to connect signals and slots in QT. You should use:
connect(button, SIGNAL(clicked()), receiver, SLOT(slotToBeCalled());
Have a look at the QT documentation.