Найти - Пользователи
Полная версия: растягивание фреймов в python3 / tkinter
Начало » GUI » растягивание фреймов в python3 / tkinter
1
zinaida
Всем доброго времени))

У меня появилась задачка: есть набор фреймов, организованных grid'ами в виде таблицы. Необходимо, чтобы они изменяли размер, когда пользователь их растягивает по горизонтали/вертикали с помощью мышки. Я искала подобный функционал в tkinter, не нашла, в результате сделала под свою задачку следующее:

Код рабочий, но хотелось бы узнать, можно подобрать более элегантное решение?
Как грамотно ресайзить фреймы с помощью мыши? Если в tkinter уже есть такой функционал, подскажите, пожалуйста, ссылку.

    def AddResizer(self, obj, targetWin, side, minsize, col_row_num):
        '''	
        obj - фрейм, в который помещается полоска, за которую его растягиваем
        targetWin - ряд/колонка таблицы, которую растягиваем
        side - положение полоски  (BOTTOM, TOP, LEFT, RIGHT)
        minsize - начальное значение минимальной ширины/высоты targetWin
        col_row_num - номер столбца/колонки
        '''
        # если растягиваем ячейку/ряд по вертикали
        if side in (BOTTOM, TOP):
            resFrame = Frame(obj, background=self.CFG['resizer_color'],  height=self.CFG['resizer_size'])
            resFrame.pack( side= side, fill="x")
            targetWin.rowconfigure(col_row_num, minsize=minsize)
            ishor = False
        else: # LEFT, RIGHT
            resFrame = Frame(obj, background=self.CFG['resizer_color'],  width=self.CFG['resizer_size'])
            resFrame.pack( side = side, fill="y")
            targetWin.columnconfigure(col_row_num, minsize=minsize)
            ishor = True
        obj.xyminsize = minsize
        resFrame.bind('<ButtonPress-1>', lambda e, o=obj, i=ishor:self.StartMove(e, o, i))
        resFrame.bind('<ButtonRelease-1>', lambda e, o=obj, i=ishor:self.StopMove(e, o, i))
        resFrame.bind('<B1-Motion>', lambda e, o=obj, i=ishor, tw=targetWin:self.OnMotion(e, o, i, tw))
    def StartMove(self, event, obj, ishor):
        obj.xyevent = event.x if ishor else event.y
        obj.xyroot = event.x_root if ishor else event.y_root
    def StopMove(self, event, obj, ishor):
        obj.xyevent = None
        obj.xyminsize += (event.x_root - obj.xyroot) if ishor else (event.y_root - obj.xyroot)
    def OnMotion(self,event, obj, ishor, targetWin):
        if ishor:
        	targetWin.columnconfigure(0, minsize=(obj.xyminsize + event.x_root - obj.xyroot))
        else:
        	targetWin.rowconfigure(0, minsize=(obj.xyminsize + event.y_root - obj.xyroot))

Спасибо заранее!
4kpt_III
У Вас есть две рамки на одном листе. И Вы тянете линию между ними. Что должно происходить?
Что Вы вообще имеет ввиду под изменением размера пользователем? Они их тянет за края как обычные окна? Я верно понял?
zinaida
4kpt_III, спасибо за ответ
>> Что Вы вообще имеет ввиду под изменением размера пользователем? Они их тянет за края как обычные окна? Я верно понял?
Да, вы верно поняли. При этом пользователь может растягивать либо по горизонтали, либо по вертикали

>> У Вас есть две рамки на одном листе. И Вы тянете линию между ними. Что должно происходить? - размер одной рамки уменьшается, другой увеличивается, в зависимости от того ,куда тянуть

На примере такая полоса (фиолетового цвета) между зеленым и синим фреймом. Если за нее тянуть, уменьшается размер зеленого и увеличивается размер синего и наоборот
4kpt_III
zinaida
4kpt_III, спасибо за ответ

Пока еще не за что.

Такой механизм уже есть. Это PanedWindow.

Ваш код проинспектировать?

zinaida
>> Такой механизм уже есть. Это PanedWindow.
Спасибо, видимо, я как-то прошла мимо него, когда искала. Прочитала - то, что нужно

>> Код проинспектировать?
Была бы вам благодарна, если не сильно отнимет у вас время
4kpt_III
Вы девушка. На девушек у меня всегда найдется время

По коду.

1. Вам нужно почитать про PEP8. Это стандарт оформление кода. Он есть переведенный на русский, поэтому проблем возникнуть не должно. Эта штука сразу режет глаза. Очень.

2. from Tkinter import * Так делать нельзя никогда.

3. Есть механизм описания докстрингов. У Вас не совсем то и не совсем так

4. Раз Вы уже делаете такое окно, то зачем в нем создавать Frame, который потом планируете использовать для хранения виджетов. Не легче ли наследовать сразу от Frame и не мучить себя контролем за его свойствами? ООП слегка не так в Tkinter используется… Хотя дело Ваше.

5. Код. Много лишнего. Можно конкретно упростить. Отличие ведь маленькие такие

if side in (BOTTOM, TOP):
            resFrame = Frame(obj, background=self.CFG['resizer_color'],  height=self.CFG['resizer_size'])
            resFrame.pack( side= side, fill="x")
            targetWin.rowconfigure(col_row_num, minsize=minsize)
            ishor = False
else: # LEFT, RIGHT
            resFrame = Frame(obj, background=self.CFG['resizer_color'],  width=self.CFG['resizer_size'])
            resFrame.pack( side = side, fill="y")
            targetWin.columnconfigure(col_row_num, minsize=minsize)
            ishor = True

6. Две функции выполняют одно и то же.

resFrame.bind('<ButtonPress-1>', lambda e, o=obj, i=ishor:self.StartMove(e, o, i))
resFrame.bind('<ButtonRelease-1>', lambda e, o=obj, i=ishor:self.StopMove(e, o, i))

В этом случае можно использовать виртуальные события virtual events.

P.S. Ну и если наследовать все же от Frame часть методов уйдет за ненадобностью. Плюс механизм станет автономным.
4kpt_III
Кстати. Забыл сказать. Отличная документация Вот тут вот.
zinaida
4kpt_III, большое спасибо, что все так подробно расписали!
Я на питоне начала писать не так давно, и ваши замечания мне очень пригодятся

P.S: за доку отдельное большущее спасибо!
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB