Strona główna Polish Python Coders Group
   Strona główna   Pomoc Zaloguj się Rejestracja  
Witamy, Gość. Zaloguj się lub zarejestruj.
Czy dotarł do Ciebie email aktywacyjny?

Zaloguj się podając nazwę użytkownika, hasło i długość sesji

Aktualności: PyStok #32 - 20 czerwiec 2018, 18:00, Białystok
Szukaj Szukaj
Strony: [1]   Do dołu
Drukuj
Wątek: licznik przycisków Tkinter  (Przeczytany 281 razy)
« : 11:30 11/05/18 »
Revan Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 2


Hello World Uśmiech

Staram się napisać programik, który generuje 25 przycisków w i przypisuje każdemu z nich losową wartość od 1 do 999 w tkinter. Zadaniem użytkownika jest kliknięcie każdego przycisku w kolejności rosnącej. Przyciski napisane są funkcją  i nie za bardzo wiem jak pobrać wartość od każdego  z nich, tak żeby callback go rozpoznał. Wiem że trzeba coś zrobić z metodą  bind(), ale nie wiem co. Jestem dość świeży jeśli chodzi o tkinter. Help plz.

Kod poniżej:

from tkinter import *
from tkinter import messagebox
import random

class Wciskanie():
    def __init__(self, wartosci, text, height, width, command, guzik, losowanie):
        self.wartosci = wartosci
        self.text = text
        self.height = height
        self.width = width
        self.command = command
        self.guzik = guzik
        self.losowanie = losowanie

    def przyciski(self):
        for i in range(25):
            losowanie = random.randint(1, 999)
            wartosci.append(losowanie)
            guzik = Button(okno, text = losowanie, height = 1, width = 7)
            ro = int(i/5)
            col = i%5
            guzik.grid(row = ro, column = col)
            bond = guzik.bind("<Button-1>", commence)
        return bond
   

class Wykonaj(Wciskanie):

    def execute(self):
        wartosci.sort()
        print(wartosci)
        print(min(wartosci))
        if guzik != min(wartosci):
            info = messagebox.showinfo("Klikacz", "Kliknij najmniejszą liczbę.")
        else:
            del wartosci[0]

def commence(event = None):
    do_it.execute()
   
       
   
text = None
height = None
width = None
command = None
losowanie = None


okno = Tk()
okno.title("Klikacz")

guzik = Button(okno, text = losowanie, height = 1, width = 7, command = commence)

wartosci = []

batony = Wciskanie(wartosci, text, height, width, command, guzik, losowanie)
do_it = Wykonaj(wartosci, text, height, width, command, guzik, losowanie)

batony.przyciski()


okno.mainloop()

Zapisane
« Odpowiedz #1 : 14:40 21/05/18 »
guest013 Offline
Advanced Python User

Zobacz profil
**

Reputacja: 17
Wiadomości: 142


Udało mi się coś zrobić bez bind(). Wydaje mi się, że pomysł był odpowiedni, tylko trzeba by to jakoś ładnie napisać, żeby nikt się nie czepnął o DRY Mrugnięcie

Kod
from tkinter import *
import random
 
def compare1():
   ls = [int(x) for x in (bb1, bb2)]
   if ls[0] == min(ls):
       b1.configure(text='lowest')
   else:
       b1.configure(text='highest')
 
def compare2():
   ls = [int(x) for x in (bb2, bb1)]
   if ls[0] == min(ls):
       b2.configure(text='lowest')
   else:
       b2.configure(text='highest')
 
num = [x for x in range(1000)]
 
root = Tk()
 
b1 = Button(root, text=random.sample(num,1), width=5, command=compare1)
b1.pack()
bb1 = b1.cget('text')
 
b2 = Button(root, text=random.sample(num,1), width=5, command=compare2)
b2.pack()
bb2 = b2.cget('text')
 
root.mainloop()
Zapisane

Expect nothing and you will never be dissapointed
« Odpowiedz #2 : 10:10 12/06/18 »
Revan Offline
Hello World!

Zobacz profil
*

Reputacja: 0
Wiadomości: 2


Hej, dziekuje za odpowiedz.

Pomoglo!  Uśmiech
Zapisane
« Odpowiedz #3 : 00:28 13/06/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 245


Trochę inna szkoła by się nie zamęczyć jakby miało tych przycisków być dajmy na to 100.
Sposób napisany przez guest013 jest jak najbardziej poprawny, ale niestety wymaga setek zbędnych linii kodu do takich rzeczy Uśmiech.
Kod
okno = Tk()
okno.title("Klikacz")
 
button_holder = []
values_holder = [random.randint(1,999) for x in range(25)]
 
def sprawdz_wartosc(value, values_list):
   print(value, values_list)
   #Tu sobie stosujesz swoje sprawdzenie czy jest to najmniejsze w liście values_holder i ewentualnie wywalasz z listy jak poniżej, lista jest już przesortowana.
   if value == values_list[0]:
       try:
           values_list.remove(value)
       except ValueError:
           print("Tej liczby już nie ma w liście")
   else:
       print("To nie jest najmniejsza liczba")
 
for i in range(len(values_holder)):
   button_holder.append(Button(okno, text=values_holder[i], height = 1, width = 7))
   button_holder[-1].grid(row = i//5, column = i%5)
   button_holder[-1].configure(command = lambda value=values_holder[i]: sprawdz_wartosc(value, values_holder))
 
values_holder.sort()
 
def kasowanie_przyciskow(holder):
   for i in holder:
       del i
   #To umożliwi ci wypełnienie frame'a ponownie, bez tworzenia kolejnego, kasując stare przyciski/obiekty (nie polegając na garbage collectorze).
okno.mainloop()

Zaś metody z cget (gdy zczytujesz text z buttona i nie potrzebujesz go jako int'a [wydaje mi się że pobiera string, nie sprawdzałem, zgańcie mnie jeśli się mylę] jest też dobrą metodą, gorzej gdy użytkownik ma nie wiedzieć co za dane przesyłasz buttonem).
Niemniej sposobu jakim to zrobił guest013 nigdy nie widziałem, coś nowego ^^.
Zapisane

Python 3.5.2 / Mint
« Odpowiedz #4 : 19:11 14/06/18 »
guest013 Offline
Advanced Python User

Zobacz profil
**

Reputacja: 17
Wiadomości: 142


Niemniej sposobu jakim to zrobił guest013 nigdy nie widziałem, coś nowego ^^.

Dziękuję, miło to słyszeć od kogoś bardziej zaawansowanego Duży uśmiech

Pomysł tej apki tak mi się spodobał (bo lubię tkintera), że powstała w pełni działająca aplikacja według pomysłu autora tego posta. Od siebie dodałem oznaczanie kolorem prawidłowego/nieprawidłowego wyboru z blokowaniem już wybranego przycisku.

Kod
from tkinter import *
import random
 
def make_use(guzik):
   def use():
       if buttons[guzik] == min(buttons.values()):
           guzik.config(state = 'disabled', bg='green')
       else:
           guzik.config(state = 'disabled', bg='red')
       del buttons[guzik]
   return use
 
nums = [x for x in range(1,1000)]
buttons = {}
 
root = Tk()
 
for i in range(25):    
   guzik = Button(root, text = random.sample(nums,1), height = 1, width = 7)
   guzik.grid(row = int(i/5), column = i%5)
   buttons[guzik] = int(guzik.cget('text'))
   guzik["command"] = make_use(guzik)
 
#print(buttons)
root.mainloop()

Mniej więcej rok temu pisałem apkę opartą na buttonach, a moje rozumowanie było wtedy zbyt pobieżne. Była także próba zrobienia przycisków w pętli, ale nie mogłem tego zrozumieć. Dzięki temu postowi wiem więcej. Wcześniej, co nawet widać w mojej poprzedniej wiadomości tworzyłem przyciskom nazwy i w ten sposób się do nich odnosiłem - po nazwach. A jak odnieść się do przycisków bez nazw wygenerowanych w pętli? Otóż po każdym kroku pętli w pamięci komputera zostaje utworzony obiekt, do którego można się odwoływać. Tutaj utworzyłem słownik buttons i dodawałem do niego pary obiekt (przycisk) i wylosowaną dla niego liczbę. Wystarczy odkomentować printa, żeby zobaczyć o czym tu pisałem Uśmiech
Zapisane

Expect nothing and you will never be dissapointed
« Odpowiedz #5 : 09:21 15/06/18 »
Guaz Offline
Advanced Python User

Zobacz profil
**

Reputacja: 38
Płeć: Mężczyzna
Wiadomości: 245


Pamiętam jak razem się z tym męczyliśmy żeby zrobić generowane buttony Chichot.
W końcu się poddaliśmy, ale męczyło mnie to na tyle, że w końcu to rozgryzłem jak słusznie zauważyłeś guest013 ^^. Mam nadzieję że się przyda - bo ułatwia to robotę niewiarygodnie ;d.
Zapisane

Python 3.5.2 / Mint
Strony: [1]   Do góry
Drukuj
Skocz do:  

© 2007 - 2018 Polish Python Coders Group
Powered by SMF 1.1.21 | SMF © 2006-2009, Simple Machines | Theme by PixelSlot