2016-04-06 2 views
2

Вот мой код для очень простого графического интерфейса:Resizeable прокруткой холст с Tkinter

from Tkinter import * 

class my_gui(Frame): 

    def __init__(self): 
     # main tk object 
     self.root = Tk() 

     # init Frame 
     Frame.__init__(self, self.root) 

     # create frame (gray window) 
     self.frame=Frame(self.root,width=100,height=100) 
     self.frame.grid(row=0,column=0) 

     self.__add_scroll_bars() 

     self.__create_canvas() 

     self.__add_plot() 

    def __create_canvas(self): 
     # create white area in the window for plotting 
     # width and height are only the visible size of the white area, scrollregion is the area the user can see by scrolling 
     self.canvas = Canvas(self.frame,bg='#FFFFFF',width=300,height=300,scrollregion=(0,0,500,500)) 

     # with this command the window is filled with the canvas 
     self.canvas.pack(side=LEFT,expand=True,fill=BOTH) 

     # position and size of the canvas is used for configuration of the scroll bars 
     self.canvas.config(xscrollcommand=self.hbar.set, yscrollcommand=self.vbar.set) 

     # add command to the scroll bars to scroll the canvas 
     self.hbar.config(command = self.canvas.xview) 
     self.vbar.config(command = self.canvas.yview) 

    def __add_scroll_bars(self): 
     # add scroll bars 
     self.hbar=Scrollbar(self.frame,orient=HORIZONTAL) 
     self.hbar.pack(side=BOTTOM,fill=X) 
     self.vbar=Scrollbar(self.frame,orient=VERTICAL) 
     self.vbar.pack(side=RIGHT,fill=Y) 

    def __add_plot(self): 
     # create a rectangle 
     self.canvas.create_polygon(10, 10, 10, 150, 200, 150, 200, 10, fill="gray", outline="black") 

    def mainLoop(self): 
     # This function starts an endlos running thread through the gui 
     self.root.mainloop() 

    def __quit(self): 
     # close everything 
     self.root.quit() 

    def mainLoop(self): 
     # This function starts an endlos running thread through the gui 
     self.root.mainloop() 

# init gui 
my_gui = my_gui() 
# execute gui 
my_gui.mainLoop() 

У меня есть два вопроса:

1) Я хочу, если изменить размер графического интерфейса, который затем полосы прокрутки всегда Конец гии и я изменяю размер холста.

2) Если я изменяю размер графического интерфейса и холста, то размер прямоугольника в холсте должен быть изменен (например, если новый размер gui и canvas в четыре раза превышает старый размер, тогда новый размер прямоугольника twize старый размер).

Я ищу решение для первой проблемы и для второй проблемы отдельно.

Спасибо за помощь.

ответ

0

Это работает очень хорошо, чтобы получить то, что я хочу, с минимальным размером прокручиваемого холста. Но все еще есть ошибка, когда gui был увеличен, и когда кажется, что невозможно прокручивать, есть возможность щелкнуть левой или верхней стрелкой полос прокрутки и, таким образом, прокрутить холст, что не возможно.

from Tkinter import * 


class ScrollableFrame(Frame): 
    def __init__(self, parent, minimal_canvas_size, *args, **kw): 
     ''' 
     Constructor 
     ''' 

     Frame.__init__(self, parent, *args, **kw) 

     self.minimal_canvas_size = minimal_canvas_size 

     # create a vertical scrollbar 
     vscrollbar = Scrollbar(self, orient = VERTICAL) 
     vscrollbar.pack(fill = Y, side = RIGHT, expand = FALSE) 

     # create a horizontal scrollbar 
     hscrollbar = Scrollbar(self, orient = HORIZONTAL) 
     hscrollbar.pack(fill = X, side = BOTTOM, expand = FALSE) 

     #Create a canvas object and associate the scrollbars with it 
     self.canvas = Canvas(self, bd = 0, highlightthickness = 0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) 
     self.canvas.pack(side = LEFT, fill = BOTH, expand = TRUE) 

     #Associate scrollbars with canvas view 
     vscrollbar.config(command = self.canvas.yview) 
     hscrollbar.config(command = self.canvas.xview) 


     # set the view to 0,0 at initialization 

     self.canvas.xview_moveto(0) 
     self.canvas.yview_moveto(0) 

     self.canvas.config(scrollregion='0 0 %s %s' % self.minimal_canvas_size) 

     # create an interior frame to be created inside the canvas 

     self.interior = interior = Frame(self.canvas) 
     interior_id = self.canvas.create_window(0, 0, window=interior, 
       anchor=NW) 

     # track changes to the canvas and frame width and sync them, 
     # also updating the scrollbar 

     def _configure_interior(event): 
      # update the scrollbars to match the size of the inner frame 
      size = (max(interior.winfo_reqwidth(), self.minimal_canvas_size[0]), max(interior.winfo_reqheight(), self.minimal_canvas_size[1])) 
      self.canvas.config(scrollregion='0 0 %s %s' % size) 
      if interior.winfo_reqwidth() != self.canvas.winfo_width(): 
       # update the canvas's width to fit the inner frame 
       self.canvas.config(width = interior.winfo_reqwidth()) 
     interior.bind('<Configure>', _configure_interior) 


class my_gui(Frame): 

    def __init__(self): 
     # main tk object 
     self.root = Tk() 

     # init Frame 
     Frame.__init__(self, self.root) 

     minimal_canvas_size = (500, 500) 

     # create frame (gray window) 

     self.frame = ScrollableFrame(self.root, minimal_canvas_size) 
     self.frame.pack(fill=BOTH, expand=YES) 

     self.__add_plot() 

    def __add_plot(self): 
     # create a rectangle 
     self.frame.canvas.create_polygon(10, 10, 10, 150, 200, 150, 200, 10, fill="gray", outline="black") 

    def mainLoop(self): 
     # This function starts an endlos running thread through the gui 
     self.root.mainloop() 

    def __quit(self): 
     # close everything 
     self.root.quit() 


# init gui 
my_gui = my_gui() 
# execute gui 
my_gui.mainLoop() 
0

Вы можете использовать этот следующий пример или интегрировать его в свой класс. Вы можете создать такой кадр, позвонив.

self.frame = ScrollableFrame(self.root) 
self.frame.pack(fill=BOTH, expand=YES) 

Создать класс, как это для вашего кадра:

from Tkinter import *  
class ScrollableFrame(Frame): 
''' 
Creates a scrollable frame 
''' 

    def __init__(self, parent, *args, **kw): 
    ''' 
    Constructor 
    ''' 

    Frame.__init__(self, parent, *args, **kw) 

    # create a vertical scrollbar 
    vscrollbar = Scrollbar(self, orient = VERTICAL) 
    vscrollbar.pack(fill = Y, side = RIGHT, expand = FALSE) 

    # create a horizontal scrollbar 
    hscrollbar = Scrollbar(self, orient = HORIZONTAL) 
    hscrollbar.pack(fill = X, side = BOTTOM, expand = FALSE) 

    #Create a canvas object and associate the scrollbars with it 
    canvas = Canvas(self, bd = 0, highlightthickness = 0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) 
    canvas.pack(side = LEFT, fill = BOTH, expand = TRUE) 

    #Associate scrollbars with canvas view 
    vscrollbar.config(command = canvas.yview) 
    hscrollbar.config(command = canvas.xview) 


    # set the view to 0,0 at initialization 

    canvas.xview_moveto(0) 
    canvas.yview_moveto(0) 

    # create an interior frame to be created inside the canvas 

    self.interior = interior = Frame(canvas) 
    interior_id = canvas.create_window(0, 0, window=interior, 
      anchor=NW) 

    # track changes to the canvas and frame width and sync them, 
    # also updating the scrollbar 

    def _configure_interior(event): 
     # update the scrollbars to match the size of the inner frame 
     size = (interior.winfo_reqwidth(), interior.winfo_reqheight()) 
     canvas.config(scrollregion='0 0 %s %s' % size) 
     if interior.winfo_reqwidth() != canvas.winfo_width(): 
      # update the canvas's width to fit the inner frame 
      canvas.config(width = interior.winfo_reqwidth()) 
    interior.bind('<Configure>', _configure_interior) 

Вы можете использовать это, чтобы получить результат, который вы хотите. Горизонтальная и вертикальная прокрутка включены для этого кадра, а позиции полосы прокрутки можно установить с помощью поля «сторона». Для второй части вашего вопроса вы могли бы еще глубже разъяснить.

Ссылка: ответ Gonzo в Python Tkinter scrollbar for frame

+0

У вас есть простой пример, где этот класс ScrollableFrame используется, например, с холстом? Я действительно не понимаю, как я могу интегрировать этот класс в свой пример. Я вижу, что много кода такое же, как и полосы прокрутки, и я вижу, что трюк для изменяемых размеров полос прокрутки, похоже, является функцией _configure_interior и функцией create_window, но я действительно не понимаю, почему. – Thaddy

+0

В этом примере создается холст с горизонтальными и вертикальными полосами прокрутки, но из того, что я могу сказать, ни один слайдер никогда не появляется, даже если размер кадра превышает размер холста, на который он помещен. https://pastebin.com/J7d0ChzX – ochawkeye

1

Вы можете использовать следующий способ интегрировать свою структуру в классе графического интерфейса:

from Tkinter import * 


class ScrollableFrame(Frame): 
    def __init__(self, parent, *args, **kw): 
     ''' 
     Constructor 
     ''' 

     Frame.__init__(self, parent, *args, **kw) 

     # create a vertical scrollbar 
     vscrollbar = Scrollbar(self, orient = VERTICAL) 
     vscrollbar.pack(fill = Y, side = RIGHT, expand = FALSE) 

     # create a horizontal scrollbar 
     hscrollbar = Scrollbar(self, orient = HORIZONTAL) 
     hscrollbar.pack(fill = X, side = BOTTOM, expand = FALSE) 

     #Create a canvas object and associate the scrollbars with it 
     self.canvas = Canvas(self, bd = 0, highlightthickness = 0, yscrollcommand = vscrollbar.set, xscrollcommand = hscrollbar.set) 
     self.canvas.pack(side = LEFT, fill = BOTH, expand = TRUE) 

     #Associate scrollbars with canvas view 
     vscrollbar.config(command = self.canvas.yview) 
     hscrollbar.config(command = self.canvas.xview) 


     # set the view to 0,0 at initialization 

     self.canvas.xview_moveto(0) 
     self.canvas.yview_moveto(0) 

     # create an interior frame to be created inside the canvas 

     self.interior = interior = Frame(self.canvas) 
     interior_id = self.canvas.create_window(0, 0, window=interior, 
       anchor=NW) 

     # track changes to the canvas and frame width and sync them, 
     # also updating the scrollbar 

     def _configure_interior(event): 
      # update the scrollbars to match the size of the inner frame 
      size = (interior.winfo_reqwidth(), interior.winfo_reqheight()) 
      self.canvas.config(scrollregion='0 0 %s %s' % size) 
      if interior.winfo_reqwidth() != self.canvas.winfo_width(): 
       # update the canvas's width to fit the inner frame 
       self.canvas.config(width = interior.winfo_reqwidth()) 
     interior.bind('<Configure>', _configure_interior) 


class my_gui(Frame): 

    def __init__(self): 
     # main tk object 
     self.root = Tk() 

     # init Frame 
     Frame.__init__(self, self.root) 

     # create frame (gray window) 

     self.frame = ScrollableFrame(self.root) 
     self.frame.pack(fill=BOTH, expand=YES) 


     #self.__add_scroll_bars() 

     #self.__create_canvas() 

     self.__add_plot() 

    def __add_plot(self): 
     # create a rectangle 
     self.frame.canvas.create_polygon(10, 10, 10, 150, 200, 150, 200, 10, fill="gray", outline="black") 

    def mainLoop(self): 
     # This function starts an endlos running thread through the gui 
     self.root.mainloop() 

    def __quit(self): 
     # close everything 
     self.root.quit() 


# init gui 
my_gui = my_gui() 
# execute gui 
my_gui.mainLoop() 

Это должно существенно решить первую проблему. Что касается второй проблемы, вам нужно создать функцию для повторного рендеринга холста при каждом изменении размера. Аналогично функции _configure_interior.

+0

Hallo, для первого он работает, но в этом примере полоса прокрутки не имеет смысла, нет ничего, чтобы прокручивать, холст всегда точно такого же размера, как полосы прокрутки, я могу никогда не прокручивайте. Я хотел прокрутить, когда GUI достаточно мал (возможно, когда gui меньше 500 раз 500, тогда я хочу прокрутить этот размер ..Для второго, когда вы делаете gui больше, полоса прокрутки кажется такой, что вы не можете прокручивать. Но когда вы нажимаете на левую стрелку нижней полосы прокрутки, вы можете видеть, что прямоугольник перемещается вправо. Это ошибка? – Thaddy

+0

В некоторых случаях он работает, чтобы заменить строку «size = (interior.winfo_reqwidth(), inner.winfo_reqheight())» на «size = (max (500, interior.winfo_reqwidth()), max (500, internal.winfo_reqheight())) « , чтобы получить в большинстве случаев прокручиваемый холст размером 500 раз 500. Но функция _configure_interior, кажется, не вызывается в каждом случае, когда размер gui был изменен. – Thaddy

+0

Я не встречал ошибку, когда я ее выполнил. Что касается полос прокрутки, которые не имеют смысла, это потому, что у вас просто простой холст с полигоном в нем. Вы можете «упаковать» другие элементы (например, метки, флажки, кнопки и т. Д.), Чтобы увидеть, что полосы прокрутки будут активированы, когда размер окна будет меньше требуемого размера, чтобы отобразить все элементы. – nihal111

Смежные вопросы