如何使按钮在Tkinter中随机移动

时间:2017-11-30 10:03:39

标签: python tkinter

这是我正在制作的游戏的一部分。在其中,玩家必须点击标有“鹿”的按钮。而不是' doe'尽可能快:

import tkinter
import time
import random

from __main__ import *

level = 2
name = "Oliver"
stop = False
score = 0
global level, name, score
if level >= 10:
    level = 10 + level/10
difficulty = level * 2
bonus = 1

def shot(animal):
    root.destroy()
    time.sleep(1)
    if animal == "Doe":
        print("You shot a doe!"),time.sleep(1)
        print("The rest of the herd have trampled you to death"),time.sleep(1.2)
        print("Oh deer!")
    elif animal == "Deer":
        print("You shot the deer!")


time.sleep(1), print("***Deer Shooting***\n\nShoot the deer, not the does"), time.sleep(2.5)

print("Ready"),time.sleep(1),print("Steady"),time.sleep(1),print("Go!\n\n\n")

root = tkinter.Tk()

NumOfDoe = difficulty

for i in range(0, NumOfDoe):
    tkinter.Button(root, text = "Doe", command = lambda: shot("Doe")).pack()

tkinter.Button(root, text = "Deer", command = lambda: shot("Deer")).pack()

root.mainloop()

当它运行时,Tkinter窗口看起来有点无聊,因为所有按钮都排成一行

我知道' .place()'功能,但我如何在这里使用它来随机分散按钮并使它们随意移动?

谢谢

2 个答案:

答案 0 :(得分:1)

首先,正如@furas所提到的那样sleep is a wrong option,所以请记住在tkinter中使用after来延迟时间!

另外,请记住构建代码(link#1link#2)并且不要尝试在一行上放置不必要的多个语句。

琐事

对于可移动按钮,最好使用Canvas小部件而不是布局管理器(除非您的真正目标是可传送的按钮)。连续两次button随机place很容易,但如果你想模拟移动,你不需要一组新的随机坐标,但旧坐标,随机距离(偏移)随机方向

可以使用button实现这个想法,但有甜蜜的place方法,可以为您完成所有这些。

您只需将每个canvas放置在object IDmove(同时它也会让您import tkinter as tk import random class App(tk.Tk): def __init__(self, difficulty, *args, **kwargs): super().__init__(*args, **kwargs) self.difficulty = difficulty self.play_area = tk.Canvas(self, background='bisque') self.play_area.pack(expand=True, fill='both') self.animals = self.generate_animals() self.play() def play(self): # move all animals continuously (each 100 ms) self.move_animals() self.after(100, self.play) def generate_animals(self): # generate all button-like animals animals = [Animal('deer', self, text='DEER')] for _ in range(self.difficulty * 2): animals.append(Animal('doe', self, text='DOE')) return animals def move_animals(self): # move all animals for animal in self.animals: animal.move() class Animal(tk.Button): def __init__(self, animal_type, *args, **kwargs): super().__init__(*args, **kwargs) self.animal_type = animal_type self.base_speed = self.master.difficulty self.play_area = self.master.play_area self.move_sets = ['n', 's', 'w', 'e'] # place button on canvas (it's possible to randomize starting locations) self.id = self.play_area.create_window(0, 0, window=self) self.configure(command=self.kill) def move(self): # move animal # get random speed and direction distance = random.randint(0, 15) * self.base_speed direction = random.choice(self.move_sets) if direction in self.move_sets[:2]: if direction == 'n': distance *= -1 # to prevent case when an animal leaves play area if 0 <= self.play_area.coords(self.id)[1] + distance <= self.play_area.winfo_height(): self.play_area.move(self.id, 0, distance) else: if direction == 'w': distance *= -1 # to prevent case when an animal leaves play area if 0 <= self.play_area.coords(self.id)[0] + distance <= self.play_area.winfo_width(): self.play_area.move(self.id, distance, 0) def kill(self): if self.animal_type == 'deer': print('You shot the deer!') else: print('You shot a doe!') print('The rest of the herd have trampled you to death') print('Oh deer!') self.master.destroy() app = App(difficulty=2) app.mainloop() 在画布上控制您的小部件)并模拟大规模移动!

实施例

after

正如你所看到的 - 它以某种方式起作用。

然而,改善和调整事物的空间很大。例如,一个更顺畅的&#34;运动。虽然它取决于我们如何进一步移动物体,但它还取决于create_window,这对于人类物种来说是24 fps(frame rate)。再次感谢time_delay = 1000 // desired_fps,我们可以通过时间延迟控制此参数,可以通过公式... def play(self): # move all animals continuously self.move_animals() self.after(41, self.play) # 24 fps # self.after(33, self.play) # 30 fps ... 计算:

...
class Animal(tk.Button):
    def __init__(self, animal_type, *args, **kwargs):
        super().__init__(*args, **kwargs)
        ...
        #   dictionary for representation purpose
        self.move_sets = {'n': (0, -1), 's': (0, 1), 'w': (-1, 0), 'e': (1, 0),
                          'nw': (-1, -1), 'sw': (-1, 1), 'ne': (1, -1), 'se': (1, 1)}
        ...

    def move(self):
        #   move animal
        #   get random distance and direction
        distance = random.randint(0, 5) * self.base_speed
        direction = random.choice(list(self.move_sets.values()))
        movement = [_ * distance for _ in direction]
        current_coords = self.play_area.coords(self.id)

        #   to prevent case when an animal leaves play area
        if 0 <= current_coords[0] + movement[0] <= self.play_area.winfo_width() and \
           0 <= current_coords[1] + movement[1] <= self.play_area.winfo_height():
            self.play_area.move(self.id, *movement)
        ...

还可以通过附加指示改善移动并将条件逻辑简化为一个声明:

"nObject1.Oid"

类似问题

答案 1 :(得分:0)

一种方法是将按钮放在一行(如前所述),但是按随机顺序排列。

您必须创建包含所有单词的列表(包含许多"Doe"),
随机播放列表然后使用此列表创建Buttons

num_of_doe = level * 2 # we use CamelCaseNames for class names

# create list with words
all_words = ["Doe"]*num_of_doe + ["Deer"]

# shuffle list ("in-place")
random.shuffle(all_words)

#  create buttons using words
for word in all_words:
    b = tk.Button(root, text=word, command=lambda txt=word:shot(txt))
    b.pack()

BTW:如果您lambda word使用for lambda txt=word:shot(txt),那么您必须使用lambda:shot(word)。如果你使用word,那么它会分配相同的值 - 列表中的最后一个值 - 因为它引用变量pack(),而不是来自此变量的值。

如果您需要更多随机位置,而不是place(),您可以使用grid()b.place(x=random.randint(0, 200), y=random.randint(0, 100)) 将按钮放在随机位置或单元格中(在网格中)

b.grid(row=random.randint(0, 10), column=random.randint(0, 10))

Activity

但它会产生问题,因为你可以将两个按钮放在同一个地方。

您需要先生成所有值。它需要保持列表中的值,然后获取新的随机值,与列表中的值进行比较,并生成新值,如果它已经在列表中。

这对你有用;)