Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Chriss Miller on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Tk drag to move toplevel window

Status
Not open for further replies.

Kirsle

Programmer
Jan 21, 2006
1,179
US
My latest Tk experiment was to have a widget in a window that, when clicked and dragged, would move the window it was in (or basically, to enable me to do overrideredirect to remove the window chrome, and make my own title bar widget that could be dragged to move the window around).

Here's the code I have so far:

Code:
#!/usr/bin/perl -w

use strict;
use warnings;
use Tk;

my $main = MainWindow->new;
$main->overrideredirect(1);
$main->geometry ('400x400+10+20');

my $dragger = $main->Frame (-background => 'orange')->pack (-fill => 'both', -expand => 1);

my $winX = 10;
my $winY = 20;

my $dragFromX = 0;
my $dragFromY = 0;

my $isDragging = 0;

$dragger->bind ('<ButtonPress-1>', sub {
	$isDragging = 1;

	# dragFrom vars should be the offset from 0,0 to the current position.
	$dragFromX = $Tk::event->x;
	$dragFromY = $Tk::event->y;

	print "Drag from: $dragFromX,$dragFromY\n";
});

$dragger->bind ('<ButtonRelease-1>', sub {
	$isDragging = 0;
});

$dragger->bind ('<Motion>', sub {
	return unless $isDragging;

	# Get the new position.
	my $curX = $Tk::event->x;
	my $curY = $Tk::event->y;

	$winX = $curX;
	$winY = $curY;

	print "MoveTo: $winX,$winY\n";

	$main->MoveToplevelWindow ($winX,$winY);
});

MainLoop;

It creates a 400x400 orange window a little ways away from the top left corner of the screen. When I click and drag, it only partly works.

By this I mean, the window does slowly move in the direction I'm dragging it, but while it's moving, it also keeps flickering in another position up and to the left of its current one. So as I drag it, it flickers back and forth between two positions slowly moving in the direction I'm dragging. When I let go of the mouse, it will pick one of these positions to stay in.

Maybe I'm just not thinking mathematically enough, but can anyone point out what might be a problem in my code?

Thanks in advance.
 
Kirsle,

my $curX = $Tk::event->x;
my $curY = $Tk::event->y;


needs to read

my $curX = $Tk::event->X;
my $curY = $Tk::event->Y;


The X and Y needs to be capitalized.


Small caps xy returns the event's coordinate relative to the widget.

Upper caps XY returns the event's coordinate relative to the root window.

Regards,
Raklet
 
Thanks! It works smoothly now!

I think I should be able to go from here and get the cursor to stay put during drag rather than jump to the corner.
 
Alright, I got my code all working how I want it to.

It took me a while to figure out that upper caps X and Y returned the coordinates relative to my screen (you said relative to root window, so the root window must've been the windows desktop?)

So, on click I had it turn the $dragFromX and $dragFromY to be relative to the corner of the window, rather than relative from the screen. After I figured this much out, it was no problem getting the cursor to stay put during drag... just subtract the drag coordinates (relative) to the new position of the window, so that the top left corner stays the same distance away from where I clicked the whole time.

Here's my code if anyone's interested. I changed the orange window to be a Toplevel of a normal MainWindow, to see if everything would still function properly if it wasn't its own main window. To change it back to being a MainWindow, just take out the $top line and change $top->Toplevel to MainWindow->new

Code:
#!/usr/bin/perl -w

use strict;
use warnings;
use Tk;

my $top = MainWindow->new;

my $main = $top->Toplevel;
$main->overrideredirect(1);
$main->geometry ('400x400+10+20');

my $dragger = $main->Frame (-background => 'orange')->pack (-fill => 'both', -expand => 1);

my $winX = 10;
my $winY = 20;

my $dragFromX = 0;
my $dragFromY = 0;

my $isDragging = 0;

$dragger->bind ('<ButtonPress-1>', sub {
	$isDragging = 1;

	# dragFrom vars should be the offset from 0,0 to the current position.
	$dragFromX = $Tk::event->X - $winX;
	$dragFromY = $Tk::event->Y - $winY;

	print "Drag from: $dragFromX,$dragFromY\n";
});

$dragger->bind ('<ButtonRelease-1>', sub {
	$isDragging = 0;
});

$dragger->bind ('<Motion>', sub {
	return unless $isDragging;

	# Get the new position.
	my $curX = $Tk::event->X;
	my $curY = $Tk::event->Y;

	$curX -= $dragFromX;
	$curY -= $dragFromY;

	$winX = $curX;
	$winY = $curY;

	print "Cur: $curX,$curY;   MoveTo: $winX,$winY (dragFrom: $dragFromX,$dragFromY)\n";

	$main->MoveToplevelWindow ($winX,$winY);
});

MainLoop;
 
Nice work on that piece.

It took me a while to figure out that upper caps X and Y returned the coordinates relative to my screen (you said relative to root window, so the root window must've been the windows desktop?)

I was quoting straight out of the documentation in Mastering Perl/Tk. It uses the term "root window" - whatever that means.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top