PDA

View Full Version : Native QFileDialog position under Win32



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.