PDA

View Full Version : Update to 4.4.2 - Now I Have A Transparent Dialog



mclark
3rd October 2008, 17:01
I've recently updated my Qt installation from 4.3.4 to 4.4.2. I have a simple dialog which is to display a 1 line message while some time-consuming operation is happening. When the operation has finished the dialog closes.

Using 4.3.4 this was displaying as expected but since my switch to 4.4.2 the dialog body has become transparent (no background color, no text).

Based on my years of programming experience:rolleyes:, I assume that my code has worked by accident in 4.3.4 and 4.4.2 has uncovered a defect. Can anyone see what is going wrong here?

I've attached a bitmap of what I'm seeing.


class GenericWaitDlg : public QDialog
{
Q_OBJECT

public:
GenericWaitDlg( QWidget *pParent );
void Initialize( QString sTitle, QString sMsg );

private:
Ui::GenericDlgClass ui;
QWidget* m_pParent;
MainWin* m_pMainWin;

};


GenericWaitDlg::GenericWaitDlg( QWidget* pParent )
: QDialog( pParent )
, m_pParent( pParent )
, m_pMainWin( reinterpret_cast<MainWin*>(
reinterpret_cast<NetConfigDlg*>( pParent )->m_pMainWin ) ) {}


void GenericWaitDlg::Initialize( QString sTitle, QString sMsg )
{
// Remove the system menu, close button and context help button
setWindowFlags( windowFlags() ^
(Qt::WindowSystemMenuHint | Qt::WindowContextHelpButtonHint) );

ui.setupUi( this );

// Create Title and text strings
setWindowTitle( sTitle );
QLabel* sText = new QLabel( sMsg, this );

// Get the label size and use to fix dialog width
QSize labelSize = sText->sizeHint().expandedTo( sText->sizeHint() );
labelSize.setWidth( labelSize.width() + 120 );

// Layout label
QHBoxLayout* hBox = new QHBoxLayout();
hBox->addWidget( sText, 0, Qt::AlignHCenter );

// Main layout
QVBoxLayout* vbox = new QVBoxLayout( this );
vbox->addSpacing( 10 );
vbox->addLayout( hBox, Qt::AlignRight );
vbox->addSpacing( 15 );
setLayout( vbox );

resize( labelSize.width(), labelSize.height() * 8 );

// Center the dialog in the parent window
move( m_pParent->pos().x() +
(m_pParent->frameGeometry().width() / 2) - (frameGeometry().width() / 2),
m_pParent->pos().y() +
(m_pParent->frameGeometry().height() / 2) - (frameGeometry().height() / 2) );
}

// Instantiate, initialize and show the dialog
GenericWaitDlg dlg( m_parent );
dlg.Initialize( DLG_TITLE, DLG_MSG );
dlg.show();
// Do some work here...
dlg.done( 0 );

caduel
4th October 2008, 08:15
i) the code does not produce a transparent dialog here (Qt 4.4.1)
ii) might be an error in your .ui file (we haven't got that)
iii) the xor is a bit fishy. idion for removing bits is
x &= ~(bits_to_remove)
iv) why cast to reinterpret_cast<NetConfigDlg*>( pParent ) ? Just pass a NetConfigDlg in the constructor instead of the QWidget!
v) the other cast: why cast an x to an x? a bit pointless ;-) try to save on those casts!

HTH

mclark
6th October 2008, 17:33
I have distilled this down to a minimal app. Using 4.4.2, the dialog interior is transparent while the identical code using 4.3.4 contains a background and text.

.ui File
<UI version="4.0" stdSetDef="1" >
<class>GenericDlgClass</class>
<widget class="QDialog" name="GenericDlgClass" >
<property name="objectName" >
<cstring>GenericDlgClass</cstring>
</property>
<property name="geometry" >
<rect>
<x>0</x>
<y>0</y>
<width>300</width>
<height>500</height>
</rect>
</property>
</widget>
<layoutDefault spacing="6" margin="11" />
<pixmapfunction></pixmapfunction>
<resources/>
<connections/>
</UI>


Source Files
#include <QDialog>
#include "ui_GenericDlg.h"

class GenericWaitDlg : public QDialog
{
Q_OBJECT

public:
GenericWaitDlg( QString sTitle, QString sMsg, QWidget* pParent = 0 );

private:
Ui::GenericDlgClass ui;
};


#include <QLabel>
#include "GenericWaitDlgTest.h"

GenericWaitDlg::GenericWaitDlg( QString sTitle, QString sMsg, QWidget* pParent )
: QDialog( pParent )
{
ui.setupUi( this );
setWindowTitle( sTitle );

// Get the label size and use to fix dialog width
QLabel* sText = new QLabel( sMsg, this );
QSize labelSize = sText->sizeHint().expandedTo( sText->sizeHint() );
labelSize.setWidth( labelSize.width() + 120 );
resize( labelSize.width(), labelSize.height() * 8 );
}


#include <QApplication>
#include "GenericWaitDlgTest.h"

int main( int argc, char *argv[] )
{
QApplication app( argc, argv );

GenericWaitDlg dlg( "GenericWaitDialog", "GenericWait Dialog message..." );
dlg.show();
for ( int i = 0; i < 0x7FFFFFFF; i++ ); // Simulate some work...
dlg.done( 0 );

return 0;
}

jpn
6th October 2008, 18:06
You cannot block the event loop with a busy loop (in fact, in the minimal test case you don't run an event loop at all). The application has no chance to deliver paint events, thus nothing gets painted.

mclark
6th October 2008, 18:50
You cannot block the event loop with a busy loop (in fact, in the minimal test case you don't run an event loop at all). The application has no chance to deliver paint events, thus nothing gets painted.

In that case this example should perform the same using both versions of Qt, no?

jpn
6th October 2008, 19:03
In that case this example should perform the same using both versions of Qt, no?
Perhaps 4.3.4 creates the native window handle upon show(), whereas 4.4.0 probably doesn't do it at that point yet. It doesn't mean that the minimal test app works with either version. You MUST let the application process its events in order to make the dialog responsive.


for ( int i = 0; i < 0x7FFFFFFF; i++ ) // Simulate some work...
app.processEvents();

mclark
6th October 2008, 19:21
You MUST let the application process its events in order to make the dialog responsive.

Ahhhh.... Now I see what you mean about the minimal test app.

So, what would you recommend for a solution for the real app?

I have a QDialog which needs to make a library call that may take 3-7 seconds (on average) to complete. I want to display something to let a user know that processing is happing (the app is NOT hung). I was using the GenericWaitDlg class described above.

jpn
6th October 2008, 19:29
So, what would you recommend for a solution for the real app?

I have a QDialog which needs to make a library call that may take 3-7 seconds (on average) to complete. I want to display something to let a user know that processing is happing (the app is NOT hung). I was using the GenericWaitDlg class described above.
What kind of library call is that? Unless there is a way to split the task into smaller chunks, I'm afraid you have to process it in a worker thread and deliver results to the main GUI thread for example by using queued signals.

mclark
6th October 2008, 19:40
What kind of library call is that?

The call is to a library I have no control over (not a Qt call). I was hoping there might be a solution other than using a worker thread.

Does this sound reasonable:
create my GenericWaitDlg
create a worker thread
connect a slot (closeGenericWaitDlg()) to the finished() signal of the thread
in the run() method of the thread, make my library call
when the library call is finished the thread should shutdown
in the closeGenericWaitDlg() method call dlg.done(0) to close the wait dialog

jpn
6th October 2008, 20:10
Yes, sounds reasonable. Just remember not to touch GUI in the worker thread. ;)

mclark
6th October 2008, 20:11
Thanks for your help, jpn. It is much appreciated!