2012-01-04 7 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

+0

http://effbot.org/tkinterbook/panedwindow.htm – Sam

관련 문제