Qt update an image in the UI through callback - c++

I have a function streamCamera(*callback) where the callback is void callback(Image) which can be used to preview the stream in any UI framework we want.
I was able to stream with this function in a opencv imshow window
void callback(image)
{
cv::imshow("image", image);
waitKey(1);
}
while the imshow is a static function and was able to stream.
Is there anything similar i can do with Qt?
What I tried,
I have a class MainWindow which inherits QMainWindow, inside the class i have attached a QGraphicsPixmapItem pixImage into the ui with ui->graphicsView->scene()->addItem(&pixImage);
since the pixImage is not accessible to the callback function, cause the Mainwindow object is not global. I was not able to set image in the pixmap;
So i ended up doing a hack, just created a global pointer a QGraphicsPixmapItem *pixImagePtr and attached the pixImage before starting the streamCamera(*callback) and inside the callback i use the pixImagePtr to set the image GUI, and it worked.
But this hack seems like not the right way to do, so it would be helpful if some qt experts shed some light on it.

Sounds like something that should be done with signals.
Let's say you have your MainWindow and Worker class.
Worker wants to show some image inside the MainWindow, you can do it like this.
class MainWindow : public QMainWindow {
Q_OBJECT
// Other members
public slots:
void showImage(const QPixmap &pixmap) {
pixImage.setPixmap(pixmap);
}
};
class Worker : public QObject {
Q_OBJECT
public:
Worker(MainWindow* parent) : QObject{parent} {
connect(this, &Worker::pixmapChanged,
parent, &MainWindow::showImage);
}
signals:
void pixmapChanged(QPixmap pixmap);
}
From now inside Worker you should be able to use pixmapChanged signal to change MainWindow image like so.
const QPixmap pixmap = getNewPixmap();
emit pixmapChanged(pixmap);

Related

Qt reimplement function

I need to subclass qt class and reimplement the virtual function.
Say that i have the QLCDNumber class and I want to reimplement the function that set the position of the number when resize the LCD number screen, how to achieve that?
I read that by inhert a class from QLCDNumber and reimplement the function,
but where to get that function code so that I can edit what needed in that function? I read the documentation but it explains the function uses and not show its code. Example image:
I mentioned the QLCDNumber class as example, I need to know the prosses of reimplemnt a virtual Qt class function.
For this particular problem you can use this type of approach where you can create an object which inherits QWidget and implement the paintEvent() of the class like this:
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
protected:
void paintEvent(QPaintEvent *pe);
signals:
public slots:
};
and in the paintEvent()
void MyWidget::paintEvent(QPaintEvent *pe)
{
QPainter *painter = new QPainter(this);
painter->begin(this);
// draw what you want here using painter
// and consider your different layouts
painter->end();
}

How to set QPixmap in QQuickImageProvider class from another class?

I am developing an application using QML and C++, the goal is to download an image named "test.jpg" from a HTTP server and show it in a QML Image component without saving it in hard disk drive.
The class "AppController" downloads the image "test.jpg" from server and store in a global QPixmap variable named "imageReadFromServer".
#ifndef APPCONTROLLER_H
#define APPCONTROLLER_H
#include <QObject>
class AppController : public QObject
{
Q_OBJECT
public:
AppController(QObject *parent = 0);
Q_INVOKABLE void sendImage(QString _imagePath, QString serverLocation);
Q_INVOKABLE void readImage(QString serverLocation);
private:
QByteArray serverResponse;
QPixmap imageReadFromServer;
};
#endif // APPCONTROLLER_H
To display images on QML Image component I know that it is necessary to use "QQuickImageProvider" class, I have done one class named "ImageProvider" and reimplemented its virtual method QPixmap requestPixmap() to handle when QML requests image showing. To test if everything was working well until now, I used the next example code provided by Qt documentation that returns a QPixmap filled with blue color:
QPixmap ImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize)
{
qDebug() << "pixmap requested";
int width = 160;
int height = 100;
if(size)
*size = QSize(width,height);
QPixmap pixmap(requestedSize.width() > 0 ? requestedSize.width() : width,
requestedSize.height() > 0 ? requestedSize.height() : height);
pixmap.fill(QColor("blue").rgba());
//return pixmap;
return pixmap;
}
In main.cpp I added its respective image provider.
engine.addImageProvider(QLatin1String("imagefromserver"), new ImageProvider);
When download button is clicked on QML, it calls ImageProvider class method successfully:
onClicked: {
imageVisualizer.visible = true
imageVisualizer.source = "image://imagefromserver/"
}
What I need is:
When requestPixmap() method from ImageProvider class is called, it should return the global variable imageReadFromServer already stored in AppController class.
I have tried to make AppController class inherits directly from QQuickImageProvider but it didn't work because imageReaderFromServer value was weirdly cleared just before call requestPixmap().
I thought that I could use SIGNALS and SLOTS to pass QPixmap between classes but QQuickImageProvider doesn't inherits from QObject, so I cannot use them.
I appreciate any suggestion.
Thanks.
EDIT
I have again tried to implement QQuickImageProvider inheritance in AppController class. It is already working, the mistake was in main.cpp file, I was declaring image provider as shown below:
AppController applicationController;
QQmlApplicationEngine engine;
engine.addImageProvider(QLatin1String("imagefromserver"), new AppController);
This created a new instance of AppController class, and when I accessed to requestPixmap() function it couldn't get the global QPixmap variable imageReadFromServer because it was created in the instance named applicationController. The solution was to assign the same instance to imageProvider as shown below:
engine.addImageProvider(QLatin1String("imagefromserver"), &applicationController);

Qt4: connect slot and signal from other forms

I have a small problem. I want run function in MainWindow from AnotherWindow. I can't set connect() for it.
Main class: MainWindow
Other form: AnotherWindow
Function in main class: setVariable(QString)
Function in other form: btnClicked()
I have now connected button signal clicked():
// In AnotherWindow.cpp
connect(ui->btnOK, SIGNAL(clicked()), this, SLOT(btnOkClicked()));
// Function in same file
void interfaceWindow::btnOkClicked() {
/* Some actions - emit signal? */
this->close();
}
btnOkClicked() are declared as private slot.
// In MainWindow.cpp
void MainWindow::setVariable(QString _var) {
this->var = _var;
}
setVariable(QString) are declared as public slot.
How I can send variable from AnotherForm (from btnOkClicked() function) to MainWindow (setVariable(QString) function) ? How and where I must send signal and make connection?
I readed about signals and slots, but my code don't work - I don't paste it here because it's terrible :)
Any help for Qt newbie?
You need to have an reference of AnotherWindow in MainWindow OR vice versa. Then you need the following things:
// AnotherWindow.h
signals:
void buttonOkClickedSignal(QString var);
// AnotherWindow.cpp
void interfaceWindow::btnOkClicked() {
emit buttonOkClickedSignal("The button got clicked!");
this->close();
}
Next step varies based on whether MainWindow has reference to AnotherWindow or vice versa. You can either:
// AnotherWindow.cpp
connect(this, SIGNAL(buttonOkClickedSignal(QString), &mainWindow, SLOT(setVariable(QString)));
or:
// MainWindow.cpp
connect(&anotherWindow, SIGNAL(buttonOkClickedSignal(QString), this, (SLOT(setVariable(QString)));
If you are invoking the slot through signal it shouldn't matter whether it's private or public (see Qt Documentation).
Hope this helps.
I'm not entirely sure I understand your question, but let me try.
You want to be able to fire a slot in another class. There are a few ways you can do that.
Declare one as a friend class to the other. Then they can see the protected and private variables/memebers
It is possible to make slots static so you can call them without a class object.
For example,
class MainWindow {
private slot:
void setVariable(QString);
}
class AnotherWindow {
friend class MainWindow;
MainWindow *window;
public:
AnotherWindow() {
connect(this, SIGNAL(fire(QString)), window, SLOT(setVariable(QString)));
}
signals:
void fire(QString);
public slots:
void onButtonClicked() {
emit fire(QString);
}
}
The previous is pseudocode so don't expect it to compile. I think this is what you want. Basically since your slot is private on MainWindow you need to make it a friend. To connect, it needs to be a member. Then when the onButtonClicked slot is evoked, then it fire()s the setVarialbe() slot.
Here is a simple code for your another window:
class MyWidget : public QWidget
{
Q_OBJECT
public:
MyWidget(QWidget * parent = 0)
{
okBtn = new QPushButton ("I am Ok!");
MyData = "";
connect(okBtn ,SIGNAL(clicked()),this,SLOT(OnOk()));
}
~MyWidget();
private:
QString MyData;
QPushButton * okBtn;
//something that modify string MyData
signals:
void MyDataSignal(QString);
//Internal slot that emits signal with proper data
private slots:
void OnOk()
{
if(MyData!="")
{
emit MyDataSignal(MyData);
}
}
};
Now in MainWindow create an object of MyWidget (suppose myWid)and connect it to slot
connect(myWid, SIGNAL(MyDataSignal(QString)),this,SLOT(OnMyWidOkClicked(QString)));
the signal will pass string to slot.
While making signals and slots keep in mind following points:
To connect a signal to a slot (or to another signal), they must have the same parameter
Parameters should be in the same order in both signal and slot.
if a signal has more parameters than the slot it is connected to, the additional parameters are simply ignored but opposite is not possible.
If you will connect a signal that have unmatched parameters to slot then no compile time error will occur but at run time command window will show a warning that signal/slot/connection does not exist.

Change label text from another class using Qt signals and slots

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!");
}

Qt: why does connect() work only in the main window class?

Here's a simple code that creates a button and assigns a onclick handler:
auto btn = new QPushButton("CLICK ME");
connect(btn, SIGNAL(clicked()), this, SLOT(btn_Click()));
private slots:
void btn_Click() {
alert("clicked!");
}
It works as it should if called in the main window class. However when I try to do this in a child window, clicking the button does nothing. The child window is shown like this:
auto settingsWindow = new SettingsWindow();
settingsWindow->show();
I guess it's somehow connected with the receiver object which is now a different window. But how can I make it work?
In order to be able to declare signals/slots in your own class you should include Q_OBJECT directive in your class:
class SettingsWindow {
Q_OBJECT
...
};
You should add a MACRO in class SettingsWindow to enable singal receiving.
Add "Q_OBJECT" like the following.
class MainWidget : public QWidget
{
Q_OBJECT
public:
MainWidget();
....