Форум русскоязычного сообщества Ubuntu


Хотите сделать посильный вклад в развитие Ubuntu и русскоязычного сообщества?
Помогите нам с документацией!

Автор Тема: Большая сетка в Tkinter.  (Прочитано 2439 раз)

0 Пользователей и 1 Гость просматривают эту тему.

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Большая сетка в Tkinter.
« : 08 Июня 2012, 21:57:24 »
Здравствуйте!
Сразу скажу, чтобы не было вопросов, что хочу запрограммировать игру "Жизнь" (кто не знает, гуглите, очень много информации).
Поскольку знаю (немного) только Питон, то и пишу на нем. Без гуя я уже сделал. Но это тут точно не дело, надо это нарисовать. Гуи я никогда не делал. Посмотрев немного литературу, выбрал Tkinter, потому что он очень простой, видимо, и должен вполне удовлетворять моим задачам.
Я решил, что сделаю сетку из кнопок, по нажатию перед началом игры записывать координаты в список начальных точек (по крайней мере, так это реализовано сейчас без гуя, можно будет переделать).
Но вознилка неожиданная проблема - как сделать 100х100 кнопок? Казалось бы, такой цикл должен решить проблемы:
b = Button(root, text="")
for x in range(dimension):
    for y in range(dimension):
        b.place(relx = x/dimension, rely = y/dimension)
Ошибок не выдает, но рисует но кнопку рисует только в верхнем левом углу, только одну. Почему?
И как лучше это сделать?

(Говорить, что это надо делать на Qt, GTK или WxWidgets не надо, я и так знаю, что, по крайней мере первые два, более перспективны и круты. Но. мне кажется, мне нужно что-то проще.)
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #1 : 08 Июня 2012, 22:06:36 »
Ты создал одну кнопку, а в цикле пытыешься ее вставлять/перемещать.
Тебе нужно каждый раз создавать новую кнопку, примерно так:

for x in range(dimension):
    for y in range(dimension):
        b = Button(root, text="")
        b.place(relx = x/dimension, rely = y/dimension)

Синтаксис Tkinter не знаю, но по логике так.
« Последнее редактирование: 08 Июня 2012, 22:12:28 от vasiliyVV »

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #2 : 08 Июня 2012, 22:10:37 »
10, для начала.

Заменил place на grid и заработало, хотя раньше это пробовал...
Попробовал 100, но кнопки такие большие, что все это дело на экран не помещается - можно ли размер кнопки как-то сделать меньше 1? На 0.5 ругается. А еще при этом tkinter почти сдох - очень долго рисовал такую сетку( Что делать?

Пользователь решил продолжить мысль 08 Июня 2012, 22:14:57:
Ты создал одну кнопку, а в цикле пытыешься ее вставлять/перемещать.
Тебе нужно каждый раз создавать новую кнопку, примерно так:

for x in range(dimension):
    for y in range(dimension):
        b = Button(root, text="")
        b.place(relx = x/dimension, rely = y/dimension)

Синтаксис Tkinter не знаю, но по логике так.
Я это пробовал, не помогло с place, а с grid помогает. Все это для меня как-то немного загадочно.
« Последнее редактирование: 08 Июня 2012, 22:14:57 от Phlya »
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #3 : 08 Июня 2012, 22:16:02 »
Исправил коммент, извини. Кстати в цикле как я написал сразу советую наполнять список указателями/именами кнопок,а то ведь к ним потом еще и обращаться надо.

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #4 : 08 Июня 2012, 22:18:17 »
Да, а как это сделать? Каким образом в цикле сделать, чтобы у каждой кнопки было свое имя?
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #5 : 08 Июня 2012, 22:28:21 »
Я вообще на pyGTK пишу, но логика в общем похожая. Объясню попроще:
В цикле создается каждый раз новый объект кнопка с именем b.
Имя каждый раз делать новое геморно, однако если ты создал кнопки с одинаковыми именами у них все разные указатели будут.
Для проверки после создания кнопки вставь print b. Поэтому есть вариант перед циклом создать список lst = [], а в цикле добавлять в него элементы lst.append(b).
после завершения циклов print lst[], там все имена кнопок, ну а дальше обращайся к элементам списка.

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #6 : 08 Июня 2012, 22:40:58 »
Я вообще на pyGTK пишу, но логика в общем похожая. Объясню попроще:
В цикле создается каждый раз новый объект кнопка с именем b.
Имя каждый раз делать новое геморно, однако если ты создал кнопки с одинаковыми именами у них все разные указатели будут.
Для проверки после создания кнопки вставь print b. Поэтому есть вариант перед циклом создать список lst = [], а в цикле добавлять в него элементы lst.append(b).
после завершения циклов print lst[], там все имена кнопок, ну а дальше обращайся к элементам списка.
Точно, спасибо!

Правда, что-то не получается сделать, чтобы работало...

lst = []
for x in range(dimension):
    for y in range(dimension):
        b = Button(root, text="", bg = 'blue')
        b.grid(column = x, row = dimension - y)
        lst.append((b, (x, y)))
for button in lst:
    button[0].bind('<Button-1>', starting_points.append(button[1]))
root.mainloop()

print starting_pointsвыдает:
[(0, 0), (0, 1), (0, 2), (0, 3), (0, 4), (0, 5), (0, 6), (0, 7), (0, 8), (0, 9), (1, 0), (1, 1), (1, 2), (1, 3), (1, 4), (1, 5), (1, 6), (1, 7), (1, 8), (1, 9), (2, 0), (2, 1), (2, 2), (2, 3), (2, 4), (2, 5), (2, 6), (2, 7), (2, 8), (2, 9), (3, 0), (3, 1), (3, 2), (3, 3), (3, 4), (3, 5), (3, 6), (3, 7), (3, 8), (3, 9), (4, 0), (4, 1), (4, 2), (4, 3), (4, 4), (4, 5), (4, 6), (4, 7), (4, 8), (4, 9), (5, 0), (5, 1), (5, 2), (5, 3), (5, 4), (5, 5), (5, 6), (5, 7), (5, 8), (5, 9), (6, 0), (6, 1), (6, 2), (6, 3), (6, 4), (6, 5), (6, 6), (6, 7), (6, 8), (6, 9), (7, 0), (7, 1), (7, 2), (7, 3), (7, 4), (7, 5), (7, 6), (7, 7), (7, 8), (7, 9), (8, 0), (8, 1), (8, 2), (8, 3), (8, 4), (8, 5), (8, 6), (8, 7), (8, 8), (8, 9), (9, 0), (9, 1), (9, 2), (9, 3), (9, 4), (9, 5), (9, 6), (9, 7), (9, 8), (9, 9)]
Почему, если нажал не на все кнопки?
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #7 : 08 Июня 2012, 22:49:35 »
Что имеешь ввиду этой записью?
button[0].bind('<Button-1>',starting_points.append(button[1]))

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #8 : 08 Июня 2012, 23:18:32 »
Что имеешь ввиду этой записью?
button[0].bind('<Button-1>',starting_points.append(button[1]))

Посмотрите, каким образом я записываю указатели - совместно с координатами. Первый пункт в записи - указатель, второй - (x, y).
Соответстенно, я связываю указатель с нажатием на кнопку мышкой, что должно вызвать запись координат кнопки в starting_points.
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #9 : 09 Июня 2012, 09:02:48 »
А зачем тебе создавать еще один список с координатами?
Если нужны координаты при клике на кнопке, то сделай еще проще:

# -*- coding: utf-8 -*-

import Tkinter
from Tkinter import *
root = Tk()

def clicked(event):
    print u'Кнопка: ', event.widget, u'Координаты: ', event.x, event.y

   
dimension = 10

for x in range(dimension):
    for y in range(dimension):
        b = Button(root, text="", bg = 'blue')
        b.grid(column = x, row = dimension - y)
        b.bind('<Button-1>', clicked)
           
root.mainloop()

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

Поправь меня если я ошибаюсь или объясни твое видение вопроса.

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #10 : 09 Июня 2012, 09:28:15 »
Перед игрой ведь надо расставить начальную фигуру, которая потом будет преобразовываться.

Да, я перешел уже примерно на такое:

def action(x, y):
    if area[y][x] == 0:
        area[y][x] = 1
    else:
        area[y][x] = 0
       
for x in range(len(area)):
    for y in range(len(area[x])):
        b = Button(frame1, text="", bg = 'blue', command = action(x, y))
        b.grid(column = x, row = dimension - y)
        lst.append((b, (x, y)))

Но почему-то, когда этот код есть в программе, в начале все точки на поле становятся закрашенными (с 1)... Если его закомментировать, такого нет.
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #11 : 09 Июня 2012, 10:10:48 »
Покажи весь код.

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #12 : 09 Июня 2012, 10:17:45 »
from numpy import array
from Tkinter import *

dimension = 100
   
root = Tk() # окно
root.title('Игра "Жизнь"')
frame1=Frame(root,width=1000,height=1000,bg='white',bd=1)
frame2=Frame(root, width=100,bg='gray',bd=1)
area = array([[0]*dimension]*dimension)

lst = []

def action(x, y):
    if area[y][x] == 0:
        area[y][x] = 1
    else:
        area[y][x] = 0
       
for x in range(len(area)):
    for y in range(len(area[x])):
        b = Button(frame1, text="", bg = 'blue', command = action(x, y))
        b.grid(column = x, row = dimension - y)
        lst.append((b, (x, y)))
frame1.pack(side='left')
frame2.pack(side='right')
   
def game(area):
    born = []
    die = []
    for y in range(1, len(area)-1):
        for x in range(1, len(area[y])-1):
            if area[y][x] == 1:
                if not survive(x, y):
                    die.append((x, y))
            elif area[y][x] == 0:
                if appear(x, y):
                    born.append((x, y))
    for i in born:
        area[i[1]][i[0]] = 1
    for i in die:
        area[i[1]][i[0]] = 0
           
def surrounding(x, y):
    horiz = area[y][x-1] + area[y][x+1]
    vert =  area[y-1][x] + area[y+1][x]
    diag = area[y-1][x-1] + area[y-1][x+1] + area[y+1][x+1] + area[y+1][x-1]
    return vert + horiz + diag

def survive(x, y):
    if surrounding(x, y) <= 1:
        return False
    elif surrounding(x, y) >= 4:
        return False
    else:
        return True

def appear(x, y):
    if surrounding(x, y) == 3:
        return True
    else:
        return False
       
#for n in range(10):
#    for i in range(len(area)):
#        print i, area[i]
#    print '   0 1 2 3 4 5 6 7 8 9'
#    print '-'*23
#    game(area)
root.mainloop()

print area
Ubuntu 14.04 (Unity), MSI GE40

Оффлайн vasiliyVV

  • Новичок
  • *
  • Сообщений: 47
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #13 : 09 Июня 2012, 10:39:19 »
Ну и где ты цвет кнопок меняешь?

Оффлайн Phlya

  • Автор темы
  • Старожил
  • *
  • Сообщений: 2219
  • Фля, Цыганский барон, Винни Пух
    • Просмотр профиля
Re: Большая сетка в Tkinter.
« Ответ #14 : 09 Июня 2012, 10:58:07 »
Цвет я там еще не вставил, сначала я хотел, чтобы это изменение записывалось в array.
Сейчас я добавил изменение цвета и оказалось, что они сразу рисуются "нажатые" (с измененным цветом и поменявшие соответвующие значения в array'у), а при нажатии ничего не происходит.
Ubuntu 14.04 (Unity), MSI GE40

 

Страница сгенерирована за 0.021 секунд. Запросов: 21.