Beefy Boxes and Bandwidth Generously Provided by pair Networks
Syntactic Confectionery Delight

"Always on top" with Win32 and Tk

by kevin_i_orourke (Friar)
on May 08, 2001 at 19:00 UTC ( #78848=perlquestion: print w/ replies, xml ) Need Help??
kevin_i_orourke has asked for the wisdom of the Perl Monks concerning the following question:

I've written a quick and dirty program to show me various stats on software I'm building (free memory, etc.) using Perl/Tk under Windows. I'd like to have it stay "always on top" of other windows, like quite a few Win32 applications are able to.

The question is: can I do this using Perl/Tk? If I can, how do I do it?


Kevin O'Rourke

Comment on "Always on top" with Win32 and Tk
Replies are listed 'Best First'.
Re: "Always on top" with Win32 and Tk
by ozzy (Sexton) on May 09, 2001 at 04:05 UTC
    With toplevel widgets, i believe you can set the options so the widget will allways be in focus. One of the options for top level widgets is
     -takefocus or -focusmodel.
    To make sure check the Perl/TK documentation. If you are working on Win, you might also want to look into trying Win32::GUI.

    -= Ozzy =-

      Thanks for the suggestion. $window->focusmodel("active") doesn't seem to work (under NT at least). -takefocus is related to tab-key traversal of widgets.

      Looks like another one of those platform-dependent things that Tk hasn't got round to. Win32::GUI is something I'm looking into just now.

      Kevin O'Rourke
Re: "Always on top" with Win32 and Tk
by spikey_wan (Scribe) on Dec 22, 2004 at 12:50 UTC
    I can't believe no-one's mentioned Tk::StayOnTop.

    It does what it says on the tin.

Re: "Always on top" with Win32 and Tk
by eserte (Deacon) on Dec 12, 2006 at 23:14 UTC
    Try $mw->attributes(-topmost => 1). This should work for Windows, and soon on freedesktop-compliant X11 window managers.
Re: "Always on top" with Win32 and Tk
by elwarren (Curate) on May 09, 2001 at 23:28 UTC
    There are third party programs you can run that can alter properties of existing windows to force them on top. Nice to keep a copy of notepad or something open on top of everything else. One that I used would allow you to shell out and execute it and it would update the window of the program it was called from.

    While not a perl solution, it's close...

        I've got it working now! As before I've removed most of the code from my program.

        use Tk; use Win32::API; ... # Windows constants my ($OnTop, $NoTop, $Top) = (-1, -2, 0); my ($SWP_NOMOVE, $SWP_NOSIZE) = (2, 1); # 'always on top' state my $isOnTop = $NoTop; ... # Create a Win32::API object for SetWindowPos my $SetWindowPos = new Win32::API("user32", "SetWindowPos", [N,N,N,N,N +,N,N], N); # and one for FindWindow my $FindWindow = new Win32::API("user32", "FindWindow", [P,P], N); ... my $w = new MainWindow; ... my $aotCBut = $w->Checkbutton(-text => "Always on top", -onvalue => $OnTop, -offvalue => $NoTop, -variable => \$isOnTop, -command => sub { # get a handle to the toplevel window containing our Perl/Tk a +pp my $class = "TkTopLevel"; my $name = $w->title; my $NULL = 0; my $topHwnd = $FindWindow->Call($class, $name); if ($topHwnd != $NULL) { # change 'always on top' state $SetWindowPos->Call($topHwnd, $isOnTop, 0, 0, 0, 0, $SWP_N +OMOVE | $SWP_NOSIZE); }; }) ->pack(-side => "bottom", expand => "yes", -fill => "x"); ... # start the UI MainLoop;

        The Win32 FindWindow API call will return a handle to a window with the specified title and class. Perl/Tk creates windows of the class TkTopLevel. You must call this after the window has been mapped (i.e. after MainLoop), otherwise you won't get a valid window handle.

        A useful reference when using Win32::API is here, it talks about Visual Basic but you can fairly easily convert it to Perl.

        Kevin O'Rourke

        I tried the VB code, converted to Perl and using Win32::API. (the code isn't the tidiest in the world, I've missed out most of the program):

        ... use Tk; use Win32::API; # Windows constants my ($OnTop, $NoTop, $Top) = (-1, -2, 0); my ($SWP_NOMOVE, $SWP_NOSIZE) = (2, 1); ... # Create a Win32::API object for SetWindowPos my $SetWindowPos = new Win32::API("user32", "SetWindowPos", [N,N,N,N,N +,N,N], N); ... my $w = new MainWindow; ... # do the 'always on top' bit my $hwnd = $w->frame; # frame returns a hex value as a string, e.g. "0 +x1234" print "$hwnd\n"; $SetWindowPos->Call(hex($hwnd), $OnTop, 0, 0, 0, 0, $SWP_NOMOVE | $SWP +_NOSIZE); MainLoop;

        Unfortunately $w->frame returns the Tk MainWindow, not the Win32 window containing it. As a result setting $w->frame 'always on top' doesn't have any effect.

        Anyone know how to get an HWND for a window's parent out of Win32? Tk::Wm's $w->wrapper doesn't work either.

        Kevin O'Rourke

        Thanks, I've had a look at the VB. I assume if I can extract an HWND from Tk I could use this. It's a bit nasty but looks like the only way.

        From my reading of Tk::Wm documentation I should be able to get the HWND using $w->frame. Time for a play with Win32::API

        Kevin O'Rourke

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://78848]
Approved by root
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others about the Monastery: (11)
As of 2015-12-01 12:32 GMT
Find Nodes?
    Voting Booth?

    My keyboard shows this many letters:

    Results (9 votes), past polls