2

I want to be able to make a text box pop up when I hover over the button, now the button changes colour when I hover over it but no text box is displayed how can I make that happen or do I need to something entirely different like make a new screen pop up when I hover over either way the hovering over isnt working and I dont know how to fix it and id like some help please

import pygame
pygame.init()
pygame.font.init()
colours = {"White" : (255, 255, 255), "Black" : (0, 0, 0), "Red" : (255, 0, 0), "Blue" : (0, 0, 255), "Green" : (0, 255, 0)}
orighpamt = 10
currentGoblin = 0

class Screen():
    def __init__(self, title, width=400, height=600, fill=colours["White"]):
        self.title=title
        self.width=width
        self.height = height
        self.fill = fill
        self.current = False

    def makeCurrent(self):
        pygame.display.set_caption(self.title)
        self.current = True
        self.screen = pygame.display.set_mode((self.width, self.height))

    def endCurrent(self):
        self.current = False

    def checkUpdate(self):
        return self.current
    def screenUpdate(self):
        if(self.current):
            self.screen.fill(self.fill)

    def returnTitle(self):
        return self.screen

class Button():
        def __init__(self, x, y, sx, sy, bcolour, fbcolour, font, fontsize, fcolour, text):
            self.x = x
            self.y = y
            self.sx = sx
            self.sy = sy
            self.bcolour = bcolour
            self.fbcolour = fbcolour
            self.fcolour = fcolour
            self.fontsize = fontsize
            self.text = text
            self.current = False
            self.buttonf = pygame.font.SysFont(font, fontsize)
        def showButton(self, display):
            if(self.current):
                pygame.draw.rect(display, self.fbcolour, (self.x, self.y, self.sx, self.sy))
            else:
                pygame.draw.rect(display, self.bcolour, (self.x, self.y, self.sx, self.sy))

            textsurface = self.buttonf.render(self.text, False, self.fcolour)
            display.blit(textsurface, ((self.x + (self.sx/2) - (self.fontsize/2)*(len(self.text)/2) - 5,(self.y + (self.sy/2) -(self.fontsize/2) - 4))))
        def focusCheck(self, mousepos, mouseclick):
            if(mousepos[0] >= self.x and mousepos[0] <= self.x + self.sx and mousepos[1] >= self.y and mousepos[1] <= self.y + self.sy):
                self.current = True
                return mouseclick
            else:
                self.current = False
                return False
class Enemy(pygame.sprite.Sprite):

    def __init__(self, dx, dy, filename):
        pygame.sprite.Sprite.__init__(self)

        self.image = pygame.image.load(filename).convert()

        self.rect = self.image.get_rect()
        self.rect.x = dx
        self.rect.y = dy



    def draw(self, screen):
        screen.blit(self.image, self.rect)



menuScreen = Screen("Menu Screen")
screen2 = Screen("Screen 2")

win = menuScreen.makeCurrent()


done = False
font = pygame.font.Font('freesansbold.ttf', 32)
clickdamage = 1
hitpoints = orighpamt
DungeonButton = Button(125, 500, 150, 50, colours["Black"], colours["Blue"], "arial", 20, colours["White"], "Dungeon")
hitboxButton = Button(80, 50, 280, 400, colours["White"], colours["Red"], "arial", 20, colours["White"], "")
hitpointamount = Button(100, 0, 200, 50, colours["White"], colours["Black"], "arial", 20, colours["Black"], str(hitpoints))
shopButton = Button(125, 500, 150, 50, colours["Black"], colours["Red"], "arial", 20, colours["White"], "Shop")
Assassin_Text = Button(50, 350, 400, 50, colours["White"], colours["Red"], "arial", 18, colours["Black"], "Sharpen your sword and increase your damage per click")
Assassin_Upgrade = Button(10, 300, 125, 50, colours["Black"], colours["Red"], "arial", 15, colours["White"], "Assassin")
goblin = Enemy(0 , 20, "images\goblin-resized.png")
goblin2 = Enemy(80 , 50, "images\monster2.png")
toggle = False
while not done:
    menuScreen.screenUpdate()
    screen2.screenUpdate()
    mouse_pos = pygame.mouse.get_pos()
    keys = pygame.key.get_pressed()

    mouse_click = False
    for event in pygame.event.get():
        if(event.type == pygame.QUIT):
            done = True
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_click = True

    if menuScreen.checkUpdate():
        
        screen2button = shopButton.focusCheck(mouse_pos, mouse_click)
        shopButton.showButton(menuScreen.returnTitle())
        if screen2button:
            win = screen2.makeCurrent()
            
            menuScreen.endCurrent()    
    elif screen2.checkUpdate():
        returnm = DungeonButton.focusCheck(mouse_pos, mouse_click)
        Assassin_Upgrade.showButton(screen2.returnTitle())
        if Assassin_Upgrade.focusCheck(mouse_pos):
            Assassin_Text.showButton(screen2.returnTitle())
        if returnm:
            win = menuScreen.makeCurrent()
            screen2.endCurrent()

    pygame.display.update()

pygame.quit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • Does this answer your question? [Pop up message box in PyGame](https://stackoverflow.com/questions/41639671/pop-up-message-box-in-pygame) – Jan Wilamowski Nov 04 '21 at 08:54

2 Answers2

3

Add another text attribute to your class. e.g.:

class Button():
    def __init__(self, x, y, sx, sy, bcolour, fbcolour, font, fontsize, fcolour, text, tiptext):
        # [...]

        self.tiptextsurface = self.buttonf.render(tiptext, False, (0, 0, 0), (255, 255, 0))

Draw the text in a Button.showTip method, when self.current is set:

class Button():
    # [...]

    def showTip(self, display):
        if self.current:
            mouse_pos = pygame.mouse.get_pos()
            display.blit(self.tiptextsurface, (mouse_pos[0]+16, mouse_pos[1]))


Minimal example based on your code:

I've simplified the Button class, but it behaves exactly like the class in your question.

import pygame
pygame.init()

class Button():
    def __init__(self, x, y, sx, sy, bcolour, fbcolour, font, fontsize, fcolour, text, tiptext):
        self.rect = pygame.Rect(x, y, sx, sy)
        self.bcolour = bcolour
        self.fbcolour = fbcolour
        self.fcolour = fcolour
        self.fontsize = fontsize
        self.current = False
        self.buttonf = pygame.font.SysFont(font, fontsize)
        self.textsurface = self.buttonf.render(text, False, self.fcolour)
        self.tiptextsurface = self.buttonf.render(tiptext, False, (0, 0, 0), (255, 255, 0))
        
    def showButton(self, display):
        color = self.fbcolour if self.current else self.bcolour
        pygame.draw.rect(display, color, self.rect)
        display.blit(self.textsurface, self.textsurface.get_rect(center = self.rect.center))

    def showTip(self, display):
        if self.current:
            mouse_pos = pygame.mouse.get_pos()
            display.blit(self.tiptextsurface, (mouse_pos[0]+16, mouse_pos[1]))

    def focusCheck(self, mousepos, mouseclick):
        self.current = self.rect.collidepoint(mousepos)
        return mouseclick if self.current else True
                
screen = pygame.display.set_mode((400, 600))
clock = pygame.time.Clock()
font = pygame.font.Font('freesansbold.ttf', 32)
shopButton = Button(125, 500, 150, 50, "black", "red", "arial", 20, "white", "Shop", "Enter the shop")

done = False
while not done:    
    clock.tick(60)
    for event in pygame.event.get():
        if(event.type == pygame.QUIT):
            done = True
        if event.type == pygame.MOUSEBUTTONDOWN:
            mouse_click = True

    mouse_pos = pygame.mouse.get_pos()
    mouse_click = False
    screen2button = shopButton.focusCheck(mouse_pos, mouse_click)

    screen.fill((255, 255, 255))
    shopButton.showButton(screen)
    shopButton.showTip(screen)
    pygame.display.update()

pygame.quit()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
1

It's easier to answer questions that provide a Minimal, Reproducible Example. Your sample has external image and font dependencies that will need to be overcome for someone to debug your code.

If your button had an associated rect, then you can tell if the mouse cursor is hovering over the button using Rect.colliderect(position).

Here's a minimal example showing some hovering text when the mouse is in a rectangle:

import pygame
WIDTH = 640
HEIGHT = 480
FPS = 30

pygame.init()
pygame.font.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption(f"Color: purple")
clock = pygame.time.Clock()

# create a centered rectangle to fill with color
color_rect = pygame.Rect(100, 100, WIDTH - 200, HEIGHT - 200)  

font = pygame.font.SysFont(None, 50, True)
msg = "  Hovering Message  "
hover_surface = font.render(msg, True, pygame.Color("chartreuse"), pygame.Color("firebrick"))

hovering = False
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    # update game elements - Get mouse position
    mx, my = pygame.mouse.get_pos()
    # draw surface - fill background
    screen.fill(pygame.Color("grey"))
    ## draw central rect
    screen.fill(pygame.Color("purple"), color_rect)
    ## display the hovering text if the mouse is over the rectangle
    if color_rect.collidepoint((mx, my)):
        screen.blit(hover_surface, (mx, my))
    # show surface
    pygame.display.update()
    # limit frames
    clock.tick(FPS)
pygame.quit()

hovering text

Your code uses a lot of raw geometric calculations where it might be easier in the long run to use some of the native pygame elements. For example, you can make your buttons immobile Sprites, and keep them in a Sprite group to make managing them easier.

import random
  • 3,054
  • 1
  • 17
  • 22
  • 1
    you don't need to `.set_caption` in the main loop, just do it once like after initializing pygame. also probably don't create instance in the loop, create the colors outside and only reference them in the loop. Also saving mouse coords would probably be better too, like `mx, my = pygame.mouse.get_pos()` that way you can use them in other places and currently that would avoid calling it twice. Also what is the `simple_colors` list supposed to do? Otherwise your answer is good. – Matiiss Nov 14 '21 at 08:43
  • Thanks for the feedback @Matiiss. Originally I had this example randomly selecting a color when clicking, hence the in-loop caption update with the selected color. I simplified the example further, but clearly did an incomplete job. I'll tidy it up as you suggest. – import random Nov 14 '21 at 11:31