in reply to Re^9: Tk Drag and Drop Between Applications
in thread Tk Drag and Drop Between Applications

Courage, Thank you so very much for your help so far!
After a sanity break, I got my app up in Tcl::Tk in Perl/Tk compatability mode. I've been reading demos, docs, and articles. This is the Tcl/Tk code that I think I need to run (followed by my questions):
package require tkdnd dnd bindsource .perl_hlist_object text/uri {\&Perl_Sub} bind .perl_hlist_object <1> {dnd drag %W}

1) Do I need the interp object to setup DnD?

I can start a Tcl::Tk GUI in one of two ways:
my $mw = MainWindow->new; #Gives me the main window object, but not + the interpreter my $interp = new Tcl::Tk; #Gives me the interpreter, but not the ma +in window

Do I need both objects? I think I need the interp object to make DnD calls, and the main window object to use perl/Tk compatability mode syntax. Is there a way to get both objects? Should I rewrite the GUI in Tcl/Tk syntax?

2) Can I get a Tcl/Tk path from a perl widget object?

This is related to #1. I can get object for a Tcl/Tk path with: my $hlist = widget(".f03.hlist01"); However, I have the ojbect and I think I need the path to set up DnD.

3) How do I make the actual calls?

Here's my stab at the Tcl/Tk objects under Tcl::Tk in perl (I haven't tested this because of #1):

My $i = new Tcl::Tk; (... generate GUI ...) $i -> call("package require", "tkdnd"); $i -> call("dnd bindsource", ".perl_hlist_object", "text/uri", {\&Perl +_Sub}); $i -> call("bind", ".perl_hlist_object", "<1>", {dnd drag %W};
Is this correct, are there any gotchas?

  1. Can I put a use a perl object instead of a Tcl/Tk path (i.e. $results_l instead of .f03.hlist01)?
  2. Is the script on line 4 expecting a Tcl sub, or can I call a perl sub? Is there a special syntax?
  3. I don't understand the reference to %W. It's "The window the event is delivered to", and it doesn't make sense to me in this context. Would I leave it %W, or do I need to provide a value?
I greatly appreciate any help in this. It feels like I'm close, but I don't know where to look for the 'last mile'.

Replies are listed 'Best First'.
Re: Tcl::Tk GUI working - Help with TkDnD through perl?
by Courage (Parson) on Dec 22, 2004 at 09:03 UTC
    To answer your questions in very brief:
    • indeed, you need interpreter to make any Tcl/Tk operations.
    • at any time $widget->interp returns it
    • at any time $widget->path returns widget path in the form .fr.t stringification should also work so "$widget" should return path;
    • Tcl::Tk and Tk widgets are very interchangeable, and here lies the extreme power of approach. Say, you have existing GUI, you can write $button=widget('.fr.b'); and then just use $button with perl/Tk syntax
    • to make Tcl/Tk calls, you should go either of following ways:
      1. $interp->Eval('package require tkdnd');
      2. $interp->invoke('package', 'require', 'tkdnd');
      3. $interp->call('package', 'require', 'tkdnd');
      1st one allows you to execute any Tcl/Tk code, 2nd is much faster than all of them because there is no parsing or substitution, 3rd one is most generic and most frequently used and it allows for you to directly use anonymous subroutines, scalar references and so on...

      It could be a bit confusing that Tcl uses curly braces in a very different way compared to Perl (those are string delimeters w/o interpolation) but you do not need to go into Tcl syntax really deep.

      What you wrote

      $i -> call("dnd bindsource", ".perl_hlist_object", "text/uri", {\&Perl +_Sub}); $i -> call("bind", ".perl_hlist_object", "<1>", {dnd drag %W};
      should probably be
      $i -> call("dnd", "bindsource", ".perl_hlist_object", "text/uri", \\'% +W',sub{Perl_Sub(shift)}); $i -> call("bind", ".perl_hlist_object", "<1>", 'dnd drag %W');
    %ev-variables processed differently in Tcl::Tk compared to perlTk so this '%W' could be a bit tricky, this is described in perl's Tcl module... I can check for details later, so let me know on your further results.

    Also use Tcl::Tk discussion list tcltk-perl at lists.sourceforge.net

    addition 1 Please refer to documentation of Tcl.pm module using perldoc Tcl, or may be http://search.cpan.org/~vkon/Tcl-0.84/Tcl.pm, so there are plenty explanations of 'call', 'icall', 'invoke' methods

    Best regards,
    Courage, the Cowardly Dog

Re: Tcl::Tk GUI working - Help with TkDnD through perl?
by Courage (Parson) on Dec 22, 2004 at 17:29 UTC
    Okay, I've played with the same Tcl module and demo as you did and found here are two ways of performing task: almost pure-tcl and reworked for perlTk syntax.

    First one, bacically feeds original demo to Tcl interpreter, and starting MainLoop (remember you still have very easy access to Tk widgets with perlTk syntax...)

    use strict; use Tcl::Tk; my $mw = Tcl::Tk::tkinit; $mw->interp->Eval(<<'EOS'); package require tkdnd ## Iconify ".". We are going to add windows and call update many times +. ## Avoid some interesting visual effects :-) wm withdraw . #--------------------------------------------------------------------- +--------- # Step 1: A simple Drag Source #--------------------------------------------------------------------- +--------- # create the source window label .source -text "source" -relief groove -bd 2 -width 20 pack .source -pady 5 # tells the DND protocol source can deliver textual data dnd bindsource .source text/plain {return "testing DND"} # bind the DND operation on left button bind .source <1> {dnd drag %W} #--------------------------------------------------------------------- +--------- # Step 1: A simple Drop Target accepting plain text #--------------------------------------------------------------------- +--------- # defines the target window label .text_plain -text "drop plain text" -relief raised -bd 1 -width +20 pack .text_plain -pady 5 # Before registering a drop target, we always have to make sure the # corresponding widget has been created: update idle # tells the DND protocol target can handle textual data dnd bindtarget .text_plain text/plain <Drop> \ {%W configure -text %D; status "\[target1\] type='%T', action='%A'" after 2000 {%W configure -text "drop plain text"}} #--------------------------------------------------------------------- +--------- # Step 2: Management of multiple types on the source #--------------------------------------------------------------------- +--------- # defines an other type on source dnd bindsource .source TK_COLOR {return "pink"} # defines a target window label .target2 -text "drop color" -relief raised -bd 1 -width 20 \ -bg lightyellow pack .target2 -pady 5 # tells the DND protocol target can handle color data dnd bindtarget .target2 TK_COLOR <Drop> { status "\[target2\] type='%T', data='%D', action='%A'" .target2 configure -bg %D after 2000 ".target2 configure -bg lightyellow" } #===================================================================== +========= # END #===================================================================== +========= proc status {msg} { .status configure -text $msg } proc init {} { wm title . "Simple Drag & Drop Demo..." label .status -relief sunken -bd 1 -width 60 -anchor w pack .status -side bottom -fill x pack [frame .sep -height 10] -side bottom -fill x pack propagate .status 0 } init update wm deiconify . EOS # Tcl inclusion for GUI finished here; you can work with widgets here +like: # my $lab = $mw->interp->widget('.status'); # $lab->configure(-text=>'new text here...'); Tcl::Tk::MainLoop;

    2nd method is reworked a bit to be more Perl-looking:

    use strict; use Tcl::Tk; my $mw = Tcl::Tk::tkinit; my $interp = $mw->interp; $interp->invoke('package', 'require', 'tkdnd'); ## Iconify ".". We are going to add windows and call update many times +. ## Avoid some interesting visual effects :-) #wm withdraw . #--------------------------------------------------------------------- +--------- # Step 1: A simple Drag Source #--------------------------------------------------------------------- +--------- # create the source window my $lab_source = $mw->Label(-text=>"source", qw/-relief groove -bd 2 - +width 20/)->pack(-pady=>5); # tells the DND protocol source can deliver textual data $interp->call('dnd','bindsource', $lab_source->path, 'text/plain', q{r +eturn "testing DND"}); # bind the DND operation on left button $interp->call('bind', $lab_source->path, '<1>', 'dnd drag %W'); #--------------------------------------------------------------------- +--------- # Step 1: A simple Drop Target accepting plain text #--------------------------------------------------------------------- +--------- # defines the target window my $lab_text_plain = $mw->Label(-text=>"drop plain text", qw/-relief r +aised -bd 1 -width 20/)->pack(-pady=>5); # Before registering a drop target, we always have to make sure the # corresponding widget has been created: $interp->update('idle'); # tells the DND protocol target can handle textual data $interp->call('dnd','bindtarget', $lab_text_plain, 'text/plain', '<Dro +p>', \\'WDTA', sub { my (undef,$int,$sub) = (shift,shift,shift); my ($W,$D,$T,$A) = (@_); # Ev vars my $receiver_widget = $int->widget($W); $receiver_widget->configure(-text=>$D); status("[target1] type='$T', action='$A'"); $int->after(2000, sub {$receiver_widget->configure(-text=>"drop pl +ain text")}); }); #--------------------------------------------------------------------- +--------- # Step 2: Management of multiple types on the source #--------------------------------------------------------------------- +--------- # defines an other type on source $interp->call('dnd','bindsource', $lab_source->path, 'TK_COLOR', q{ret +urn "pink"}); # defines a target window my $lab_t2 = $mw->Label(-text=>"drop color", qw/-relief raised -bd 1 - +width 20 -bg lightyellow/) ->pack(-pady=>5); # tells the DND protocol target can handle color data $interp->call('dnd','bindtarget', $lab_t2, 'TK_COLOR', '<Drop>', , \\ +'WDTA', sub { my (undef,$int,$sub) = (shift,shift,shift); my ($W,$D,$T,$A) = (@_); # Ev vars $lab_t2->configure(-bg=>$D); status("[target1] type='$T', action='$A'"); $int->after(2000, sub {$lab_t2->configure(-bg=>'lightyellow')}); }); #===================================================================== +========= # END #===================================================================== +========= $interp->wm('title','.',"Simple Drag & Drop Demo..."); my $lab_stat = $mw->Label(qw/-relief sunken -bd 1 -width 60 -anchor w/ +)->pack(qw/-side bottom -fill x/); $mw->Frame(-height=>10)->pack(qw/-side bottom -fill x/); sub status { my $msg = shift; $lab_stat->configure(-text=>$msg); } $mw->update; $interp->MainLoop;

    Best regards,
    Courage, the Cowardly Dog

      Courage & Monks,

      I'm just getting back from winter break (and I hope you had a good holiday). Thank you so much for all of your advice and input! With your extensive help I got the application working prior to leaving for holiday.

      My DnD implementation is now five by five.

      Thanks again,

      Ardemus