Closed WebTiger89 closed 7 months ago
Hello,
There isn't with just hiding as that just makes the elements not be drawn and not interactable. You could probably make something like this with setting the relative position and hiding the error label. Though this isn't something I've really considered until just now.
Just had a quick tinker:
import pygame
from pygame import Rect
from pygame_gui import UIManager, UI_BUTTON_PRESSED
from pygame_gui.elements import UIButton, UITextEntryLine, UIWindow, UILabel
pygame.init()
pygame.display.set_caption('Login window test')
window_surface = pygame.display.set_mode((800, 600))
manager = UIManager((800, 600), 'data/themes/quick_theme.json')
background = pygame.Surface((800, 600))
background.fill(manager.ui_theme.get_colour('dark_bg'))
window = UIWindow(rect=pygame.Rect((50, 50), (400, 300)),
manager=manager, resizable=False,
window_display_title='Login')
window.set_minimum_dimensions((400, 300))
confirm_button = UIButton(relative_rect=Rect(10, -40, 100, 30),
text='Confirm',
container=window,
anchors={'top': 'bottom',
'left': 'left',
'bottom': 'bottom',
'right': 'left'})
cancel_button = UIButton(relative_rect=Rect((10, -40), (100, 30)),
text='Cancel',
container=window,
anchors={'top': 'bottom',
'left': 'left',
'bottom': 'bottom',
'right': 'left',
'left_target': confirm_button})
password_entry = UITextEntryLine(Rect((90, -100), (210, 30)),
container=window,
anchors={'top': 'bottom',
'left': 'left',
'bottom': 'bottom',
'right': 'left',
'bottom_target': confirm_button}
)
password_entry.set_text_hidden(True)
username_error_label = UILabel(Rect((90, 0), (210, 30)),
text="",
container=window,
anchors={'top': 'bottom',
'left': 'left',
'bottom': 'bottom',
'right': 'left',
'bottom_target': password_entry}
)
username_error_label.hide()
username_entry = UITextEntryLine(Rect((90, -40), (210, 30)),
container=window,
anchors={'top': 'bottom',
'left': 'left',
'bottom': 'bottom',
'right': 'left',
'bottom_target': username_error_label}
)
username_entry_label = UILabel(Rect((-72, -40), (72, 30)),
text="Username:",
container=window,
anchors={'top': 'bottom',
'left': 'right',
'bottom': 'bottom',
'right': 'right',
'right_target': username_entry,
'bottom_target': username_error_label}
)
password_entry_label = UILabel(Rect((-72, -100), (72, 30)),
text="Password:",
container=window,
anchors={'top': 'bottom',
'left': 'right',
'bottom': 'bottom',
'right': 'right',
'right_target': password_entry,
'bottom_target': confirm_button}
)
clock = pygame.time.Clock()
is_running = True
while is_running:
time_delta = clock.tick(60)/1000.0
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
if event.type == UI_BUTTON_PRESSED:
if event.ui_element == confirm_button:
print('Confirmed!')
if event.type == pygame.KEYDOWN and event.key == pygame.K_F1:
username_error_label.set_relative_position((60, -40))
username_error_label.set_text("Error with username")
username_error_label.show()
if event.type == pygame.KEYDOWN and event.key == pygame.K_F2:
username_error_label.set_relative_position((60, 0))
username_error_label.set_text("")
username_error_label.hide()
manager.process_events(event)
manager.update(time_delta)
window_surface.blit(background, (0, 0))
manager.draw_ui(window_surface)
pygame.display.update()
Looks like this:
Then when you hit F1:
Works for me, thanks for your invest. I still have one problem, might you have a look please:
import pygame
import pygame_gui
import csv
import os.path
# noinspection SpellCheckingInspection
class StartMenu:
scores_csv = 'scores.csv'
scores = []
is_running = False
width = 800
height = 600
def create_window(self):
pygame.display.set_caption('Startmenü')
window_surface = pygame.display.set_mode((self.width, self.height))
manager = pygame_gui.UIManager((self.width, self.height))
background = pygame.Surface((self.width, self.height))
background.fill(pygame.Color("white"))
x_mid = self.width / 2
y_mid = self.height / 2
entry_box_width = 200
x_pos_elements = x_mid - (entry_box_width / 2)
# Erstellt ein single line TextInput Feld
# Das Element ist zentriert ausgerichtet
# Alle weiteren Elemente werden relativ zu ihren Vorgängern ausgerichtet, siehe anchors
username_input = pygame_gui.elements.UITextEntryLine(
relative_rect=pygame.Rect((0, -80), (entry_box_width, 50)), manager=manager, anchors={'center': 'center'})
# Placeholder text setzen
username_input.placeholder_text = "Benutzername"
# Hintergrundfarbe setzen
username_input.background_colour = pygame.Color("white")
# Cursorfarbe so wie Textfarbe setzen
username_input.text_cursor_colour = username_input.text_colour
# Element neu rendern
username_input.rebuild()
# Focus state speichern, um einen Wechsel zu erkennen
previous_focus = username_input.is_focused
error_label_width = 250
error_label_height = 35
# username_error_label_height = 50
# Verstecktes Fehler label element erstellen
username_error_label = pygame_gui.elements.UILabel(text="",
relative_rect=pygame.Rect(
(-entry_box_width, -error_label_height),
(error_label_width, error_label_height)),
manager=manager, anchors={'top_target': username_input,
'left_target': username_input})
# Horizontale Textausrichtung setzen
username_error_label.text_horiz_alignment = 'left'
username_error_label.text_colour = pygame.Color("red")
username_error_label.hide()
username_error_label.rebuild()
# Passwort TextInput Feld erstellen
password_input = pygame_gui.elements.UITextEntryLine(
relative_rect=pygame.Rect((-error_label_width, 0), (entry_box_width, 50)), manager=manager,
anchors={'top_target': username_error_label,
'left_target': username_error_label})
password_input.placeholder_text = "Passwort"
password_input.background_colour = pygame.Color("white")
password_input.text_cursor_colour = password_input.text_colour
# Eingabe wird unkenntlich gemacht
password_input.set_text_hidden(True)
password_input.rebuild()
# Verstecktes Fehler label element erstellen
password_error_label = pygame_gui.elements.UILabel(text="",
relative_rect=pygame.Rect(
(-entry_box_width, -error_label_height),
(error_label_width, error_label_height)),
manager=manager, anchors={'top_target': password_input,
'left_target': password_input})
# Horizontale Textausrichtung setzen
password_error_label.text_horiz_alignment = 'left'
password_error_label.text_colour = pygame.Color("red")
password_error_label.hide()
password_error_label.rebuild()
# password_input_confirmation = pygame_gui.elements.UITextEntryBox(
# relative_rect=pygame.Rect((x_pos_elements + entry_box_width + 20, 150), (entry_box_width, 50)), manager=manager)
login_button = pygame_gui.elements.UIButton(
relative_rect=pygame.Rect((-error_label_width, 0), (entry_box_width, 50)), text='Login',
manager=manager, anchors={'top_target': password_error_label, 'left_target': password_error_label})
self.load_scores()
is_running = True
clock = pygame.time.Clock()
while is_running:
time_delta = clock.tick(60) / 1000.0
for event in pygame.event.get():
if event.type == pygame.QUIT:
is_running = False
if event.type == pygame.KEYDOWN and event.key == pygame.K_F1:
password_error_label.update_containing_rect_position()
password_error_label.rebuild()
password_input.update_containing_rect_position()
password_input.rebuild()
if event.type == pygame_gui.UI_BUTTON_PRESSED:
if event.ui_element == login_button:
print('Hello World!')
if len(username_input.text) == 0:
username_error_label.set_relative_position((-entry_box_width, 0))
username_error_label.set_text("Bitte füllen Sie das Feld.")
username_error_label.show()
if len(password_input.text) < 1:
password_error_label.set_text("Bitte füllen Sie das Feld.")
if len(password_input.text) in range(1, 5):
password_error_label.set_text("Mindestens 5 Zeichen!")
password_error_label.set_relative_position((-entry_box_width, 0))
password_error_label.show()
if event.type == pygame_gui.UI_TEXT_ENTRY_CHANGED:
if event.ui_element == username_input:
if len(event.text) > 1:
print("Changed text:", event.text)
username_error_label.set_relative_position((-entry_box_width, -error_label_height))
username_error_label.hide()
if event.ui_element == password_input:
if len(password_input.text) in range(1, 5):
password_error_label.set_text("Mindestens 5 Zeichen!")
password_error_label.show()
else:
password_error_label.set_relative_position((-entry_box_width, -error_label_height))
password_error_label.hide()
if username_input.is_focused:
previous_focus = True
if not username_input.is_focused and previous_focus:
previous_focus = False
print("lost focus")
if not self.check_user(username_input.text):
print("user not registered")
manager.process_events(event)
manager.update(time_delta)
window_surface.blit(background, (0, 0))
manager.draw_ui(window_surface)
pygame.display.update()
# def validate_input(self, username, password):
# if len(username) == 0:
def load_scores(self):
# Prüfen, ob Datei existiert
if os.path.isfile(self.scores_csv):
# Öffnet Datei zum Lesen
# Datei wird automatisch geschlossen, siehe 'with'
with open(self.scores_csv, newline='') as csv_file:
# CSV Parser/Reader Instanz
csv_reader = csv.DictReader(csv_file)
# Über Zeilen iterieren
for row in csv_reader:
# Existierende scores in Liste eintragen
self.scores.append(row)
# Wenn Datei nicht existiert, wird diese mit initialem Text erstellt
else:
# Öffnet Datei zum Schreiben
with open(self.scores_csv, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',')
writer.writerow(["Username"] + ["Password"] + ["Punkte1"] + ["Punkte2"])
def create_user(self, username, password):
with open(self.scores_csv, 'w', newline='') as csvfile:
writer = csv.writer(csvfile, delimiter=',')
# def create_scores(self):
def check_user(self, username):
for profile in self.scores:
print(profile["Username"])
if profile["Username"] == username:
return True
return False
if __name__ == "__main__":
pygame.init()
menu = StartMenu()
menu.create_window()
When username_error_label
and password_error_label
are shown at the same time (press button while text fields are empty) and I fill the username, username_error_label hides, password_input moves up but unfortunately the position of password_error_label does not update. I would expect it moves up too so it is directly below password_input (y is 0 at this time). I tried it with update_containing_rect_position()
but with no luck. Any idea how I can overcome this?
Hmm, I guess it is not chaining the anchor movements correctly here. Probably a bug, but you can fix for now by adding:
password_error_label._update_absolute_rect_position_from_anchors()
In this block at the end:
if len(event.text) > 1:
print("Changed text:", event.text)
username_error_label.set_relative_position((-entry_box_width, -error_label_height))
username_error_label.hide()
# Add line here
@MyreMylar @WebTiger89 Check if this works now with the latest main branch as, if this issue is labelled correctly, it should have been fixed when I had found and fixed this issue.
I will have a look into this.
Tested this again and it all seems to work correctly now 👍
Hi, is there any logic that when an element gets hidden, other elements around will take its room and when the hidden element is showed again, it claims its room back. I'm looking for such behavior like in HTML.
For example, having a login mask, you have a username field and below a password field. But for validation you will also need an error label below the username or between username and password field respectively. The label element is hidden by default and gets visible when validation fails. Is there built-in logic to move the password field down when the label element gets visible and move up when it gets invisible again by using anchor targets?