Pygame button widget'ı

event hook nedir lütfen açıklayabilir misiniz ?

benim istediğim update metodunun içinde olması benim yerime her şeyi yapması
değil size sorduğum size gösterdiğim metodlar işime yararmı

benim demeye çalıştığım
şu kodu kullanmak istemediğim:

if event.type == pg.MOUSEBUTTONDOWN

benim istediğim:

import pygame as pg


display = pg.display.set_mode((500,500))


class Button():
    butonlar = []
    def __init__(self, *, command, image_path, pos):
        self.command = command
        self.sprite = pg.image.load(image_path).convert()
        self.rect = self.sprite.get_rect(topleft= pos)
        self.butonlar.append(self)
    def update(self, *args):
        mouse = pg.mouse.get_pos()
        clicked = pg.mouse.get_pressed()

        if clicked[0]:
            if self.rect.collidepoint(mouse):
                self.command(mouse)

    def delete(self):
        self.butonlar.remove(self)


buton1 = Button(command = lambda event: print("1. buton basıldı"), image_path="Buton.png", pos=(100,100))
buton2 = Button(command = lambda event: print("2. buton basıldı"), image_path="Buton.png", pos=(200,200))


while True:

    display.fill((255,255,255))
    
    for event in pg.event.get():
        if event.type == pg.QUIT:
            exit()
        for but in Button.butonlar:
            but.update()    

        

    for buton in Button.butonlar:
        display.blit(buton.sprite,buton.rect)
    
    pg.display.update()

sizce bu kodu kullansam olur mu veya daha kısa bir yol varmı

bu kodu daha iyi hale nasıl getiririm (yani ButtonDown değişkeni ile yaptığım işi daha iyi nasıl yaparım)

import pygame as pg


pg.init()

#------------------Button Widget------------------
class Button(pg.sprite.Sprite):
    def __init__(self, *, command, image, pos):
        pg.sprite.Sprite.__init__(self)
        self.command = command
        self.image = pg.image.load(image).convert()
        self.rect = self.image.get_rect(topleft= pos)
        self.ButtonDown = False
        
        
    def update(self, *args):
        mouse = pg.mouse.get_pos()
        clicked = pg.mouse.get_pressed()
        if self.rect.collidepoint(mouse):
            if clicked[0] and self.ButtonDown == False:
                self.ButtonDown = True
                self.command()
            elif not clicked[0]:
                self.ButtonDown = False    




display = pg.display.set_mode((500,500))




buton1 = Button(command = lambda : print("1. buton basıldı"), image="BUTONIMG.png", pos=(100,100))
buton2 = Button(command = lambda : print("2. buton basıldı"), image="BUTONIMG.png", pos=(100,200))


while True:

    display.fill((255,255,255))
    
    for event in pg.event.get():
        if event.type == pg.QUIT:
            exit()

    buton1.update()
    buton2.update()
    
    display.blit(buton1.image,buton1.rect)
    display.blit(buton2.image,buton2.rect)
    
    pg.display.update()

Olur olur.

Var, event loop.

Event loop kullanarak.

1 Beğeni

@aib çok güzel ve öz cevaplamış :smiley: Kodunuzda Button.update metodunun içinde pg.mouse.get_pos() ve clicked = pg.mouse.get_pressed() fonksiyonları çağrıldığı için defalarca aynı fonksiyonu çağırıyorsunuz. update metodunda yapacağınız bu işi bir defa yapmanız lazım. Bunu event loop’da yapmanızın hiçbir sakıncası yok. Ama siz illaki öyle bir kod istemiyorum diye tutturdunuz. Sebebini anlayabilmiş değilim. Çok istiyorsanız Button sınıfı için bir sınıf metodu (classmethod) oluşturun, döngüyü de onun içinde -bir defa- yapın.

Mesela klavyede a tuşuna basıldığında siz kodunuzda hiçbir kontrol yapmadan önceden belirlediğiniz bir fonksiyon çalıştırılıyorsa bu bir event hook oluyor. Yani belli bir event (olay) gerçekleştiğinde belli bir fonksiyon çağırılılıyor (bu da hook).

Event loop kullanmayı istemiyorum cunku
Bu olayı button classı içinde nasıl kullanıcağmı
Bilmediğimden dolayi sunu denedim ama yaramadı

def update (self):
      for event in pg.event.get ():
             #....

Ama bu event loopunun içine yazdığım kod calismadi

Bunun çalışmama sebebi pg.event.get() fonksiyonunun queue’den eventleri silmesi. Yani bu fonksiyonu çağırdığınızda daha önce elinize geçmeyen bütün eventleri alıyorsunuz, ve bu eventler pygame’den siliniyor. Eğer bu fonksiyonu ana döngünüzde iki defa çağırırsanız istediğiniz gibi çalışmaz.

Bir de cümlelerinizde nokta kullanırsanız sizi daha rahat anlayacağım.

Peki bunu nasıl yapabilirim
Yani event loop’u nasıl dahil edebilirim (button class icinde)

Eventleri kontrol ettiğiniz ana döngüde bu işlemleri yapabilirsiniz.

Bu kodu inceleyin istiyorsanız.

import pygame as pg


pg.init()

#------------------Button Widget------------------
class Button(pg.sprite.Sprite):
    def __init__(self, *, command, image, pos):
        pg.sprite.Sprite.__init__(self)
        self.command = command
        self.image = pg.image.load(image).convert()
        self.rect = self.image.get_rect(topleft= pos)
        self.ButtonDown = False
        
        
    def update(self, pos):
        if self.rect.collidepoint(pos):
            self.command()
            ### yapılacak işlemler   

    @classmethod
    def update_buttons(cls, *buttons):
        pos = pg.mouse.get_pos()
        for buton in buttons:
            buton.update(pos)



display = pg.display.set_mode((500,500))




buton1 = Button(command = lambda : print("1. buton basıldı"), image="1.png", pos=(100,100))
buton2 = Button(command = lambda : print("2. buton basıldı"), image="2.png", pos=(100,200))


while True:

    display.fill((255,255,255))
    
    for event in pg.event.get():
        if event.type == pg.QUIT:
            exit()
        if event.type == pg.MOUSEBUTTONDOWN:
            Button.update_buttons(buton1, buton2)
    
    display.blit(buton1.image,buton1.rect)
    display.blit(buton2.image,buton2.rect)
    
    pg.display.update()

Event loop event aldiginda (for event in pygame.event.get(): ...) dugmelerin update fonksiyonlarina bu event’i parametre olarak yollayabilir. Mouse move/click event’i olup olmadigi update’in icinde de, disinda da kontrol edilebilir. (Birden fazla event icin birden fazla update de yazilabilir.) Buton/koordinat kontrolunun iceride yapmasi daha mantikli olur diye dusunuyorum.

benim event loop buttonu kullanıcağım yerden başka bir betikte

o zaman ne yapıcağım

Her şey bir tek event loopda kontrol edilecek, normalde pygame kullanırken herkesin yaptığı gibi.

Saolun anladım ve yaptım özür dilerim pygame de yeniyim

kodum:

import pygame as pg


pg.init()

#------------------Button Widget------------------
class Button(pg.sprite.Sprite):
    def __init__(self, *, command, image, pos):
        pg.sprite.Sprite.__init__(self)
        self.command = command
        self.image = pg.image.load(image).convert()
        self.orginalimg = self.image.copy()
        self.rect = self.image.get_rect(topleft= pos)
        self.ButtonDown = False
        
        
    def handle_event(self, event):

        
        mouse = pg.mouse.get_pos()
        clicked = pg.mouse.get_pressed()
        if self.rect.collidepoint(mouse):
            self.image = pg.image.load("BUTONDOWNIMG.png").convert()
            if event.type == pg.MOUSEBUTTONDOWN:
                self.command()

        else:
            self.image =  self.orginalimg
1 Beğeni

Aslında hala her button örneği için aynı fonksiyonlar çağırılmış oluyor ama ne diyeyim. Bir de clicked değişkenini tanımlamışsınız ama kullanmamışsınız.

Kopyala-yapistir yaptığım için silmeyi ubuttum

Kodunuza tekrar baktım da buton her tıklandığında BUTONDOWNIMG.png dosyası tekrar diskten okunuyor. Böyle işlemlerden kaçınarak programınızın başlarında bir defa okuyup bir değişkene atamanız daha doğru olacaktır.

Anladım ve aklıma bir şey geldi
.convert() ile .convert_alpha() arasında bir fark varmı?

Evet. convert_alpha metodu transparent resimler için kullanılıyor.