2012-01-04 66 views
1

我有一些浮动在可滚动画布小部件上的文本小部件。我想让用户通过拖动它们的边缘和/或边角来调整它们的大小,如果它们拖动左上角或边角,可能会移动它们。我愿意将它们变成带有文本小部件的框架,因为无论如何我都可以这样做。在tkinter画布内部制作小部件/框架可调整大小

我想我可以手动处理事件,如果我可以让它显示调整大小手柄。我需要捕捉鼠标悬停并自己点击边框吗?

添加一个“<配置>”事件绑定什么都不做,正如人们所期望的。据称ttk.Sizegrip只能在顶层窗口中运行。有很多资源可以用来防止调整大小,但为了方便调整它们却很少,而且它们似乎都适用于顶级窗口。

回答

2

我最终围绕小部件制作了一个带有胖边框的框架,捕捉鼠标事件以及自己处理所有脏调整大小逻辑。

我必须记录点击位置的初始位置和每个连续鼠标移动的位置,并分别用它们来分别调整顶部/左侧和底部/右侧的大小。

编辑:这是一个方便(相对)封装的实现。

from Tkinter import * 

class ResizableCanvasFrame(Frame): 
    ''' 
    Class that handles creating resizable frames on a canvas. 
    Don't pack it. 

    Set save_callback to whatever you want to happen when the mouse 
    lets up on the border. You can catch <Configure> too, but at least 
    in my case I didn't want to save the new position on every mouse move. 
    ''' 
    def __init__(self, master, x, y, w, h, *args, **kwargs): 
     # master should be a Canvas 
     self.frame_thickness = 5 
     Frame.__init__(
      self, 
      master, 
      *args, 
      borderwidth = self.frame_thickness, 
      cursor = 'fleur', 
      **kwargs 
     ) 
     self.canvas = master 
     self.resize_state = None 
     self.bind('<Button-1>', self.mousedown) 
     self.bind('<B1-Motion>', self.mousemove) 
     self.bind('<ButtonRelease-1>', self.mouseup) 
     self.bind('<Destroy>', self.delete_item) 
     # add self to canvas 
     self.itemid = self.canvas.create_window(
      x, 
      y, 
      window=self, 
      anchor="nw", 
      width=w, 
      height=h 
     ) 
     self.save_callback = None 

    def canvas_coords(self): 
     return map(int, self.canvas.coords(self.itemid)) 

    def move(self, dx, dy): 
     # strictly, this is out of the range of RCF, 
     # but it helps with the law of demeter 
     self.canvas.move(self.itemid, dx, dy) 

    def mousedown(self, event): 
     window_width = self.winfo_width() 
     window_height = self.winfo_height() 
     self.resize_state = { 
      'start_coords': (event.x, event.y), 
      'last_coords': (event.x, event.y), 
      'left_edge': (0 <= event.x < self.frame_thickness), 
      'right_edge': (window_width - self.frame_thickness <= event.x < window_width), 
      'top_edge': (0 <= event.y < self.frame_thickness), 
      'bottom_edge': (window_height - self.frame_thickness <= event.y < window_height), 
     }    

    def mousemove(self, event): 
     if self.resize_state: 
      resize = self.resize_state # debug var 
      event_x = event.x 
      event_y = event.y 
      # distance of cursor from original position of window 
      delta = map(int, (event.x - self.resize_state['start_coords'][0], 
           event.y - self.resize_state['start_coords'][1])) 
      # load current pos, size 
      new_x, new_y = self.canvas_coords() 
      new_width = int(self.canvas.itemcget(self.itemid, 'width')) 
      new_height = int(self.canvas.itemcget(self.itemid, 'height')) 
      # handle x resize/move 
      if self.resize_state['left_edge']: 
       # must move pos and resize 
       new_x += delta[0] 
       new_width -= delta[0] 
      elif self.resize_state['right_edge']: 
       new_width += (event.x - self.resize_state['last_coords'][0]) 
      # handle y resize/move 
      if self.resize_state['top_edge']: 
       new_y += delta[1] 
       new_height -= delta[1] 
      elif self.resize_state['bottom_edge']: 
       new_height += (event.y - self.resize_state['last_coords'][1]) 
      # save new settings in item, not card yet 
      self.resize_state['last_coords'] = (event.x, event.y) 
      self.canvas.coords(self.itemid, new_x, new_y) 
      self.canvas.itemconfig(self.itemid, width=new_width, height=new_height) 

    def mouseup(self, event): 
     if self.resize_state: 
      self.resize_state = None 
      if self.save_callback: 
       self.save_callback() 

    def delete_item(self, event): 
     self.canvas.delete(self.itemid) 
0

你可以使用PanedWindow小部件,或者你的画布里面他们几个的组合。他们旨在做到这一点。尽管如此,让PanedWindow像画布中的“粘性”命令一样拉伸是一个未知数。

这就是我偶然发现这篇文章时所寻找的。

+0

http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/panedwindow.html – Sam 2014-01-19 07:56:39

+0

http://effbot.org/tkinterbook/panedwindow.htm – Sam 2014-01-19 07:57:23