1

I'm new to pygame so there might be some things that could be tidied up; as this is just for a university project im not too concerned about that for the moment though.

class button():
    def __init__(self, color, x,y,width,height, text=''):
        self.color = color
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text

    def draw(self,screen,outline=None):
        #Call this method to draw the button on the screen
        if outline:
            pygame.draw.rect(screen, outline, (self.x-2,self.y-2,self.width+4,self.height+4),0)
            
        pygame.draw.rect(screen, self.color, (self.x,self.y,self.width,self.height),0)
        
        if self.text != '':
            font = pygame.font.Font('/Users/luke/Documents/Education/UEA/Masters /Application Programming/Assignment 2/Practise/digital-7 (italic).ttf', 30)
            text = font.render(self.text, True, black)
            screen.blit(text, (self.x + (self.width/2 - text.get_width()/2), self.y + (self.height/2 - text.get_height()/2)))

    def isOver(self, pos):
        # self.x + self.width > pos[0] > self.x and self.y + self.height > pos[1] > self.y:
        #Pos is the mouse position or a tuple of (x,y) coordinates
        if self.x + self.width > pos[0] > self.x and self.y + self.height > pos[1] > self.y:
            return True
        else:
            return False

I've used the Tech with Tim code for the class of the "button" which works as it should, and then i've created a function to call the button whenever i want to use it (which works as it should, for the most part).

def draw_button(name, msg, outline, active, inactive, x, y, w, h, action=None):
    name = button(inactive, x, y, w, h, msg)
    name.draw(screen, outline)
    butn = True
    while butn:
        clock.tick(60)
        name.draw(screen, outline)
        pygame.display.flip()

        for event in pygame.event.get():
            pos = pygame.mouse.get_pos()
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            
            if event.type == pygame.MOUSEBUTTONDOWN:
                if name.isOver(pos):
                    action()
            
            if event.type == pygame.MOUSEMOTION:

                if name.isOver(pos):
                    name.color = active
                else:
                    name.color = inactive

Im also not too sure why the indents arent uploading onto this (but they are correct in my code) so i know that's not the issue.. However, when calling the function, only the first one appears. Let me show you what i mean.

Take the title screen code for example:

def titlescreen():
    active = True

    while active:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                exit_game()

        screen.fill(background)
        title_text('Welcome To')
        titleimage()

        # btn("Start", 240,380, 150, 50, button, btn_hover, mainmenu)
        # btn("Quit", 420,380, 150, 50, button, btn_hover, exit_game)

        draw_button("Start_button", "START", black, btn_hover, buttonnormal, 240, 380, 150, 50, mainmenu)

        draw_button("exit_button", "quit", black, btn_hover, buttonnormal, 420, 380, 150, 50, exit_game)


        pygame.display.update()
        clock.tick(60)

When run, it creates this:

Start_button appearing

As you can see only the "start_button" Button is created. Conversely, when the Start_button commented out, the exit_button appears.

exit_button appearing

So my question is, how do i make them both appear at the same time...

Thanks in advance.

EDIT: This is the new code that displays all the buttons, but they flicker.

enter image description here

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
lukeorriss
  • 27
  • 6
  • Yes of course, because you have an extra `while`-loop in the method `draw_button`. You have an application loop. Use it! You don't need the method `draw_button` at all. – Rabbid76 Jan 03 '21 at 17:58
  • Thank you a lot! Okay, so two things. First, both buttons are showing up, which is perfect. However, the buttons are flickering like mad, and only work when clicked a portion of the times... Do you know if theres any easy fix for this? I've attached a new picture to the bottom. – lukeorriss Jan 03 '21 at 18:02
  • See [Why is the PyGame animation is flickering](https://stackoverflow.com/questions/62120723/why-is-the-pygame-animation-is-flickering/62120776#62120776) – Rabbid76 Jan 03 '21 at 18:04
  • Next you will have problems with the events. See [Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?](https://stackoverflow.com/questions/58086113/faster-version-of-pygame-event-get-why-are-events-being-missed-and-why-are/58087070#58087070) – Rabbid76 Jan 03 '21 at 18:06

1 Answers1

1

Yes of course, because you have an extra while-loop in the method draw_button. You have an application loop. Use it! You don't need the while loop in draw_button at all.

You will also need to remove the display update from draw_button. One update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering.
See Why is the PyGame animation is flickering

Next you will have problems with the events. pygame.event.get() get all the messages and remove them from the queuepygame.event.get() get all the messages and remove them from the queue. See the documentation:

This will get all the messages and remove them from the queue. [...]

If pygame.event.get() is called in multiple event loops, only one loop receives the events, but never all loops receive all events. As a result, some events appear to be missed.
Get the events once and use them in multiple loops or pass the list or events to functions and methods where they are handled.
See Faster version of 'pygame.event.get()'. Why are events being missed and why are the events delayed?.

def draw_button(button, outline, active, inactive, event_list, action=None):

    mouse_pos = pygame.mouse.get_pos()
    if button.isOver(mouse_pos):
        button.color = active
    else:
        button.color = inactive

    button.draw(screen, outline)
    
    for event in event_list:
        if event.type == pygame.MOUSEBUTTONDOWN:
            if action and button.isOver(event.pos):
                action()
def titlescreen():
    active = True

    start_button = button(buttonnormal, 240, 380, 150, 50, "START")
    quit_button = button(buttonnormal, 420, 380, 150, 50, "quit")

    while active:
        
        event_list = pygame.event.get()
        for event in event_list:
            if event.type == pygame.QUIT:
                exit_game()

        screen.fill(background)
        title_text('Welcome To')
        titleimage()

        draw_button(start_button, black, btn_hover, buttonnormal, event_list, mainmenu)
        draw_button(quit_button, black, btn_hover, buttonnormal, event_list, exit_game)

        pygame.display.update()
        clock.tick(60)
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • 1
    You are honestly a life saver... I have been struggling with this issue for the last (about 18 hours) and the fact that you looked at it and just knew what was wrong makes me a bit jealous... But i honestly can't thank you enough! Kudos to you my friend, thank you – lukeorriss Jan 03 '21 at 18:27