http://www.perlmonks.org?node_id=337655

spikey_wan has asked for the wisdom of the Perl Monks concerning the following question:

Hello World!

Does anyone know how to position the dialog boxes from Win32::FileOp. i.e. the OpenDialog, SaveAsDialog and BrowseForFolder dialog boxes?

They seem to be relative to the console window, so that if the console is not displayed, or is not there at all (i.e. I generated an .exe file with perlapp --gui), then they appear in the top left corner of the screen, but if the console IS displayed then they appear with their top left corner close to the top left of the console.

I really want them positioned relative to my main Tk window, like I can with everything else. I have a feeling that it may be something to do with the handle option, but adding '-handle => $mw' didn't seem to make any difference.

Thanks,

Spike.

UPDATE
Thanks to eserte, the updated code below now works for positioning the OpenDialog and SaveAsDialog relative to the main Tk window. Unfortunately it doesn't work on the BrowseForFolder dialog box. If I could just find a way to get it to work for that one, I could die happy! ;-)

Short demo:

use strict; use warnings; use Tk; use Win32::FileOp; my $mw = MainWindow -> new; $mw -> withdraw; my $windowid = hex ($mw -> id); my $openbutton = $mw -> Button ( -text => 'Open', -command => \&opensub, ) -> pack; my $savebutton = $mw -> Button ( -text => 'save', -command => \&savesub, ) -> pack; my $browsebutton = $mw -> Button ( -text => 'browse', -command => \&browsesub, ) -> pack; $mw -> Popup; MainLoop; sub opensub { my $file = OpenDialog(-title => "open", -handle => $windowid); } sub savesub { my $file = SaveAsDialog(-title => "save", -handle => $windowid); } sub browsesub { my $dir = BrowseForFolder ("no handle"); my $dir1 = BrowseForFolder("with handle", -handle => $windowid); }

Replies are listed 'Best First'.
Re: Win32::FileOp window positioning?
by halley (Prior) on Mar 18, 2004 at 15:32 UTC
    Win32::FileOp::OpenOrSaveDialog() populates a Win32 data structure called an OPENFILENAME. It's a really crazy structure with a lot of seemingly unrelated data. One element is an HWND which refers to the "owner window."

    I think the common file open dialog uses this field to center the dialog relative to that window, or that window's top level grandparent. If you don't populate it, the console window or the desktop itself are the only choices it would have.

    If you provide a hash reference as an argument to Win32::FileOp::OpenDialog(), it will populate many parameters in the struct for you. For example, { -handle => $myDesiredHwnd } would fill that HWND parameter in the Win32 data structure. But the trick becomes figuring out the right hWnd value for that.

    You'd have to look into your Windows build of Tk::MainWindow to see if it has a window handle you could retrieve.

    Update: Sorry if this is greek-- the Tk::* folks want to be as generic as possible, while the Win32::* stuff tends to expose a lot of random capability like this. Exposing capability is fine, but it requires a lot more legwork to learn how it all applies or how to take advantage of it.

    --
    [ e d @ h a l l e y . c c ]

Re: Tk::FileSelect or Tk::FBox as common file dialogs for Win32
by Brutha (Friar) on Mar 19, 2004 at 08:39 UTC
    Hello Spike, why do you mix Win32 and Tk?

    Did you look at the Tk::FileSelect or Tk:FBox modules? They seem to be a wrapper for the Win32 common dialog under Win2K for me and are easy to use.

    Look into the Tk Widget demo under 'common dialogs' point 2. Click the browse button to see them, click see code for an example in sub fileDialog.

    They work fine for me.

    And it came to pass that in time the Great God Om spake unto Brutha, the Chosen One: "Psst!"
    (Terry Pratchett, Small Gods)

      Thanks Brutha. Initially, I was using these, but I have a problem with getSaveFile. If the selected file already exists, it gives a "file exists, overwrite?" warning, which seems impossible to switch off. In my script, if the user selects an existing file, it is because they want their results appending to the existing file, so you can see that this warning was inappropriate and misleading. As I couldn't stop this warning from happening, I had to try something else, which opened up a whole new can of worms ;-)
Re: Win32::FileOp window positioning?
by didier (Vicar) on Mar 19, 2004 at 09:03 UTC

    You cannot use anchor popup to do that.
    But there are work around, for example you can draw the dialog box like this at 50x50 screen coord*:
    use Tk; $mw = MainWindow -> new; $openbutton = $mw -> Button ( -text => 'Open', -command => \&opensub, )-> pack; sub opensub { $top = $mw ->Toplevel; $top -> wm('geometry', '0x0+50+50'); $top->overrideredirect(1); $type_file = [['GIF Image', '.gif'], ['JPG Image', '.jpg']]; $file_openned = $top->getOpenFile(-filetypes => $type_file, -title => 'Choose an image', -defaultextension => \$type_file); } MainLoop;

    Hope this help.
      Wow, thanks Didier, that's a really neat trick! I can see lots of uses for that already! The problem is, though, you used getOpenFile, and I need to use the OpenDialog, SaveAsDialog, and BrowseForFolder. Still a neat trick, though.
Re: Win32::FileOp window positioning?
by eserte (Deacon) on Mar 19, 2004 at 09:36 UTC
    Please check if id() returns a decimal or hexadecimal value (it may be the latter) and convert if necessary.
      Aha, thanks eserte! Now I'm really getting somewhere!! I converted the window id from hex to dec, and it worked for OpenDialog and SaveAsDialog, but it doesn't work for BrowseForFolder.

      Here's an almost completely working snippet, except that I still can't position the BrowseForFolder dialog.

      use strict; use warnings; use Tk; use Win32::FileOp; my $mw = MainWindow -> new; $mw -> withdraw; my $windowid = hex ($mw -> id); my $openbutton = $mw -> Button ( -text => 'Open', -command => \&opensub, ) -> pack; my $savebutton = $mw -> Button ( -text => 'save', -command => \&savesub, ) -> pack; my $browsebutton = $mw -> Button ( -text => 'browse', -command => \&browsesub, ) -> pack; $mw -> Popup; MainLoop; sub opensub { my $file = OpenDialog(-title => "open", -handle => $windowid); } sub savesub { my $file = SaveAsDialog(-title => "save", -handle => $windowid); } sub browsesub { my $dir = BrowseForFolder ("no handle"); my $dir1 = BrowseForFolder("with handle", -handle => $windowid); }

        BrowseForFolder() doesn't (yet) support this style of calling. And there aparently was a bug in the code. Could you try to replace the BrowseForFolder in FileOp.pm with the following code:

        sub BrowseForFolder { undef $Win32::FileOp::Error; my $lpszTitle = shift() || "\0"; my $nFolder = shift() || 0; my $ulFlags= (shift() || 0) | 0x0000; my $hwndOwner = (defined $_[0] ? shift() : GetWindowHandle()); my ($pidlRoot, $pszDisplayName, $lpfn, $lParam, $iImage, $pszPath) = ("\0"x260, "\0"x260, 0, 0, 0, "\0"x260 ); $nFolder = CSIDL_DRIVES() unless defined $nFolder; $Win32::FileOp::SHGetSpecialFolderLocation->Call($hwndOwner, $nFold +er, $pidlRoot) and return undef; $pidlRoot = hex unpack 'H*',(join'', reverse split//, $pidlRoot); my $browseinfo = pack 'LLppILLI', ($hwndOwner, $pidlRoot, $pszDisplayName, $lpszTitle, $ulFlags, $lpfn, $lParam, $iImage); my $bool = $Win32::FileOp::SHGetPathFromIDList->Call( $Win32::FileOp::SHBrowseForFolder->Call($browseinfo), $pszPath ); $pszPath =~ s/\0.*$//s; $bool ? $pszPath : undef; }
        and then use
        my $dir1 = BrowseForFolder("with handle", undef, undef, $windowid);

        I have a few more changes pending to be released, hopefully I'll have some spare time to do that sometime soon.

        HTH, Jenda
        We'd like to help you learn to help yourself
        Look around you, all you see are sympathetic eyes
        Stroll around the grounds until you feel at home
           -- P. Simon in Mrs. Robinson