From: Martin DeMello Date: 2004-09-15T21:19:56+09:00 Subject: ruby/tk - getting started I wrote my first small tk app (mostly by pasting in code from various examples and reading through the tcl/tk docs), but now I've run into a wall. The following code displays a canvas and lets the user draw lines on it; the bit I'm stuck at is getting the x,y coordinates of the mouseclick to be the coordinates on the canvas, rather than on the canvas display viewport. (i.e., right now when I scroll, the (x,y) I get from @canvas.bind("1",...) is not the same (x,y) that line.coords needs, since they're using two different coordinate systems) martin require 'tk' class PatternDraw def initialize(parent) TkLabel.new(parent, 'wraplength'=>'4i', 'justify'=>'left', 'text'=>"Cadlab Pattern Generator."){ pack('side'=>'top') } @grid = TkFrame.new(parent) { pack('expand'=>'yes', 'fill'=>'both', 'padx'=>1, 'pady'=>1) } TkGrid.rowconfigure(@grid, 0, 'weight'=>1, 'minsize'=>0) TkGrid.columnconfigure(@grid, 0, 'weight'=>1, 'minsize'=>0) _grid = @grid # canvas @canvas = TkCanvas.new(parent, { 'background' => 'white', 'borderwidth' => 2, 'relief' => 'ridge', 'scrollregion'=> ['-10c', '-10c', '10c', '10c'] }) {|c| grid('in'=>_grid, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') TkScrollbar.new(parent, 'command'=>proc{|*args| c.yview(*args) }) {|vs| c.yscrollcommand(proc{|first,last| vs.set first,last}) grid('in'=>_grid, 'padx'=>1, 'pady'=>1, 'row'=>0, 'column'=>1, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') } TkScrollbar.new(parent, 'orient'=>'horiz', 'command'=>proc{|*args| c.xview(*args)}) {|hs| c.xscrollcommand(proc{|first,last| hs.set first,last}) grid('in'=>_grid, 'padx'=>1, 'pady'=>1, 'row'=>1, 'column'=>0, 'rowspan'=>1, 'columnspan'=>1, 'sticky'=>'news') } } @start_x = @start_y = 0 @canvas.bind("Motion", proc {|x, y| do_motion(x, y)}, "%x %y") @canvas.itembind('all', 'Any-Enter', proc{objEnter @canvas}) @canvas.itembind('all', 'Any-Leave', proc{objLeave @canvas}) @canvas.bind("1", proc {|e| do_press(e.x, e.y)}) @canvas.bind("2", proc{|x,y| @canvas.scan_mark(x,y)}, '%x %y') @canvas.bind("3", proc {|e| release_line}) @canvas.bind('B2-Motion', proc{|x,y| @canvas.scan_dragto(x,y)}, '%x %y') end def objEnter(c) id = c.find_withtag('current')[0].id $oldFill = c.itemconfiginfo(id, 'fill')[4] c.itemconfigure(id, 'fill'=>'SeaGreen1') end def objLeave(c) id = c.find_withtag('current')[0].id c.itemconfigure(id, 'fill'=>$oldFill) end def do_press(x, y) if @current_line @current_line.coords @start_x, @start_y, x, y @current_line.fill 'black' @current_line = nil do_press(x,y) else @start_x = x @start_y = y @current_line = TkcLine.new(@canvas, x, y, x, y) end end def do_motion(x, y) if @current_line @current_line.coords @start_x, @start_y, x, y end end def release_line @canvas.delete(@current_line) @current_line = nil end end root = TkRoot.new{ title 'Canvas' } PatternDraw.new(root) Tk.mainloop