PDA

View Full Version : image not getting refreshed in Qlabel



prkhr4u
29th November 2013, 06:17
I am trying to refresh a image in a QLabel.It is getting refreshed when i used this code on a button click:

void Dialog_user::on_btn_Stop_clicked()
{
flag=0;
sleep(2);
ui->label->setPixmap(QPixmap("abc.bmp"));
}

When i am doing the same thing via a signal-slot mechanism,it is not getting refreshed.The code is :

void Dialog_user::ImageRefreshSlot()
{
qDebug()<<"inside slot";
sleep(2);
qDebug()<<"after sleep";
ui->label->setPixmap(QPixmap("abc.bmp"));
}

I have verified that signal and slot is connected via a debug message. The message "inside slot" and "after sleep" is successfully printed,but the label is not refreshed again.
But again if i am clicking the button,the image is getting refreshed.

P.S.:
I have a image processing application,where the image changes every 2 secs.

anda_skoa
30th November 2013, 00:27
What is that sleep(2) for? It is usually a very bad idea to block the UI thread, especially for several seconds.

Cheers,
_

prkhr4u
30th November 2013, 03:42
It is a heavy image processing application,so it takes around 2 secs to process the image after a trigger is called by signal slot mechanism.
Hence I wait for 2 seconds and then display the image.
In Detail, I have a mutithreaded application,where in one thread some image processing is going and when the processing starts,I emit a signal which is caught by the ImageRefreshSlot and since the processing takes 2 seconds,I make it wait for 2 seconds.

saman_artorious
30th November 2013, 08:52
It is a heavy image processing application,so it takes around 2 secs to process the image after a trigger is called by signal slot mechanism.
Hence I wait for 2 seconds and then display the image.
In Detail, I have a mutithreaded application,where in one thread some image processing is going and when the processing starts,I emit a signal which is caught by the ImageRefreshSlot and since the processing takes 2 seconds,I make it wait for 2 seconds.

Use QTimer::singleShot() instead of sleep and see if it changes pixmap or not.

anda_skoa
30th November 2013, 11:17
In Detail, I have a mutithreaded application,where in one thread some image processing is going and when the processing starts,I emit a signal which is caught by the ImageRefreshSlot and since the processing takes 2 seconds,I make it wait for 2 seconds.

Then you have your synchronisation points wrong. It really doesn't matter for the main thread when the processing thread has started working, the only thing that matters is when it has finished. Because at that point you have a new image to display.

Cheers,
_

prkhr4u
4th December 2013, 08:33
I have now removed the sleep and emitted a signal just after image has been formed.But still the image is not getting refreshed.
Here is what I am doing:
//GrabThread.cpp

void GrabThread::run()
{
ImageFormation();
check=0;
emit ImageRefreshSignal();
}


Image processing finishes in ImageFormation() and after that I emit a signal 'ImageRefreshSignal', which I am catching in a dialog as follows:
//dialog_user.cpp


Dialog_user::Dialog_user(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog_user)
{
ui->setupUi(this);
ui->label->setPixmap(QPixmap("abc.bmp"));
}
Dialog_user::~Dialog_user()
{
delete ui;
}
void Dialog_user::ImageRefreshSlot()
{
qDebug()<<"inside slot";
ui->label->setPixmap(QPixmap("abc.bmp"));
}


I am successfully getting "inside slot" message,which indicates that ImageRefreshSlot() has been called,but still the image is not getting refreshed.

Have connected the signal-slot in main.cpp as follows:


int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow win;
win.show();
Dialog_user d_user;
GrabThread gthread;
QObject::connect( & gthread, SIGNAL( ImageRefreshSignal() ),& d_user, SLOT( ImageRefreshSlot() ) );
gthread.start();
return a.exec();
}

anda_skoa
4th December 2013, 09:46
Are you sure the image on disk has changed?

Any reason you do not just transfer the image within the application?

Cheers,
_

prkhr4u
4th December 2013, 09:53
yes,the image on disk has changed.
In fact,I also have a button to check the same code.On button click the code works:

void Dialog_user::on_btn_Stop_clicked()
{
ui->label->setPixmap(QPixmap("abc.bmp"));
}

I am not transferring the image within application because I am unable to refresh the image.It takes the same image as it took during the build time,even though the image on disk changes.

anda_skoa
4th December 2013, 11:57
yes,the image on disk has changed.
In fact,I also have a button to check the same code.On button click the code works:


Hmm. In your other slot check the file timestamp using QFileInfo before loading and verify that it has indeed already been changed then.


I am not transferring the image within application because I am unable to refresh the image.It takes the same image as it took during the build time,even though the image on disk changes.

I meant: why doesn't your signal contain the image as a parameter?

Cheers,
_

d_stranz
5th December 2013, 01:44
I am successfully getting "inside slot" message,which indicates that ImageRefreshSlot() has been called,but still the image is not getting refresh

Is your image processing thread closing the file (or at least flushing it) so the contents are physically written to the disk? If the thread simply keeps the file open while continuously updating it, the changes might simply be in the disk cache and not actually in the file itself.

Also, if your app doesn't return to the event loop after the "image finished" signal is handled, the UI won't update. Handling the button click *does* return the app to the event loop, so the pixmap *will* be updated.

And who is this "atathamquin" who keeps thanking every post, no matter what it says? Seems to be a few of these types running around the forum lately.

prkhr4u
5th December 2013, 04:30
@anda_skoa: I have checked the file physically and also its timestamp also.It is indeed changing everytime.
Also I am not passing image as a parameter through my signal because I need to read the file again and again and hence I am doing it on a physical file and i know its location,so no need to pass.

@d_stranz: yes,the image processing thread is closing the file and the contents are physically written to the disk.
I think you are correct,that it is not returning to the event loop after "image finished" signal is handled..hence the UI is not updating.
Pl tell how to return to the event loop,as I am unable to do so..

ChrisW67
5th December 2013, 04:48
You are using a relative path to the file. It seems quite possible you are writing to one file called abc.bmp and reading from another.

prkhr4u
5th December 2013, 05:02
There is only 1 file abc.bmp.
I have verified it as I am initializing the label with it and also using external button_click event to run the same code and it is working correctly.

anda_skoa
5th December 2013, 10:15
Also I am not passing image as a parameter through my signal because I need to read the file again and again and hence I am doing it on a physical file and i know its location,so no need to pass.


I am afraid I can't follow. It really doesn't matter how the file is being accessed, does it?
Your worker thread manipulates a QImage, right? It saves the data to file after it is done, right? Why not just also emit the image via signal for displaying?

That avoids any race condition on file access, avoids unnecessary disk I/O, avoid unnecessary image decoding.

Cheers,
_

prkhr4u
5th December 2013, 10:23
My worker thread manipulates a bitmap image(stored on file) and I am using QPixmap to display it inside a label.
I emit the signal just after the thread finishes manipulating that bitmap image.
Hence i need to read the file everytime and for that I am using a slot mechanism to reset the image in the label everytime a signal is emmited.
Here is the code inside the slot:


ui->label->setPixmap(QPixmap("abc.bmp"));

stampede
5th December 2013, 10:41
Yes but why do you need disk access ? Worker can process the image and send the processed result directly to the display thread, what's wrong with that :confused:
now you have this:


[load image from disk] --> process it --> [save to disk] --> inform gui that image is updated --> [load from disk] --> display

why not have this:


[load image from disk] --> process it --> inform gui that image is updated, send the image via signal --> display

:confused:

prkhr4u
7th December 2013, 07:32
Can you pl tell how to pass image via signal,I am unable to do so.

anda_skoa
7th December 2013, 10:23
You add QImage as a parameter of the signal



class GrabThread : public QThread
{
Q_OBJECT

signals:
void ImageRefreshSignal(const QImage &image);
};

And you pass the image at emit


emit ImageRefreshSignal(image); // or image.copy() if the thread continues to use "image"


Similar signature changes to slot and connect obviously

Cheers,
_

prkhr4u
9th December 2013, 08:39
I have done the changes and now am sending the image via signal,but still I am unable to refresh the image.
Here is what I have done:

class GrabThread : public QThread
{
Q_OBJECT
private:
void run();
public:
signals:
void ImageRefreshSignal(const QImage &image);
};
Signal emmited like:

QImage img;
img.load("abc.bmp");
emit ImageRefreshSignal(img);
slot method called like:

void Dialog_user::ImageRefreshSlot(QImage img )
{
qDebug()<<"inside slot";
ui->label->setPixmap(QPixmap::fromImage(img));
}
//dialog_user.h

class Dialog_user : public QDialog
{
Q_OBJECT

public:
explicit Dialog_user(QWidget *parent = 0);
~Dialog_user();

private slots:
void ImageRefreshSlot (QImage img);
the connection is as follows:

QObject::connect( & gthread, SIGNAL( ImageRefreshSignal(QImage) ),& d_user, SLOT( ImageRefreshSlot(QImage) ) );
I have checked the mechanism, and the message "inside slot" is being printed,but the image is not getting refreshed.

stampede
9th December 2013, 09:25
Why do you load the image before sending it ? Can't you send the processed object ? Can we see the image processing code ?

prkhr4u
9th December 2013, 10:25
I have a separate image processing thread,which processes the image object as well as writes it to a bmp file "abc.bmp"
The image processing is entirely different from GUI thread and works continuously in the background.
As the GUI thread is only meant for display purposes,I am not sending the processed object for writing in GUI thread.

Is there other way to send the image via a signal without loading it?

stampede
9th December 2013, 12:52
I have a separate image processing thread,which processes the image object as well as writes it to a bmp file "abc.bmp"
The image processing is entirely different from GUI thread and works continuously in the background.
As the GUI thread is only meant for display purposes,I am not sending the processed object for writing in GUI thread.
Yes we know that ! Show us the code where you do this "abc.bmp" file writing in image processing thread. We want you to just emit the changed image apart from writing it to file. You have some image object on which you call save() method, right ? Just emit a signal, passing this object as parameter...

prkhr4u
12th December 2013, 04:20
Here is the main code for writing:

void convert2bmp(unsigned int **Buffer_in,unsigned int x_size,unsigned int y_size,char *output_str)
unsigned char* data3d = new unsigned char[x_size*y_size];
fp = fopen (output_str, "wb");
for ( i = x_size; i >= 0; i--)
for (j = 0; j < y_size; j++)
{
data3d[k++]=Buffer_in[i][j];
}
fwrite( data3d, sizeof( char ),x_size*y_size, fp);
fclose(fp);


Buffer_in: buffer containing the processed image data
x_size,y_size: dimension of image
Output_str: name of output file:"abc.bmp"

After some image processing,which occurs on the buffer,I am writing it to a bitmap file.The Buffer_in is only available to me inside this(image processing thread) and then I am displaying the image in a Qlabel in GUI thread.
The method "convert2bmp" is being called after every image processing iteration and the processed image needs to be displayed on a GUI thread everytime.
But the image is not getting refreshed every time.

ChrisW67
12th December 2013, 06:41
The variable k is used uninitialised.

Just from looking at what you are doing to the image data I think it is exceptionally unlikely you have a valid BMP at the end of the process.
Ignoring your GUI for a moment. Is the BMP file being written? Is it the correct size in bytes? Is it a valid BMP and can you see the right image in Microsoft Paint or something similar?

prkhr4u
12th December 2013, 07:35
The bmp file is being written properly.
I have excluded the code for bmp header and small variables like i,j,k.
The code for main file writing is being enclosed.

anda_skoa
12th December 2013, 10:25
If Buffer_in is your pixel data, you can probably use it to create a QImage instance pointing to the same image data.

And then use QImage::copy() to send it through the signal.

Cheers,
_

prkhr4u
17th December 2013, 10:38
I have sent the pixel data using QImage as follows:

QImage myImage(400,700,QImage::Format_RGB888);
for (int x=0;x<400;x++)
for (int y=0;y<700;y++)
myImage.setPixel(x,y,qRgb(Buffer_in[y][x*3],Buffer_in[y][x*3+1],Buffer_in[y][x*3+2]));
emit ImageRefreshSignal(myImage.copy(0,0,400,700));

and used the slot as follows:

void Dialog_user::ImageRefreshSlot(QImage img )
{
qDebug()<<"inside slot";
ui->label->setPixmap(QPixmap::fromImage(img));
}

still the label containg the image is not getting refreshed.
The slot is being called correctly and the debug message "Inside slot" is being printed.

anda_skoa
17th December 2013, 12:30
I have sent the pixel data using QImage as follows:

QImage myImage(400,700,QImage::Format_RGB888);
for (int x=0;x<400;x++)
for (int y=0;y<700;y++)
myImage.setPixel(x,y,qRgb(Buffer_in[y][x*3],Buffer_in[y][x*3+1],Buffer_in[y][x*3+2]));
emit ImageRefreshSignal(myImage.copy(0,0,400,700));

In this case (QImage having its own memory) you can do without the copy().



still the label containg the image is not getting refreshed.
The slot is being called correctly and the debug message "Inside slot" is being printed.

Very strange.
Only thing left I can think of is something blocking the UI thread, like some code calling sleep() or blocking API.

If you don't have any of those, can you try to create a minimal test case? I.e. something where the thread just does some random pixel value changes?

Cheers,
_

prkhr4u
19th December 2013, 10:20
I created a test case and changed some pixel values.
I was able to successfully change the pixel values,when I was doing it in MainWindow.
But If I do the same in another dialog,The pixel values are not even set and QLabel remains as such.
I checked in the same way,the debug message "inside slot" is being printed for the dialog.

I have some login code,which I want to put in Main Window and then open a new dialog(on successful login),where I show the processed image in a Qlabel.

anda_skoa
19th December 2013, 10:41
I created a test case and changed some pixel values.


Can you attach that test case? The idea of a minimal test case it that others can try it and look for potential errors.

Cheers,
_

prkhr4u
20th December 2013, 04:12
I have attached the minimal test case.
Do have a look at the same

anda_skoa
20th December 2013, 10:19
Your code works nicely (after uncommenting the dialog's show() call of course, can display something that is hidden)

The image thread emits the image and the dialog it is connected to gets the slot invocation and displays the image.

I modified the thread's run() method it randomly use a different color and indeed those changes are visible in the dialog connected to the thread.

Cheers,
_

prkhr4u
21st December 2013, 03:50
I know that this way it is working,but I want to show the dialog only after clicking the button "go to dialog" from main window.In that case it is not working.
I suspect this is due to the event loop not closing,but I am unable to close it and hence the label is not working.

Similarly there is some login code in main window,after clicking login button,the dialog opens up and I want to show the image in the label.The label is then unable to set the image at that moment.
I have tried with both QImage and bitmap image.In both the cases,the QLabel is unable to show the image.

anda_skoa
21st December 2013, 10:27
I know that this way it is working,but I want to show the dialog only after clicking the button "go to dialog" from main window.In that case it is not working.


I don't see why this would not also work.

Why didn't you put that into the testcase?

Right now your code does exactly what it is supposed to do. The thread emits the image, the label in the connected dialog is updated.
There is a button which opens another dialog and it also shows its label content as expected.
The event loop is nicely running. If the thread is modified to emit images in a loop, the label in the dialog it is connected to will change every time there is a new image.

Cheers,
_

prkhr4u
23rd December 2013, 02:56
I had commented the dialog.show() in my test case.It Is not working as expected.
Comment out the line dialog.show() and then:
When I click on the button in the main window,the dialog opens up and the label shows "Text label" and the image is not shown at all.

If I am showing the dialog at the start( uncommenting the dialog.show()),then it is working.But I want the dialog to be open only after clicking the button.

ChrisW67
23rd December 2013, 03:14
You never connect the signal from the thread to the dialog you create in the MainWindow::on_btn_dialog_clicked(). Why would you expect it to update?
(The way your code is written the thread object is not available to be connected in this routine anyway.)

anda_skoa
23rd December 2013, 08:03
I had commented the dialog.show() in my test case.It Is not working as expected.

It is. I tested it.



Comment out the line dialog.show() and then:
When I click on the button in the main window,the dialog opens up

No, a second dialog opens up.



and the label shows "Text label" and the image is not shown at all.

As expected, that is what its code, generated from the designer UI file, is doing.



If I am showing the dialog at the start( uncommenting the dialog.show()),then it is working.

No, time of showing has nothing to do with that.

You have two places were you create dialog instances. One in main() and one in the main window's slot.

The instance from main() is connected to the thread and updates its label when ever there is a new image. Any instance created from the main window's slot has no interaction after it has been created and thus shows whatever you had in its UI file.




But I want the dialog to be open only after clicking the button.

Then you need to connect the button to the dialog' show() slot, or use a slot that calls show() on the dialog.

Cheers,
_

prkhr4u
23rd December 2013, 08:08
I have connected the signal to slot in the main.cpp file.
Here is the code:

QObject::connect( & iThread, SIGNAL( ImageRefreshSignal(QImage) ),& dlg, SLOT( ImageRefreshSlot(QImage) ) );
I have checked it also,as inside the slot method the debug message "inside slot" is being printed.

Even calling the connect method inside the MainWindow:: on_btn_dialog_clicked() does the same thing.

anda_skoa
23rd December 2013, 08:13
I have connected the signal to slot in the main.cpp file.
Here is the code:

QObject::connect( & iThread, SIGNAL( ImageRefreshSignal(QImage) ),& dlg, SLOT( ImageRefreshSlot(QImage) ) );


Yes, and it works as expected. The dialog shows all updates it gets from the thread.



I have checked it also,as inside the slot method the debug message "inside slot" is being printed.

Indeed it does.



Even calling the connect method inside the MainWindow:: on_btn_dialog_clicked() does the same thing.
Exactly! Connecting these other dialogs to the thread will make them update their label as well.

Cheers,
_

prkhr4u
26th December 2013, 09:47
Here is the sequence of events I want:

load main window,start image processing thread -> click on button 'go to dialog' -> open a new dialog -> refresh image(QImage from thread via signal-slot) in Qlabel in new dialog

Here is what is happening:

load main window,start image processing thread -> click on button 'go to dialog' -> open a new dialog -> Qlabel showing only 'Text Label' and image is not loaded.

Only the dialogs which start from main can interact with the thread and can update themselves with the thread,but In my case the dialog is opening from main window and is not able to interact with the thread.
pl suggest how to overcome this problem?
Is there any design changes I have to do?

ChrisW67
26th December 2013, 11:17
You have been told several times what needs to be done: connect the dialog slot to the signal providing the update. The dialog you launch in response to the button press is never going to update unless you connect it to something that is going to cause it to update. It really is that simple. You will have to arrange your program so that this connection can be made, and then you have to code that connection.

The instance of the dialog you create in main() and connect to the output of your thread has nothing to do with the instance of the dialog you create in the button slot, which remains connected to nothing.