Найти - Пользователи
Полная версия: Tkinter.Canvas, несколько create_window() и scrollregion.
Начало » GUI » Tkinter.Canvas, несколько create_window() и scrollregion.
1
antib
Пытаюсь сделать в одном поле канвас три набора виджетов, из трёх одновременно видим должен быть только один. Каждый набор должен иметь возможность скролла, scrollregion определяю по bbox(). И оно таки работает, но не полностью так как я предполагал.

Если все три окна изначально сделать скрытыми (state=HIDDEN, строка 41 и т.д.)и оставить их включение на волю юзера, то все работает, но если одно окно изначально не скрывать или снять коммент с вызова функции show1() , строка 80, то скролл работает так, будто scrollregion не задан, а bbox выводит координаты (0,0,1,1) т.е. все виджеты занимают 1 пиксель.

Почему оно так я не могу ни понять ни нагуглить.
ОС - Дебиан Ленни.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from Tkinter import *
app=Tk()
toolbar=Frame (app, relief=RIDGE)
field=Frame (app, relief=RIDGE)
canva=Canvas (field, width=1000, height=500, relief=SUNKEN)
sbar=Scrollbar(field, command=canva.yview, orient=VERTICAL, bg="gray", takefocus=0)
canva.configure(yscrollcommand=sbar.set)
def wheel (event): #привязка колеса мыши к "холсту"
if event.num == 5 or event.delta == -120:
canva.yview(SCROLL, 1, "units")
if event.num == 4 or event.delta == 120:
canva.yview(SCROLL, -1, "units")

app.bind ("<Button-4>",wheel)
app.bind ("<Button-5>",wheel)
app.bind ("MouseWheel", wheel)

canva.focus_set()
frame1=Frame(field)
frame2=Frame(field)
frame3=Frame(field)
list1=[]
list1=range(20)
for step in range (20):
list1[step]=Button (frame1, text="First "+str(step)+" of 20")
list1[step].pack (side=TOP)
list2=[]
list2=range(30)
for step in range(30):
list2[step]=Button (frame2, text="Second "+str(step)+" of 30")
list2[step].pack (side=TOP)
list3=[]
list3=range(40)
for step in range (40):
list3[step]=Button (frame3, text="Third "+str(step)+" of 40")
list3[step].pack (side=TOP)
window1=canva.create_window(0,0,window=frame1,anchor=NW)
canva.itemconfig (window1,state=HIDDEN)
window2=canva.create_window(0,0,window=frame2,anchor=NW)
canva.itemconfig (window2,state=HIDDEN)
window3=canva.create_window(0,0,window=frame3,anchor=NW)
canva.itemconfig (window3,state=HIDDEN)

field.pack(side=BOTTOM)
sbar.pack(side=RIGHT,fill=Y)
canva.pack(side=BOTTOM)
toolbar.pack(fill=X,side=TOP)

def show1(): #показать окно1, скрыть окна 2 и 3
canva.itemconfig (window1,state=NORMAL)
canva.itemconfig (window2,state=HIDDEN)
canva.itemconfig (window3,state=HIDDEN)
print canva.bbox(window1)
canva.configure(scrollregion=canva.bbox(window1))
def show2(): #показать окно2, скрыть окна 1 и 3
canva.itemconfig (window2,state=NORMAL)
canva.itemconfig (window1,state=HIDDEN)
canva.itemconfig (window3,state=HIDDEN)
print canva.bbox(window2)
canva.configure(scrollregion=canva.bbox(window2))

def show3(): #показать окно3, скрыть окна 2 и 1
canva.itemconfig (window3,state=NORMAL)
canva.itemconfig (window2,state=HIDDEN)
canva.itemconfig (window1,state=HIDDEN)
print canva.bbox(window3)
canva.configure(scrollregion=canva.bbox(window3))

but1=Button (toolbar, text="switch 1",command=show1)
but1.pack(side=LEFT)
but2=Button (toolbar, text="switch 2",command=show2)
but2.pack(side=LEFT)
but3=Button (toolbar, text="switch 3",command=show3)
but3.pack(side=LEFT)

def main():
#show1()
print "1 "+str(canva.bbox(window1))
print "2 "+str(canva.bbox(window2))
print "3 "+str(canva.bbox(window3))
app.mainloop()
return 0
if __name__ == '__main__': main()
antib
Интересно, моя проблема слишком лёгкая или слишком трудная? :)
Griffon
Банально нет времени попробовать. Попробуй выполнить функцию не сразу, а, скажем, через 100мс.
antib
Griffon
Банально нет времени попробовать. Попробуй выполнить функцию не сразу, а, скажем, через 100мс.
Так?
show1()
app.after(1000)
app.mainloop()
Разницы не наблюдается.

Мне непонятно, почему при переключении видимости/невидимости групп виджетов слетает скролл - одинаковым образом созданные группы могут или наползать на видежеты за пределами канвас или же прокручиваться не выходя за ее границы.

Видимо, я не понимаю чего-то в принципе отображения объектов canvas.create_window.
Я пытаюсь сделать переключение между несколькими “полями”, которые бы работали как вкладки. Каждая “вкладка” это окно, изначально все окна создаются так.
self.window=self.canva.create_window(0,0,window=self.frame)
self.canva.itemconfig(self.window,state=HIDDEN)
Потом я наполняю этот self.frame всякими виджетами и по ходу пьесы окна можно переключать меняя state одного на NORMAL. После переключения я переопределяю scrollregion скроллбара.
self.canva.configure(scrollregion=self.canva.bbox(self.window))
Если окна со скроллом создается вместе с прочими элементами (напр. тулбары) то переключение между ними происходит нормально. Если окно перенаполняется виджетами по новой, после того как другие уже были созданы, то при скролле его элементы проплывают над тулбарами, если их размер больше канвас. Если это разме меньше, то они скролятся (хотя необходимости в этом нет), но остаются в пределах канвас.

Что я упускаю из виду?
Griffon
Изменил
def print_bbox():
show2()
print "1 "+str(canva.bbox(window1))
print "2 "+str(canva.bbox(window2))
print "3 "+str(canva.bbox(window3))
def main():
app.after(100, print_bbox)
app.mainloop()
return 0
Добавил
toolbar.pack(fill=X,side=TOP)
field.pack()
sbar.pack(side=RIGHT,fill=Y)
canva.pack(side=BOTTOM)

Frame(app, relief=GROOVE, bg="red", height=50).pack(side=BOTTOM, fill=BOTH)

....

def show3(): #показать окно3, скрыть окна 2 и 1
canva.itemconfig (window3,state=NORMAL)
canva.itemconfig (window2,state=HIDDEN)
canva.itemconfig (window1,state=HIDDEN)
list3.append(Button (frame3, text="Third %s of %s" % (len(list3), len(list3)+1)))
list3[-1].pack (side=TOP)
canva.update()
print canva.bbox(window3)
canva.configure(scrollregion=canva.bbox(window3))
Питон 2.7.1. Всё работает как ожидается. Никаких проблем.
antib
Заработало, спасибо.
Буду думать.
    list3.append(Button (frame3, text="Third %s of %s" % (len(list3), len(list3)+1)))
list3[-1].pack (side=TOP)
canva.update()
Вероятно где-то тут закопан ответ на вопрос в конце моего предыдущего поста.

upd:
Время создания window влияет. Если создать window и соотв. ей frame в начале программы, а наполнение этих фреймов оставить на потом, то скролл работает правильно. Если window и frame создаются в процессе, то всё выглядит печальнее.
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