Hi everyone,
I am trying to send the http post request from my qt app. I have read alot and still struggling to get some concepts of signals and slots. Would be nice if somebody can help me out from here..
here is my qml code snippet:
TextField { id: u_name; placeholderText: userText(); Layout.fillWidth: true; style: StyleTextField {} }
TextField { id: p_text; echoMode: TextInput.Password; Layout.fillWidth: true; style: StyleTextField {} }
Button {
id: signInButton
text: "Sign In";
style: StyleButton {}
Layout.fillWidth: true;
//Layout.alignment: Qt.AlignTop;
signal esLoginClicked()
onClicked: {
if (u_name.text.length) Settings.userText = u_name.text;
if (p_text.text.length) Settings.passText = p_text.text;
signInButton.esLoginClicked().connect(esLogin(u_name.text, p_text.text));
page_stack.pop();
}
}
Here I am trying to get username and password from user and want to pass it to slot "esLogin" that I have declared in my header file using signal esLoginCLicked() which I have created here only. My header files looks like this...
Q_OBJECT
Q_PROPERTY(QString userText READ userText WRITE setUserText NOTIFY userTextChanged)
Q_PROPERTY(QString passText READ passText WRITE setPassText NOTIFY passTextChanged)
public:
static esQuickSettings *instance(void);
public:
QString userText(void);
QString passText(void);
// void esLoginClicked(void);
// void esLoginClicked(const QString& userText, const QString passText);
public:
void setUserText(const QString& user);
void setPassText(const QString& passt);
void esLogin(const QString& userText, const QString& passText);
signals:
void userTextChanged(void);
void passTextChanged(void);
but somehow I am not able to make it work and missing some key concept here to make signal and slot work.
P.S: I want to take input from QML and put in slot which will have the definition in cpp file respective to header.
There are (at least) two ways to address this issue, but I will only let you know one of them based on the comment discussion.
Connect the QML signal to the C++ slot.
main.qml
...
Button {
id: signInButton
// This is necessary for finding this nested item in C++
objectName: "SignInButtonObjectName"
...
}
...
main.cpp
...
QQmlEngine engine;
QQmlComponent component(&engine, "main.qml");
QObject *object = component.create();
QObject *childObject = object->findChild<QObject*>("SignInButtonObjectName");
Foo foo;
QObject::connect(childObject, SIGNAL(esLoginClicked(const QString&, const QString&)), &foo, SLOT(esLogin(const QString&, const QString&)));
...
The other approach would be to call the C++ slot in your qml code when the signal happens to be emitted which is probably even simpler. In that case, you would make the method below either Q_INVOKABLE or even better: a slot.
void esLogin(const QString& userText, const QString& passText);
Then, you would need to make sure that this method is exposed to qml via context properties, namely: you would make the class a context property which would be available to qml for calling like foo.esLogin() in your desired qml signal handler.
Related
New question for you guys.
I have a simple kde (kf5) plasmoid, with a label and two buttons.
I have a C++ class behind the scenes, and I am currently able to send signals from C++ to qml.
The problem: I need to send signals from the qml buttons to the C++ class.
Usually this could be done by using the standard Qt/qml objects like QQuickView and so on, but in my case I have no main.cpp.
This is my C++ class header. Using a QTimer, I emit the textChanged_sig signal, which tells the qml to refresh the label's value:
class MyPlasmoid : public Plasma::Applet
{
Q_OBJECT
Q_PROPERTY(QString currentText READ currentText NOTIFY textChanged_sig)
public:
MyPlasmoid( QObject *parent, const QVariantList &args );
~MyPlasmoid();
QString currentText() const;
signals:
void textChanged_sig();
private:
QString m_currentText;
}
This is the plasmoid main.qml:
import QtQuick 2.1
import QtQuick.Layouts 1.1
import org.kde.plasma.core 2.0 as PlasmaCore
import org.kde.plasma.plasmoid 2.0
import org.kde.plasma.components 2.0 as PlasmaComponents
Item {
Plasmoid.fullRepresentation: ColumnLayout {
anchors.fill: parent
PlasmaComponents.Label {
text: plasmoid.nativeInterface.currentText
}
PlasmaComponents.Button {
iconSource: Qt.resolvedUrl("../images/start")
onClicked: {
console.log("start!") *** HERE
}
}
}
}
The PlasmaComponents.Label item contains the correct value of the c++ field m_currentText.
*** HERE I need to emit some signal (or invoke a c++ method, would have the same effect).
Any hint?
Since you can access the currentText property through plasmoid.nativeInterface that object is almost certainly an instance of your C++ applet class, i.e. a MyPlasmoid instance.
So if your MyPlasmoid has a slot, it can be called as a function on the plasmoid.nativeInterface object
in C++
class MyPlasmoid : public Plasma::Applet
{
Q_OBJECT
public slots:
void doSomething();
};
in QML
onClicked: plasmoid.nativeInterface.doSomething()
i have a problem of using signals in QML.
i have created a signal in the cpp file and i want to use it in the qml file
the file AppUI.hpp:
Class ApplicationUI: public QObject {
Q_OBJECT
Q_PROPERTY(bool loading READ loading NOTIFY loadingChanged)
public:
Q_SIGNALS:
void loadingChanged();
private:
bool _loading;
bool loading() const;
...
}
in the file AppUI.cpp:
ApplicationUI::ApplicationUI(bb::cascades::Application *app) :
QObject(app),_loading(false) {
...
traitment
_loading=false;
emit lodingChanged();
}
bool AppnUI::loading() const{
return _loading;
}
and in QML file:
MapView {
id: mapview
objectName: "mapViewObj"
visible: !_mapViewTest.loading
}
ActivityIndicator {
visible: _mapViewTest.loading
running: _mapViewTest.loading
}
but the problem here is that i get this ERROR on the console
Error: NOTIFY signal 'loadingChanged' of property 'loading' does not exist in class ApplicationUI.
First, in c++, in order for your data member loading to be visible to QML, you first need to create a public getter, and put it into qproperty like follows:
Q_PROPERTY(bool getloading READ getloading NOTIFY loadingChanged)
public bool getloading() const;
This is because QML cannot access private member in c++ class.
Also, in QML, you can use a signal in c++ like so:
onCreationCompleted: { // or other function
_mapViewTest.lodingChanged.connect(whatyouwanttodo);
}
function whatyouwanttodo() {
// do something
}
Note that your signal and function connected need to have the same param list
Is there a way of accessing signals(such as clicked()) of a QML control such as a button, from c++. Assume that I have the memory address of that specific control. I just want to simulate a click event from c++ code.
Easy. You just create a slot in a C++ object that has a QObject base to it, make sure its registered as a QML type, then you "instantiate" it in the QML document, and connect the desired signal to the C++ object through QML using connect() and handle the logic from the C++ side.
Example:
I have a Rectangle I want to get the onWidthChanged signal from and use it in my class ShapeTracker which tracks when shapes change or whatever
in main.cpp:
#include "shapetracker.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
/* this is where you register ShapeTracker as a QML type that can be
accessed through the QML engine even though its a C++ QObject */
qmlRegisterType<ShapeTracker>("my_cpp_classes", 1, 0, "ShapeTracker");
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
then in
main.qml
import QtQuick 2.6
/* import the C++ class you registered into this QML document */
import my_cpp_classes 1.0
Window {
visible: true
Item {
/* set up a parent item that has a signal which is exposed to
the ShapeTracker object and the Rectangle you want to track */
id: myRootItem
signal rectangleChanged(var newWidth)
/* Heres our special Rectangle from QML that will send a signal when
its width changes */
Rectangle {
id: specialRectangle
width: 250
/* send the signal rectangleChanged(width) from our parent item
root item whenever width changes
*/
onWidthChanged: function() { rectangleChanged(width); }
}
/* Special Button that when clicked enlarges the Rectangle but
10px */
Button {
id: mySpecialButton
onClicked: { click_handler(mouse); }
function click_handler(mouse): {
if (specialRectangle.width < 500)
specialRectangle.width += 10;
}
}
/* Heres the actual ShapeTracker instance, which exists
as a QObject inside of the QML context, but has its methods
which are declared in C++, and exposed to the QML engine */
ShapeTracker {
id: myShapeTracker
/* similar to a constructor, but more like a callback */
Component.onCompleted: {
/* connect our signal from the parent root Item called
"rectangleChanged" to the ShapeTracker's Slot called
"myRectangleChangeHandler" */
myRootItem.rectangleChanged.connect(myShapeTracker.myRectangleChangeHandler);
/* connect send_mouse_click to the click_handler of
the button */
myShapeTracker.send_mouse_click.connect(mySpecialButton.click_handler)
}
}
}
}
in shapetracker.h you simply add a new slot with the name myRectangleChangeHandler and it will receive that signal whenever it is send via QML to be processed via C++
class ShapeTracker : public QObject {
Q_OBJECT
public:
ShapeTracker(QObject *parent = 0 );
signal:
void send_mouse_click(QMouseEvent *event);
public slots:
void myRectangleChangeHandler(QVariant newWidth) {
/* Perform a mouse click on our QML Object mySpecialButton
using QQuickItem::mousePressEvent and sending it via
signal back to QML */
QMouseEvent myEvent(QEvent::MouseButtonPress, QPointF(1,1), Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QMouseEvent* pressEvent = QQuickItem::mousePressEvent(&myEvent);
emit send_mouse_click(pressEvent);
}
};
In Summary, you expose a C++ QObject to QML, then you use
object.signal.connect(cppObject.desired_slot)
To connect them -- all the extra stuff was for a functional example in case anyone needs it later
In reality, you don't even need this functionality because anything happening in an onClick event could just as easily be put into any other property such on
Rectangle {
id: rect
signal customClick(var var1)
onCustomClick : { console.log(var1); }
}
Item {
rect.customClick(1);
}
The easy way would be to call all the receiving SLOTS manually. But that would be tedious and error prone.
You might try implementing a sub-class of QObject that has one slot onClicked() which emits the signal clicked() and use it as a shim between the button and elements controlled by the button. Connect the button clicked() to the new object onClicked() and then connect the new object to the original receivers. Then calling onClicked() would trigger the behavior.
This is a very simple example, and I haven't run it through the compiler.
ButtonShim.hpp
#include <QObject>
class ButtonShim : public QObject {
Q_OBJECT
public:
ButtonShim(QObject *parent = 0);
virtual ~ButtonShim();
public slots:
void onClicked();
signals:
void clicked();
};
ButtonShim.cpp
#include "ButtonShim.hpp"
ButtonShim::ButtonShim(QObject *parent) : QObject(parent) {
}
ButtonShim::~ButtonShim() {
}
void ButtonShim::onClicked() {
// All we do here is emit the clicked signal.
emit clicked();
}
SomeFile.cpp
#include <bb/cascades/Button>
#include "ButtonShim.hpp"
...
ButtonShim * pButtonShim = new ButtonShim(pButton); // pButtonShim will live as long as pButton
bool c = connect(pButton, SIGNAL(clicked()), pButtonShim, SLOT(onClicked()));
c = connect(pButtonShim, SIGNAL(clicked()), pSomeObject, SLOT(onButtonClicked()));
...
// to simulate a click of pButton
pButtonShim->onClicked();
SomeFile.qml
// assuming ButtonShim has been exposed to QML from your application
...
attachedObjects: [
ButtonShim {
id: buttonShim
onClicked: {
clickedLabel.text = "I've been clicked";
}
}
]
...
Label {
id: clickedLabel
text: "I haven't been clicked"
}
Button {
text: "Click Me"
onClicked: {
buttonShim.onClicked();
}
}
I think that you can look at code for tests. There they get object from QML file loaded into engine.
If you have an QObject you can just call signal because, AFAIR
public signals:
void clicked();
is expanded by moc into
public:
void clicked();
I'm trying to change text of a class Label from another class. I have class MainWindow, which contains Label.
I also have a Bot class from which I wanna change the value of label.
I'm trying to create signal and slots but I have no idea where to start.
I created signal and slots like so:
//in mainwindow.h
signals:
void changeTextSignal();
private slots:
void changeText();
//in mainwindow.cpp
void MainWindow::changeText(){
this->label->setText("FooBar");
}
But I have no idea how to connect a signal to be able to change Label's text from another class.
Read up on Qt signal-slot mechanism. If I understand you correctly, you are trying to signal from Bot to MainWindow that the Label text needs to change. Here's how you do it...
//bot.h
class Bot
{
Q_OBJECT;
//other stuff here
signals:
void textChanged(QString);
public:
void someFunctionThatChangesText(const QString& newtext)
{
emit textChanged(newtext);
}
}
//mainwindow.cpp
MainWindow::MainWindow
{
//do other stuff
this->label = new QLabel("Original Text");
mybot = new Bot; //mybot is a Bot* member of MainWindow in this example
connect(mybot, SIGNAL(textChanged(QString)), this->label, SLOT(setText(QString)));
}
void MainWindow::hello()
{
mybot->someFunctionThatChangesText("Hello World!");
}
I'm running around in circles about this. Just can't wrap my head around signals and slots.
Just looking for some mechanism that can automatically update my UI when a signal in my C++ occurs.
Example:
I have two labels in Qml that have text: _app.method that returns a value.
I have a button that onClicked runs a Q_INVOKABLE method. That method emits a signal when it's done, eg, fetches geocordinates and updates the values that the above text: assignments rely on.
What I want is SOMETHING to update the text: assignments once those values change.
I just need these signals / slots explained plainly. The only examples in documentation seem to assume ONLY QML or C++ but not a mix of both. The sample code have examples, but not explained specifically in documentation.
If you had plain description, im sure I could adapt to it. Eg, 1: define this in QML, 2: define this in hpp file, 3: define these in cpp file.
I've tried using QObject's setPropery("text","value") but my app crashes when attempting this.
Tell me if i'm wrong...
1) in QML:
Button {
id: aButton
text: _app.value
onClicked: {
_app.valueChanged.connect(aButton.onValueChanged);
_app.value = _app.value + 1;
}
function onValueChanged (val) {
aButton.text = "New value: " + val;
}
}
2) in HPP:
Q_PROPERTY(int value READ value WRITE setValue NOTIFY valueChanged)
public:
int value();
void setValue(int i);
signals:
void valueChanged(int);
private:
int m_iValue;
3) in CPP:
int class::value()
{
return m_iValue;
}
void class::setValue(int i)
{
// name is same as HPP WRITE Q_PROPERTY statement
m_iValue = i;
emit valueChanged(m_iValue);
}
So, what happens is that, in QML, the onClick method CONNECTS the signal with a QML Function; which means, now we're listening for a value change, and when it does, that function will be called. THEN, we change the value... since the Q_PROPERTY set the write value to a function called setValue, setValue is called with the new value; internally, m_iValue is changed, and an emit occurs, which tells whoever is listening to valueChanged that there's a new value.
Hey, my QML is listening to that! (via the _app.valueChanged.connect script). So, the QML object (the Button) that was listening to that, has it's onValueChanged function called, with the new value (because of the emit valueChanged(m_iValue).
Please tell me i've figured this out??!?!
If you are using Q_PROPERTY macro, there's no need to bind onValueChanged signal with a function explicitly to change button's text. And also you need not emit valueChanged signal with m_iValue. Make below mentioned changes in corresponding files
QML:
Button {
horizontalAlignment: HorizontalAlignment.Center
verticalAlignment: VerticalAlignment.Center
id: aButton
text: _app.value
onClicked: {
_app.value = _app.value + 1
}
}
HPP:
signals:
void valueChanged();
CPP:
emit valueChanged();