tkjoystick.py
Go to the documentation of this file.
1 #!/usr/bin/env python
2 # -*- coding: utf-8 -*-
3 # -*- Python -*-
4 
5 #
6 # @brief tk joystick
7 # @date $Date$
8 # @author Norkai Ando <n-ando@aist.go.jp>
9 #
10 # Copyright (C) 2007
11 # Noriaki Ando
12 # Task-intelligence Research Group,
13 # Intelligent Systems Research Institute,
14 # National Institute of
15 # Advanced Industrial Science and Technology (AIST), Japan
16 # All rights reserved.
17 #
18 # $Id$
19 #
20 
21 # $Log$
22 #
23 
24 from Tkinter import *
25 import time
26 import math
27 import mutex
28 import sys
29 
30 class ToggleItem:
31  def __init__(self):
32  self.active = True
33 
34  def activate(self):
35  self.active = True
36  self.draw()
37 
38  def deactivate(self):
39  self.active = False
40  self.delete()
41 
42  def toggle(self):
43  if self.active:
44  self.deactivate()
45  else:
46  self.activate()
47 
48 
50  def __init__(self, canvas, text, x, y):
51  ToggleItem.__init__(self)
52  self.canvas = canvas
53  self.id = self.canvas.create_text(x, y, text=text)
54  self.text = text
55  self.x = x
56  self.y = y
57  self.draw_text(x, y, text)
58 
59  def draw(self):
60  if self.active == False: return
61  self.delete()
62  self.id = self.canvas.create_text(self.x, self.y, text=self.text)
63 
64  def draw_text(self, x, y, text):
65  self.x = x
66  self.y = y
67  self.text = text
68  self.draw()
69 
70  def delete(self):
71  self.canvas.delete(self.id)
72 
73 
75  def __init__(self, canvas, width, height):
76  ToggleItem.__init__(self)
77  self.x0 = width/2
78  self.y0 = height/2
79  self.width = width
80  self.height = height
81  self.canvas = canvas
82  self.id = [None] * 4
83  self.draw()
84 
85  def draw(self):
86  if self.active == False: return
87  self.delete()
88  self.id[0] = self.canvas.create_line(0, self.height/2,
89  self.width, self.height/2)
90  self.id[1] = self.canvas.create_text(self.width - 10,
91  self.height/2 + 10,
92  text="x")
93  self.id[2] = self.canvas.create_line(self.width/2, 0,
94  self.width/2, self.height)
95  self.id[3] = self.canvas.create_text(self.width/2 + 10,
96  + 10, text="y")
97  return
98 
99  def delete(self):
100  for i in self.id:
101  self.canvas.delete(i)
102 
104  def __init__(self, canvas, x, y, width, height, pitch):
105  ToggleItem.__init__(self)
106  self.canvas = canvas
107  self.x = x
108  self.y = y
109  self.width = width
110  self.height = height
111  self.pitch = pitch
112  self.id = []
113  self.draw()
114 
115  def draw(self):
116  if self.active == False: return
117  self.delete()
118  if self.pitch == 0:
119  circnum = 0
120  else:
121  circnum = max(self.width, self.height) / self.pitch
122  circrange = range(circnum)
123  circrange.reverse()
124  for i in circrange:
125  x0 = self.x - self.pitch * i
126  y0 = self.y - self.pitch * i
127  x1 = self.x + self.pitch * i
128  y1 = self.y + self.pitch * i
129  if i % 2 == 0:
130  color = "#dddddd"
131  else:
132  color = "#eeeeee"
133  id = self.canvas.create_oval(x0, y0, x1, y1, fill=color,
134  outline="#ffffff")
135  self.id.append(id)
136  id = self.id
137  id.reverse()
138  for i in id:
139  self.canvas.tag_lower(i)
140 
141  def delete(self):
142  for c in self.id:
143  self.canvas.delete(c)
144 
145  def set_pitch(self, pitch):
146  self.pitch = pitch
147  self.draw()
148 
150  def __init__(self, canvas, x0, y0, x1, y1, color, width):
151  ToggleItem.__init__(self)
152  self.canvas = canvas
153  self.x0 = x0
154  self.y0 = y0
155  self.x1 = y1
156  self.y1 = y1
157  self.color = color
158  self.width = width
159  self.id = self.canvas.create_line(self.x0, self.y0, self.x1, self.y1,
160  fill=self.color, width=self.width)
161  self.draw()
162 
163  def draw(self):
164  if self.active == False: return
165  self.delete()
166  self.id = self.canvas.create_line(self.x0, self.y0, self.x1, self.y1,
167  fill=self.color, width=self.width)
168  def draw_line(self, x0, y0, x1, y1):
169  self.x0 = x0
170  self.y0 = y0
171  self.x1 = x1
172  self.y1 = y1
173  self.draw()
174 
175  def delete(self):
176  self.canvas.delete(self.id)
177 
178 class Stick:
179  def __init__(self, canvas, x, y, r, **key):
180  self.canvas = canvas
181  # Joystick ID
182  self.key = key
183  self.id = self.canvas.create_oval(x-r, y-r, x+r, y+r, **key)
184  # ID of the line from center to joystick handle
185  self.line = None
186  # (x,y) text ID
187  self.xy_text = None
188  # (r,th) text ID
189  self.pol_text = None
190 
191  # Offset from display coordinate system to joystick coordinate
192  # system
193  self.offsetx = x
194  self.offsety = y
195 
196  # Position of the joystick in the display joystick coordinate
197  # system
198  self.x = 0
199  self.y = 0
200 
201  # Position of the jpystick in the jpystick coordinate system
202  self.pos_x = 0
203  self.pos_y = 0
204 
205  self.coffx = 0
206  self.coffy = 0
207 
208  # Binding to joystick
209  self.make_binds()
210 
211  def set_on_drag_start(self, func):
212  self.on_drag_start = func
213 
214  def set_on_dragging(self, func):
215  self.on_dragging = func
216 
217  def set_on_drag_end(self, func):
218  self.on_drag_end = func
219 
220  def make_binds(self):
221  self.canvas.tag_bind(self.id, '<1>', self.drag_start)
222  self.canvas.tag_bind(self.id, '<Button1-Motion>', self.dragging)
223  self.canvas.tag_bind(self.id, '<Button1-ButtonRelease>', self.drag_end)
224 
225  def drag_start(self, event):
226  # Calculate offset on the clocked position
227  x1 = event.x - self.offsetx
228  y1 = event.y - self.offsety
229  self.coffx = x1 - self.x
230  self.coffy = y1 - self.y
231 
232  self.calc_pol(self.pos_x, self.pos_y)
233 # self.draw_text()
234 
235  # Callback
236  if self.on_drag_start != None:
237  self.on_drag_start((self.pos_x, self.pos_y), (self.r, self.th))
238 
239  def dragging(self, event):
240  # Moving length of drag
241  x1 = event.x - self.offsetx
242  y1 = event.y - self.offsety
243  dx = (x1 - self.x) - self.coffx
244  dy = (y1 - self.y) - self.coffy
245 
246  # Moving circle
247  self.canvas.move(self.id, dx, dy)
248  self.canvas.tag_raise(self.id)
249  # Calculate joystick position
250  self.x = x1 - self.coffx
251  self.y = y1 - self.coffy
252  self.pos_x = self.x
253  self.pos_y = -self.y
254  self.calc_pol(self.pos_x, self.pos_y)
255 
256  # Callback
257  if self.on_dragging != None:
258  self.on_dragging((self.pos_x, self.pos_y), (self.r, self.th))
259 
260  def drag_end(self, event):
261  x1 = event.x - self.offsetx
262  y1 = event.y - self.offsety
263  # Moving length to return back
264  dx = x1 - self.coffx
265  dy = y1 - self.coffy
266  self.canvas.move(self.id, -dx, -dy)
267  self.x = 0
268  self.y = 0
269  self.pos_x = 0
270  self.pos_y = 0
271  self.calc_pol(self.pos_x, self.pos_y)
272  # Callback
273  if self.on_drag_end != None:
274  self.on_drag_end((self.pos_x, self.pos_y), (self.r, self.th))
275 
276  def calc_pol(self, x, y):
277  r = math.hypot(x, y)
278  if r == 0:
279  th = 720.0
280  elif y >= 0.0:
281  th = math.acos((x * 1.0) / (r * 1.0)) * 180.0 / math.pi
282  elif y < 0.0:
283  th = math.acos((x * 1.0) / (r * 1.0)) * -180.0 / math.pi
284  self.r = r
285  self.th = th
286  return (r, th)
287 
288  def get_pos(self):
289  return self.pos_x, self.pos_y, self.r, self.th
290 
291 
292 class TkJoystick(Frame):
293  def __init__(self, r=10, width=300, height=300, master=None):
294  Frame.__init__(self, master)
295 
296  self.pos_x = 0.0
297  self.pos_y = 0.0
298  self.pol_r = 0.0
299  self.pol_th = 0.0
300 
301  self.stick_r = r
302 
303  self.width = width
304  self.height = height
305 
306  self.wd = 160
307 
308  self.x0 = width/2
309  self.y0 = height/2
310 
311  self.xentry = ""
312  self.yentry = ""
313  self.rentry = ""
314  self.thentry = ""
315 
316  # scale variable
317  self.scale_var = DoubleVar()
318  self.scale_var.set(1.0)
319 
320  # checkbutton variables
321  self.vline_check = StringVar()
322  self.vline_check.set("on")
323  self.axis_check = StringVar()
324  self.axis_check.set("on")
325  self.circ_check = StringVar()
326  self.circ_check.set("on")
327  self.xy_check = StringVar()
328  self.xy_check.set("on")
329  self.pol_check = StringVar()
330  self.pol_check.set("on")
331 
332  # x-y entry variables
333  self.xentry = StringVar()
334  self.xentry.set("0.0")
335  self.yentry = StringVar()
336  self.yentry.set("0.0")
337 
338  # polarpos entry variables
339  self.rentry = StringVar()
340  self.rentry.set("0.0")
341  self.thentry = StringVar()
342  self.thentry.set("0.0")
343 
344  # text position
345  self.xytext_x = self.width - 50
346  self.xytext_y = self.height - 25
347  self.poltext_x = self.width - 60
348  self.poltext_y = self.height - 10
349 
350  # vector line
351  self.vline_color = "#aaaaaa"
352  self.vline_width = 2
353  self.default_pitch = 50
354 
355  # callback function
356  self.on_update = None
357 
358  self.init()
359  self.pack()
360 
361 
362  def init(self):
363  self.canvas = Canvas(self, bg="white", \
364  width = self.width, height = self.height)
365  self.canvas.pack(side=LEFT)
366 
367  # coaxial pattern
369  self.x0, self.y0,
370  self.width, self.height, pitch=50)
371 
372  # axis
373  self.can_axis = CanvasAxis(self.canvas, self.width, self.height)
374 
375  # x-y text
376  text = 'x: %4d, y: %4d' % (0, 0)
377  self.can_xytext = CanvasText(self.canvas, text,
378  self.xytext_x, self.xytext_y)
379 
380  # polar position text
381  text = 'r: %4.2f, th: NaN' % (0.0)
382  self.can_poltext = CanvasText(self.canvas, text,
383  self.poltext_x, self.poltext_y)
384 
385  self.can_vline = CanvasLine(self.canvas, self.x0, self.y0,
386  self.x0, self.y0,
387  self.vline_color, self.vline_width)
388 
389  # joystick circle
390  self.stick = Stick(self.canvas, self.width/2, self.height/2,
391  self.stick_r,
392  fill="#999999", width=1)
393  self.stick.set_on_drag_start(self.on_pos_update)
394  self.stick.set_on_dragging(self.on_pos_update)
395  self.stick.set_on_drag_end(self.on_pos_update)
396 
397 
398  # right side widgets
399  self.frame = Frame(self, height=self.height, width=self.wd)
400  self.frame.pack(side=LEFT, fill=Y, padx=3, pady=3)
401  self.create_scale(self.frame).pack(side=TOP, fill=Y)
402  self.create_checkbutton(self.frame).pack(side=TOP, fill=Y)
403  self.create_pollabel(self.frame).pack(side=BOTTOM, fill=Y)
404  self.create_xylabel(self.frame).pack(side=BOTTOM, fill=Y)
405  return
406 
407  def create_scale(self, frame):
408  f = Frame(frame, bd=2, relief=GROOVE)
409  dummy = Frame(f, width=self.wd)
410  dummy.pack(side=TOP)
411  sl = Scale(f, from_=0, to=10, resolution=0.01,
412  label="Scale Factor", command=self.on_scale,
413  variable=self.scale_var, orient=HORIZONTAL)
414  bt = Button(f, text="Reset Scale", command=self.reset_scale)
415  sl.pack(side=TOP, fill=X)
416  bt.pack(side=TOP, fill=X)
417  return f
418 
419  def on_scale(self, val):
420  v = float(val)
421  if v == 0.0:
422  pitch = 0
423  else:
424  pitch = self.default_pitch/v
425  self.can_circle.set_pitch(pitch)
426 
427  def create_checkbutton(self, frame):
428  f = Frame(frame, bd=2, relief=GROOVE)
429  dummy = Frame(f, width=self.wd)
430  dummy.pack(side=TOP)
431  vec = Checkbutton(f, text="Vector Line",
432  onvalue="on", offvalue="off",
433  justify=LEFT, anchor=W,
434  variable=self.vline_check,
435  command=self.can_vline.toggle)
436  axis = Checkbutton(f, text="Axis",
437  onvalue="on", offvalue="off",
438  justify=LEFT, anchor=W,
439  variable=self.axis_check,
440  command=self.can_axis.toggle)
441  circ = Checkbutton(f, text="Background",
442  onvalue="on", offvalue="off",
443  justify=LEFT, anchor=W,
444  variable=self.circ_check,
445  command=self.can_circle.toggle)
446  xy = Checkbutton(f, text="X-Y position",
447  onvalue="on", offvalue="off",
448  justify=LEFT, anchor=W,
449  variable=self.xy_check,
450  command=self.can_xytext.toggle)
451  pol = Checkbutton(f, text="Polar postion",
452  onvalue="on", offvalue="off",
453  justify=LEFT, anchor=W,
454  variable=self.pol_check,
455  command=self.can_poltext.toggle)
456  for w in [vec, axis, circ, xy, pol]:
457  w.pack(side=TOP, anchor=W, fill=X)
458  return f
459 
460  def create_xylabel(self, frame):
461  f = Frame(frame)
462  dummy = Frame(f, width=self.wd)
463  dummy.pack(side=TOP)
464  xl = Label(f, text="x: ", width=3)
465  xe = Entry(f, width=7, textvariable=self.xentry,
466  justify=RIGHT, relief=GROOVE)
467  yl = Label(f, text="y: ", width=3)
468  ye = Entry(f, width=7, textvariable=self.yentry,
469  justify=RIGHT, relief=GROOVE)
470 
471  for w in [ye, yl, xe, xl]:
472  w.pack(side=RIGHT, fill=X)
473  return f
474 
475  def create_pollabel(self, frame):
476  f = Frame(frame, width=self.wd)
477  dummy = Frame(f, width=self.wd)
478  dummy.pack(side=TOP)
479  rl = Label(f, text="r: ", width=3)
480  re = Entry(f, width=7, textvariable=self.rentry,
481  justify=RIGHT, relief=GROOVE)
482  thl = Label(f, text="th:", width=3)
483  the = Entry(f, width=7, textvariable=self.thentry,
484  justify=RIGHT, relief=GROOVE)
485  for w in [the, thl, re, rl]:
486  w.pack(side=RIGHT, fill=X)
487  return f
488 
489  def reset_scale(self):
490  self.scale_var.set(1.)
491  pitch = self.default_pitch/1.0
492  self.can_circle.set_pitch(pitch)
493 
494  def get_pos(self):
495  return self.pos_x, self.pos_y, self.pol_r, self.pol_th
496 
497  def on_pos_update(self, pos, pol):
498  self.pos_x = pos[0] * self.scale_var.get()
499  self.pos_y = pos[1] * self.scale_var.get()
500  self.pol_r = pol[0] * self.scale_var.get()
501  self.pol_th = pol[1]
502 
503  xt = '%4d' % (self.pos_x)
504  yt = '%4d' % (self.pos_y)
505  rt = '%5.2f' % (self.pol_r)
506  if pol[1] > 360: tht = 'NaN'
507  else: tht = '%5.2f' % self.pol_th
508 
509  self.xentry.set(xt)
510  self.yentry.set(yt)
511  self.rentry.set(rt)
512  self.thentry.set(tht)
513 
514  text = 'x: %4d, y: %4d' % (pos[0], pos[1])
515  self.can_xytext.draw_text(self.xytext_x, self.xytext_y, text)
516  if pol[1] > 360:
517  text = 'r: %5.2f, th: NaN' % (pol[0])
518  else:
519  text = 'r: %5.2f, th: %5.2f' % (pol[0], pol[1])
520  self.can_poltext.draw_text(self.poltext_x, self.poltext_y, text)
521 
522  self.can_vline.draw_line(self.x0, self.y0,
523  self.x0 + pos[0],
524  self.y0 - pos[1])
525 
526  if self.on_update != None:
527  self.on_update((self.pos_x, self.pos_y),
528  (self.pol_r, self.pol_th))
529 
530  def set_on_update(self, func):
531  self.on_update = func
532 
533 def test ():
534  m = TkJoystick()
535 
536  while 1:
537  m.update()
538  print m.get_pos()
539 
540 
541 if __name__ == '__main__': test()
def __init__(self, canvas, x0, y0, x1, y1, color, width)
Definition: tkjoystick.py:150
def __init__(self, canvas, width, height)
Definition: tkjoystick.py:75
def __init__(self, canvas, x, y, width, height, pitch)
Definition: tkjoystick.py:104
def __init__(self, canvas, x, y, r, key)
Definition: tkjoystick.py:179
def __init__(self, r=10, width=300, height=300, master=None)
Definition: tkjoystick.py:293
def append(dest, src)
Definition: NVUtil.py:386


openrtm_aist_python
Author(s): Shinji Kurihara
autogenerated on Mon Feb 28 2022 23:01:07