I am new to QT. I have been trying to see the bridge between javascript and Qt Class.
What I did:
1) I have a button and connected clicked signal to on_pushButton_clicked, also I have qwebview instance.
In on_pushButton_clicked:
...
QUrl url = QUrl::fromLocalFile("C:\\whoami\\sd\\index.html");
QObject::connect(ui->webView->page()->mainFrame(), SIGNAL(javaScriptWindowObjectCleared()),
this, SLOT(addJSObject()));
ui->webView->page()->mainFrame()->load(QUrl(url));
....
and in addJSObject,
void MainWindow::addJSObject()
{
qDebug () <<"Inside addJSObject";
ui->webView->page()->mainFrame()->addToJavaScriptWindowObject(QString("mBridge"), m_bridge);
qDebug () <<"Nooo. I m not invoked..";
}
Problem:
It compiles without error, and html file is displayed in the qwebview, but addJSObject callback is not invoked.
Could someone help me in order to resolve this issue?.. I must have done some silly mistake. :(.
Make sure, that your MainWindow: 1) inherits QObject 2) has Q_OBJECT macro 3) has a slot addJSObject().
For example mainwindow.h:
class MainWindow : public QObject
{
Q_OBJECT
public:
MainWindow();
private slots:
void addJSObject();
};
If this is correct, you should be able to connect to addJSObject() without static QObject::connect(). Just use connect() when referring to this as signal target object.
One way to just check, that your signalling works is to try using QTimer timeout signal:
QTimer::singleShot(5000, this, SLOT(addJSObject()));
Related
I am using Qt 4.6.0 (32 bit) under Windows 7 Ultimate. Consider the following QThread:
Interface
class ResultThread : public QThread
{
Q_OBJECT
QString _post_data;
QNetworkAccessManager _net_acc_mgr;
signals:
void onFinished(QNetworkReply* net_reply);
private slots:
void onReplyFinished(QNetworkReply* net_reply);
public:
ResultThread();
void run();
void setPostData(const QString& post_data);
};
Implementation
ResultThread::ResultThread() : _net_acc_mgr(this)
{
connect(&_net_acc_mgr, SIGNAL(finished(QNetworkReply*)),
this, SLOT(onReplyFinished(QNetworkReply*)));
}
void ResultThread::onReplyFinished(QNetworkReply* net_reply)
{
emit onFinished(net_reply);
}
void ResultThread::setPostData(const QString& post_data)
{
_post_data = post_data;
}
void ResultThread::run()
{
_net_acc_mgr.post(QNetworkRequest(QUrl("http://[omitted]")),
QByteArray(_post_data.toStdString().c_str()));
}
Whenever _net_acc_mgr.post() is executed in ResultThread::run(), I got the following Application Output in Qt Creator:
QObject: Cannot create children for a parent that is in a different thread.
(Parent is QNetworkAccessManager(0x22fe58), parent's thread is QThread(0x9284190), current thread is ResultThread(0x22fe48)
What does this mean? How to solve it?
The run() member function is executed in a different thread, rather than the thread where QNetworkRequestManager object was created.
This kind of different-thread problems happen all the time with Qt when you use multiple threads. The canonical way to solve this problem is to use signals and slots.
Create a slot in the object where QNetworkRequestManager belongs to, create a signal in ResultThread and connect both of the somewhere, the constructor of ResultThread would be a good place.
The code which is currently in ResultThread::run() goes to the new slot, and is replaced by a emit(yourSignal()). If necessary send a pointer to your ResultThread as a parameter with your emit function to gain access to member functions/variables.
I received this error message when I forgot to set the QNetworkRequestManager's parent.
nam = new QNetworkAccessManager(this);
I am trying to connect QPushButton to lambda expression:
QPushButton* loadTextFileButton = new QPushButton("load");
connect(loadTextFileButton, &QPushButton::clicked, [](){
qDebug()<<"clicked";
});
Compiler gives me an errors like: No matching function to call "MyClass::connect(..."
What I am doing wrong?
The connect function, which is part of Qt's signal and slots mechanism is Qt's extension to C++.
The connect function is actually a static function of QObject, so you can use it from anywhere, by simply including QObject: -
#include <QObject>
...
QObject::connect(itemPtr1, SIGNAL(someFunction()), itemPtr2, SLOT(someOtherFunction());
The objects itemPtr1 and itemPtr2 are pointers to instances of classes that are derived from QObject and support signals and slots.
In order for a class to use the signal and slot mechanism, it must inherit from QObject and declare the Q_OBJECT macro:-
class MyClass : public QObject
{
Q_OBJECT // the Q_OBJECT macro, which must be present for signals and slots
public:
MyClass(QObject* parent);
signals:
public slots:
private:
void StandardFunction();
};
As this class inherits QObject, it now has direct access to the connect function, allowing calling connect directly:-
QPushButton* loadTextFileButton = new QPushButton("load");
connect(loadTextFileButton, &QPushButton::clicked, []()
{
qDebug()<<"clicked";
});
Finally, Qt 5 introduced a new syntax for signals and slots: -
connect(loadTextFileButton, &QPushButton::clicked, this, &MyClass::StandardFunction);
You may have noticed that the advantage here is that the signal can be connected to a function that is not declared as a slot. In addition, using this syntax provides compile time error checking.
I am using RtMidi library to handle midi message in my Qt application and I am facing problem with slot trigger:
My PhMidiInput object is emiting signal from the RtMidi callback upon specific midi message but the slots are not always triggered.
Here is a part of the PhMidiInput class:
class PhMidiInput : QObject
{
Q_OBJECT
public:
void PhMidiInput() {}
signals:
void quarterFrame(unsigned char data);
private:
static void callback(double, std::vector< unsigned char > *message, void *userData ) {
PhMidiInput *midiInput = (PhMidiInput*)userData;
if(midiInput)
midiInput->onMessage(message);
}
void onMessage(std::vector<unsigned char> *message) {
...
emit quarterFrame(data);
...
}
}
Connecting to a lambda functor works:
PhMidiInput midiIn;
int quarterFrameCount;
connect(&midiIn, &PhMidiInput::quarterFrame, [&](unsigned char data) {
quarterFrameCount++;
});
Connecting to my application window works to:
// MyWindow inherits from QMainWindow
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MyWindow::onQuarterFrame);
When trying to connect to a custom class (MidiTest) inheriting from QObject it does'nt trigger:
connect(_midiIn, &PhMidiInput::quarterFrame, this, &MidiTest::onQuarterFrame);
I was wondering if there was something around QObject::moveToThread() but since I don't create the thread myself (the signal is sent from a callback) I don't know if I need to use it or not.
It is as simple as calling emit obj->quarterFrame(data); from the callback. If the connection type is default then this will be perfectly thread safe.
Though you should create a QByteArray from data to pass around as data will likely not be valid by the time the slots get called.
void callback(..., void* user){
//user is the standard void* in most callbacks passed as reinterpret_cast<void*>(this)
unsigned char* data = ...;
QByteArray bytes(data);
emit reinterpret_cast<PhMidiInput>(user)->quarterFrame(bytes);//calling the signal which will behave as you'd expect
}
In the last connect() call you pass this and MidiTest::onQuarterFrame as the receiver object and method. I bet this is not an instance of MidiTest, is it?
The problem here is that you're passing SLOT method from MidiTest, while the receiver object is this, which is not instance of MidiTest. Change receiver from this to some instance of MidiTest.
I'm surprised this code doesn't crash your application when running.
I wrote the class and add a slot:
class graphShow : public QObject {
Q_OBJECT
public:
graphShow(){}
public slots:
void upd(QGraphicsScene &S);
};
Implementation of graphShow::upd is here:
void graphShow::upd(QGraphicsScene &S) {
QGraphicsTextItem* pTextItem = S.addText("Test");
pTextItem->setFlags(QGraphicsItem::ItemIsMovable);
}
Connection:
graphShow gr;
QPushButton* p1 = new QPushButton("Show");
/*...*/
QObject::connect(p1,SIGNAL(clicked()),&gr,SLOT(upd(&scene);));
During compiling I have no errors but when program starts I see this message:
Object::connect: No such slot graphShow::upd(&scene); in main.cpp:93
What am I doing wrong?
You need to set up connection in the following way:
QObject::connect(p1, SIGNAL(clicked()), &gr, SLOT(upd(QGraphicsScene &)));
However this also may not wark, because Qt docs state:
The signature of a signal must match the signature of the receiving
slot. (In fact a slot may have a shorter signature than the signal it
receives because it can ignore extra arguments.)
By the way, you doing it wrong. You could not connect signal without arguments to slot with argument. For your case you should use QSignalMapper.
I have a custom class derived from QGraphicsPixmapItem. Its called GraphPixmapItemCustom and it's overloaded method is:
void GraphPixmapItemCustom::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
QGraphicsPixmapItem::mousePressEvent(event);
GraphMarkItemCustom *ptr;
if(event->button() == Qt::RightButton)
{
qDebug("Before emit");
emit addPoint(QPointF(event->pos().x(), event->pos().y()));
qDebug("After emit");
markList.append(new GraphMarkItemCustom(QPointF(event->pos().x(), event->pos().y())));
ptr = markList.last();
markGroup->addToGroup(ptr);
//this->scene()->addItem(ptr);
}
}
the signal is declared at header:
signals:
void addPoint(QPointF position);
In main class that has a pointer to object of class GraphPixmapItemCustom called
private:
GraphPixmapItemCustom *pixItemRGB;
and in the main class I have a slot called:
private slots:
void pointAdd(QPointF position);
In the main class constructor I have a connection:
connect(pixItemRGB, SIGNAL(addPoint(QPointF)), this, SLOT(pointAdd(QPointF)));
In the slot I have only qDebug("YUPPY IT ACTUALLY WORKS!");
But the slot is not beeing fired. Why? I have deleted all moc files and everything that didn't have to be there. So only .pro, .h and .cpp files along with .ui forms where neccesary were left.
I have checked most hits at Google. What is the best (I'm not sured - maybe i modified something) that it worked! I remember the working effects of this connection. Help!
You have to connect the signal after creating the GraphPixmapItemCustom object with the new operator.