no_ghost
28th May 2009, 14:07
Qt documentation says:
"Note that on Windows the dialog will spin a blocking modal event loop that will not dispatch any QTimers, and if parent is not 0 then it will position the dialog just under the parent's title bar."
Not in the center of the parent window, as one expecting.
But WinAPI provides a very simple way to define native file dialog's positions. In few words - you have to assign a hook function pointer in OPENFILENAME structure and position dialog properly in that function.
This function creates correct OPENFILENAME (don't forget to make similar changes in qt_win_make_OFNA function)
static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
const QString& initialSelection,
const QString& initialDirectory,
const QString& title,
const QString& filters,
QFileDialog::FileMode mode,
QFileDialog::Options options)
{
// ....
OPENFILENAME* ofn = new OPENFILENAME;
memset(ofn, 0, sizeof(OPENFILENAME));
// ....
ofn->lpfnHook = qt_win_ofn_hook; // custom hook
ofn->lCustData = (LPARAM)parent; // parent of dialog window
ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLEHOOK); // OFN_ENABLEHOOK enables ofn hook fields
// ....
}
And this is a hook function:
UINT_PTR CALLBACK qt_win_ofn_hook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
// process initialization message
if(uiMsg == WM_INITDIALOG)
{
OPENFILENAME* ofn;
QWidget* parent;
HWND frame_dlg;
RECT frame_rect;
QRect parent_rect;
int dlg_left;
int dlg_top;
// this should work even if lParam points to OPENFILENAMEA
ofn = (OPENFILENAME*)lParam; // ofn goes to lparam (as MSDN says)
parent = (QWidget*)ofn->lCustData; // custom data filled in ofn
if(parent == 0)
{
// using desktop if no parent window
parent_rect = QApplication::desktop()->geometry();
}
else
{
// getting parent rect
QPoint parent_topleft;
parent_topleft = parent->mapToGlobal(QPoint(0, 0));
parent_rect = QRect(parent_topleft, parent->size());
}
frame_dlg = GetParent(hdlg); // file dialog handle
GetWindowRect(frame_dlg, &frame_rect); // file dialog frame rect
// compute left and top of final rect
dlg_left = (parent_rect.left() + parent_rect.right()) / 2 -
(frame_rect.right - frame_rect.left) / 2;
dlg_top = (parent_rect.top() + parent_rect.bottom()) / 2 -
(frame_rect.bottom - frame_rect.top) / 2;
// position file dialog
SetWindowPos(frame_dlg, 0, dlg_left, dlg_top, 0, 0, SWP_NOSIZE);
}
return FALSE;
}
Full qfiledialog_win.cpp file is in the attachments.
Hope it will help. Or may be, in one beautiful day, it will be commited to the main repository.
"Note that on Windows the dialog will spin a blocking modal event loop that will not dispatch any QTimers, and if parent is not 0 then it will position the dialog just under the parent's title bar."
Not in the center of the parent window, as one expecting.
But WinAPI provides a very simple way to define native file dialog's positions. In few words - you have to assign a hook function pointer in OPENFILENAME structure and position dialog properly in that function.
This function creates correct OPENFILENAME (don't forget to make similar changes in qt_win_make_OFNA function)
static OPENFILENAME* qt_win_make_OFN(QWidget *parent,
const QString& initialSelection,
const QString& initialDirectory,
const QString& title,
const QString& filters,
QFileDialog::FileMode mode,
QFileDialog::Options options)
{
// ....
OPENFILENAME* ofn = new OPENFILENAME;
memset(ofn, 0, sizeof(OPENFILENAME));
// ....
ofn->lpfnHook = qt_win_ofn_hook; // custom hook
ofn->lCustData = (LPARAM)parent; // parent of dialog window
ofn->Flags = (OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_EXPLORER | OFN_ENABLEHOOK); // OFN_ENABLEHOOK enables ofn hook fields
// ....
}
And this is a hook function:
UINT_PTR CALLBACK qt_win_ofn_hook(HWND hdlg, UINT uiMsg, WPARAM wParam, LPARAM lParam)
{
// process initialization message
if(uiMsg == WM_INITDIALOG)
{
OPENFILENAME* ofn;
QWidget* parent;
HWND frame_dlg;
RECT frame_rect;
QRect parent_rect;
int dlg_left;
int dlg_top;
// this should work even if lParam points to OPENFILENAMEA
ofn = (OPENFILENAME*)lParam; // ofn goes to lparam (as MSDN says)
parent = (QWidget*)ofn->lCustData; // custom data filled in ofn
if(parent == 0)
{
// using desktop if no parent window
parent_rect = QApplication::desktop()->geometry();
}
else
{
// getting parent rect
QPoint parent_topleft;
parent_topleft = parent->mapToGlobal(QPoint(0, 0));
parent_rect = QRect(parent_topleft, parent->size());
}
frame_dlg = GetParent(hdlg); // file dialog handle
GetWindowRect(frame_dlg, &frame_rect); // file dialog frame rect
// compute left and top of final rect
dlg_left = (parent_rect.left() + parent_rect.right()) / 2 -
(frame_rect.right - frame_rect.left) / 2;
dlg_top = (parent_rect.top() + parent_rect.bottom()) / 2 -
(frame_rect.bottom - frame_rect.top) / 2;
// position file dialog
SetWindowPos(frame_dlg, 0, dlg_left, dlg_top, 0, 0, SWP_NOSIZE);
}
return FALSE;
}
Full qfiledialog_win.cpp file is in the attachments.
Hope it will help. Or may be, in one beautiful day, it will be commited to the main repository.