Text Size Change Persistence

Viewed 34

I'll start with simply copy and pasting my huge chunk of code:

# Libraries #

import pygame
from pygame.locals import *
import ResolutionMenu

# Classes #

class GuiSettings:
    def __init__(self):
        self.TextSize = 20
        self.button_color = (35, 65, 145)
        self.button_color_hover = (70, 105, 150)

class Button():
    def __init__(self, x, y, width, height, outline, settings, text = "", action = None):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.text = text
        self.settings = settings
        self.action = action
        self.outline = outline

    def draw(self, screen, outline = None):

        if self.outline:
            pygame.draw.rect(screen, self.outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)


        color = self.settings.button_color if not self.isOver(pygame.mouse.get_pos()) else self.settings.button_color_hover
        pygame.draw.rect(screen, color, (self.x, self.y, self.width, self.height), 0)

        if self.text != "":
            font = pygame.font.SysFont('segoeuisemibold', self.settings.TextSize)
            text = font.render(self.text, 1, (0, 0, 0))
            screen.blit(text, (self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))

    def update(self, events):
        for event in events:
            if event.type == pygame.MOUSEBUTTONDOWN and self.isOver(pygame.mouse.get_pos()) and self.action:
                self.action()

    def isOver(self, pos):
        if pos[0] > self.x and pos[0] < self.x + self.width:
            if pos[1] > self.y and pos[1] < self.y + self.height:
                return True         
        return False


# Variables # 

settings = GuiSettings()
Click = False
Clock = pygame.time.Clock()
H, W = ResolutionMenu.resolution
pygame.init()
pygame.display.set_caption("Main Menu")
font = pygame.font.SysFont(None, settings.TextSize)
screen = pygame.display.set_mode((ResolutionMenu.resolution))

# Functions #


def draw_text_center(text, font, colour, surface):
        textobj = font.render(text, 1, colour)
        textrect = textobj.get_rect()
        textrect.center = ((H / 2), (W / 10))
        surface.blit(textobj, textrect)

def draw_text(text, font, colour, surface, XandY):
        textobj = font.render(text, 1, colour)
        textrect = textobj.get_rect()
        textrect.topleft = (XandY)
        surface.blit(textobj, textrect)

def MainMenu():
    while True:
        if ResolutionMenu.resolution == (800, 600):

            screen.fill ((0, 0, 0))

            draw_text_center("Main Menu Navigation", font, (255, 255, 255), screen)

            mx, my = pygame.mouse.get_pos()
            button1 = pygame.Rect((W/10), (H/5), (W/3), (H/15))
            button2 = pygame.Rect((W/10), (H/2), (W/3), (H/15))

            if button1.collidepoint((mx, my)):
                if Click:
                    game()
                
            if button2.collidepoint((mx, my)):
                if Click:
                    OptionsMenu()

            pygame.draw.rect(screen, (255, 0, 0), button1)
            pygame.draw.rect(screen, (255, 0, 0,), button2)
            
            Click = False        
            for event in pygame.event.get():
                if event.type == QUIT:
                    pygame.quit()
                    
                if event.type == KEYDOWN:
                    if event.key == K_ESCAPE:
                        pygame.quit()
                
                if event.type == MOUSEBUTTONDOWN:
                    if event.button == 1:
                        Click = True

            pygame.display.update()
            Clock.tick(60)
        
def game():
    running = True
    while running:
        screen.fill((0,0,0))
        
        draw_text('Test 1', font, (255, 255, 255), screen, (20, 20))
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    running = False
        
        pygame.display.update()
        Clock.tick(60)


def OptionsMenu():    

    screen = pygame.display.set_mode((800, 600))
    settings = GuiSettings()

    buttons = [
        Button(100, 150, 200, 50, (0, 0, 0), settings, "Set Text Size: 14", lambda: settings.__setattr__('TextSize', 14)),
        Button(500, 150, 200, 50, (0, 0, 0), settings, "Set Text Size: 16", lambda: settings.__setattr__('TextSize', 16)),
        Button(100, 300, 200, 50, (0, 0, 0), settings, "Set Text Size: 18", lambda: settings.__setattr__('TextSize', 18)),
        Button(500, 300, 200, 50, (0, 0, 0), settings, "Set Text Size: 20", lambda: settings.__setattr__('TextSize', 20))
    ]

    running = True
    while running:
        events = pygame.event.get()
        for event in events:
            if event.type == pygame.QUIT:
                pygame.quit()
                return
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    running = False

        for button in buttons:
            button.update(events)

        screen.fill((100, 100, 100))

        for button in buttons:
            button.draw(screen)
        

        pygame.display.flip()

MainMenu()

So as you can see, recently I've been trying to make a main menu navigation panel for a game, and all is going well so far. I have stumbled into a problem, however.

The problem is thus: I have created a class of which holds the settings for text size, the button colour and the button hover colour (the colour of the button will change when the mouse pos is inside of the button's area).

class GuiSettings:
    def __init__(self):
        self.TextSize = 20
        self.button_color = (35, 65, 145)
        self.button_color_hover = (70, 105, 150)

This works completely fine when I'm inside of the OptionMenu() function, but when breaking that function, by pressing esc and returning to the MainMenu() function, the text size of the "Main Menu Navigation" text (Code below) doesn't change, despite using the 'settings.TextSize' as the size variable. I'm not sure why this is seeing as on the options menu uses a lambda function to change the value of the text size.

buttons = [
        Button(100, 150, 200, 50, (0, 0, 0), settings, "Set Text Size: 14", lambda: settings.__setattr__('TextSize', 14)),
        Button(500, 150, 200, 50, (0, 0, 0), settings, "Set Text Size: 16", lambda: settings.__setattr__('TextSize', 16)),
        Button(100, 300, 200, 50, (0, 0, 0), settings, "Set Text Size: 18", lambda: settings.__setattr__('TextSize', 18)),
        Button(500, 300, 200, 50, (0, 0, 0), settings, "Set Text Size: 20", lambda: settings.__setattr__('TextSize', 20))
    ]

Sorry that this has been such a long question, thank you for reading and I hope someone better at this than me can give me some help.

1 Answers

You create the font object before the main application loop with the font size settings.TextSize. This font object doesn't magically change when you change the settings.TextSize afterwards. The font size is used to rasterize the glyphs in the font. You need to create a new font object with a new size after the function OptionsMenu is left.
Furthermore you need to use the global statement, since font and settings are variables in global namespace.

def MainMenu():
    global font    # font is a variable in global namespace

    while True:
        if ResolutionMenu.resolution == (800, 600):
            # [...]

            if button2.collidepoint((mx, my)):
                if Click:
                    OptionsMenu()

                    # create new font with new size
                    font = pygame.font.SysFont(None, settings.TextSize) 

            # [...]
def OptionsMenu():  
    global settings   # settings is a variable in global namespace

    screen = pygame.display.set_mode((800, 600))
    # settings = GuiSettings() # <--- DELETE use the existing object instead

    # [...]
Related