Schrift
[thread]12980[/thread]

canvas rect item callback Frage

Leser: 1


<< >> 6 Einträge, 1 Seite
FoolAck
 2009-01-11 21:51
#117861 #117861
User since
2008-05-02
69 Artikel
BenutzerIn
[default_avatar]
Moin.

Ich möchte ein callback genau dann ausgeführt haben, wenn die Maus in ein Rectitem gelangt (<Enter>) und gleichzeitig ein Mausbutton gedrückt ist.
Hier mein Versuch:


Code (perl): (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#!/usr/bin/env perl
use strict;
use warnings;
use Tk;

$|++;

my $data = {
    pressed => 0,
};

my $mw = MainWindow->new();
my $canvas = $mw->Canvas(-width => 200, -height => 200)->pack();
$canvas->CanvasBind('<ButtonPress>',   sub {$data->{pressed} = 1; print "pressed\t";});
$canvas->CanvasBind('<ButtonRelease>', sub {$data->{pressed} = 0; print "released\n";});

my @items;
for my $x (1 .. 4) {
    my $x1 = $x * 25;
    my $y1 = $x1;
    my $x2 = $x1 + 25;
    my $y2 = $y1 + 25;

    $items[$x - 1] = $canvas->createRectangle($x1, $y1, $x2, $y2, -fill => 'red', -width => 0);
}

$canvas->bind($items[$_], '<Enter>', sub {if ($data->{pressed}) {print "wtf\t"}}) for 0 .. 3;

MainLoop();

Das Script gibt "pressed" und "released" wie erwartet aus. Aber "wtf" nur, wenn man den Mausbutton innerhalb eines Rects released, in das man vorher ge"Enter"t ist während ein Mausbutton gedrückt war. "Enter"t man (mit gedrücktem Mausbutton) mehrere Mal das Selbe Rectitem, so gibt das Script entsprechend oft "wtf" aus, allerdings auch erst beim release-Event. (Aus verschiedensten Kombis (außerhalb eines rects drücken, in verschiedene rects "Enter"n und dann außerhalb eines rects wieder releasen etc.pp.) werd ich irgendwie auch nicht schlauer, eher noch verwirrter.)
Gebe ich statt nur "wtf" auch "wtf $data->{pressed}" aus, wird immer "wtf 1" ausgegeben.

Wo liegt mein Denkfehler?

edit: hab mal output-buffering ausgestellt. Erstmal: die wtfs die kommen jetzt zumindest (größtenteils) zur richtigen Zeit. Aber:
Es kommt nur, wenn man
1. einen Mausbutton in einem rect drückt und dann immer wieder in das Selbe rect "Enter"t. (Dann kommts "direkt", also zeitlich korrekt.)
2. wenn man außerhalb eines rects einen Mausbutton drückt und dann in ein rect eintritt und dort released. (Dann kommts erst mit dem release-Event. Und dann auch maximal ein "wtf".)
3. eine Mischung aus beiden: man drückt einen Mausbutton innerhalb rects A und "Enter"t dann rect B. released man dann innerhalb von rect B kommt ein zusätzliches "wtf" (zu denen, die eventuell schon von rect A kamen) dazu, allerdings auch erst wie bei 2. mit dem release-Event.
Spieler
 2009-01-12 01:55
#117862 #117862
User since
2007-09-24
70 Artikel
BenutzerIn
[default_avatar]
Code: (dl )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
use strict;
use warnings;
use Tk;

$|++;

my $data = {
pressed => 0,
};

my $mw = MainWindow->new();
my $canvas = $mw->Canvas(-width => 200, -height => 200)->pack();
my @items;
for my $x (1 .. 4) {
my $x1 = $x * 25;
my $y1 = $x1;
my $x2 = $x1 + 25;
my $y2 = $y1 + 25;

$items[$x - 1] = $canvas->createRectangle($x1, $y1, $x2, $y2, -fill => 'red', -width => 0);
}

$canvas->Tk::bind( '<B1-Motion>', [\&b1_motion,Tk::Ev('x'),Tk::Ev('y')]) for 0 .. 3;
MainLoop();

sub b1_motion{
my ($c,$x,$y) = @_;
my $item_id = $c->find('overlapping',$x,$y,$x,$y);
$item_id = defined $item_id ? $item_id->[0] : '';
print "processing item $item_id\n" if $item_id;
}

Meinst du so etwas?

Grüße, Christoph
FoolAck
 2009-01-12 03:04
#117863 #117863
User since
2008-05-02
69 Artikel
BenutzerIn
[default_avatar]
Nö. Der callback soll nur einmal ausgeführt werden (deswegen das bind auf "<Enter>") pro rectitem. Nicht bei jeder Mausbewegung innerhalb des rects, sondern halt nur beim "eintreten" in den rect-Bereich. Bei "<Enter>" halt.
(Wobei "<Enter>" kein Muss ist, ist halt nur imho die einleuchtendste Alternative bei meiner Problemstellung.)
Spieler
 2009-01-12 09:10
#117864 #117864
User since
2007-09-24
70 Artikel
BenutzerIn
[default_avatar]
Merk dir doch einfach das aktuelle Item und führe den Callback nur aus, wenn es ein neues ist...

Grüße, Christpoh
FoolAck
 2009-01-12 17:06
#117879 #117879
User since
2008-05-02
69 Artikel
BenutzerIn
[default_avatar]
Naja, das wäre ne Notlösung/Workaround. (Performancemäßig wird da auch viel verschenkt. "<B1-Enter>" müsste es geben. Hm, grade nachgesehen. Scheints sogar zu geben, mal ausprobieren...) Wobei ich meinen initialen Denkfehler immer noch nicht sehe..

edit: "<B1-Enter>" verhält sich ziemlich genau so wie meine "selbst gebackene" Lösung. HM

edit:
Quote
Enter and Leave events trigger for an item when it becomes the current item or ceases to be the current item; note that these events are different than Enter and Leave events for windows.

von hier. Hm, muss ich mich wohl doch von <Enter> trennen...

edit: ok, ich habs nu mit deiner Lösung gemacht Christoph. Und performance geht eigentlich. Vielen liepen Dank o/
Spieler
 2009-01-12 21:06
#117890 #117890
User since
2007-09-24
70 Artikel
BenutzerIn
[default_avatar]
Hallo,

hab noch ein Wenig herumgespielt:
Code: (dl )
1
2
3
4
5
6
use Tk;
my $mw = tkinit;

$mw->Entry()->pack->bind('<Enter>',sub{print"entered\n"}) for (0..5);

MainLoop;


Zeigt bei mir unter X11 das gleiche Verhalten wie der Canvas:
Empfängt ein Entry <ButtonDown>, so werden die folgenden <Enter> events (bis zum ButtonRelease) nur noch für dieses Entry Widget ausgelöst.

Das ist scheinbar im Fall von Canvas so implementiert, damit es mit dem Verhalten der Widgets konsistent ist. Auf jeden Fall sagt ein Kommentar in tkCanvas.c:
Code: (dl )
1
2
3
4
5
6
    /*
* Check whether or not a button is down. If so, we'll log entry
* and exit into and out of the current item, but not entry into
* any other item. This implements a form of grabbing equivalent
* to what the X server does for windows.
*/

Interessant. Erwartet hätte ich das nicht ...

Grüße, Christoph
<< >> 6 Einträge, 1 Seite



View all threads created 2009-01-11 21:51.