Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] Button Instance
#1
I'm playing around with making a button class and have come across problem.
As long as I just have one button the cursor works as expected but, if I place two or more the cursor flickers.

Any insight appreciated.
See video



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
#! /usr/bin/env python3.10
 
# Do the imports
import pygame
import os
 
# Get current working directory
path = os.getcwd()
 
# Initialize pygame
pygame.init()
 
# Set screen size
screen = pygame.display.set_mode((800,600))
 
# Set and display the window icon
# game_icon = pygame.image.load(f'{path}/icons/ratt.ico')
# pygame.display.set_icon(game_icon)
 
# Set a hand cursor
hand = pygame.SYSTEM_CURSOR_HAND
arrow = pygame.SYSTEM_CURSOR_ARROW
 
# Set and display window title
pygame.display.set_caption('My Game')
 
# pygame clock for setting frame rate
clock = pygame.time.Clock()
 
class Button:
    def __init__(self):
        self.text = 'Button'
        self.x = 0
        self.y = 0
        self.font_size = 30
        self.bgcolor = (110, 110, 255)
        self.fgcolor = (255, 255, 255)
        self.border_color = (90, 90, 90)
        self.shadow_color = (180, 180, 180)
        self.pos = pygame.mouse.get_pos()
 
 
    def show(self):
 
        btn_text = pygame.font.SysFont(None, self.font_size)
 
        button_shadow = pygame.Rect(self.x+3, self.y+3, btn_text.size(self.text)[0]*2, \
                                    btn_text.size(self.text)[1]*2+1)
        border = pygame.Rect(self.x-1, self.y-1, (btn_text.size(self.text)[0]*2)+2, \
                             (btn_text.size(self.text)[1]*2)+3)
        button = pygame.Rect(self.x, self.y, btn_text.size(self.text)[0]*2, btn_text.size(self.text)[1]*2)
        text = btn_text.render(f'{self.text}', True, self.fgcolor)
 
        if button.collidepoint(self.pos[0], self.pos[1]):
            pygame.mouse.set_cursor(hand)
            self.bgcolor = (150,150,255)
            self.fgcolor = (250,250,255)
        else:
            pygame.mouse.set_cursor(arrow)
 
 
        pygame.draw.rect(screen, self.shadow_color, button_shadow)
        pygame.draw.rect(screen, self.border_color, border)
        pygame.draw.rect(screen, self.bgcolor, button)
        screen.blit(text, (self.x+button.width/4, self.y+button.height/4))
 
 
# Main program
def main():
    running = True
 
    while running:
        screen.fill('ivory')
 
        btn = Button()
        btn.x = 220
        btn.y = 210
        btn.show()
 
        btn2 = Button()
        btn2.text = 'Button 2'
        btn2.x = 420
        btn2.y = 210
        btn2.show()
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
 
 
        pygame.display.update()
        clock.tick(60)
 
if __name__ == '__main__':
    main()
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts


Reply
#2
The problem is that the other button keeps wanting to change the cursor back to the pointer. Here I've used a class variable calledhand_cursorto keep track of when a button has changed the cursor. Check out lines 31 and lines 61 through 64.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#! /usr/bin/env python3.10
  
# Do the imports
import pygame
import os
  
# Get current working directory
path = os.getcwd()
  
# Initialize pygame
pygame.init()
  
# Set screen size
screen = pygame.display.set_mode((800,600))
  
# Set and display the window icon
# game_icon = pygame.image.load(f'{path}/icons/ratt.ico')
# pygame.display.set_icon(game_icon)
  
# Set a hand cursor
hand = pygame.SYSTEM_CURSOR_HAND
arrow = pygame.SYSTEM_CURSOR_ARROW
  
# Set and display window title
pygame.display.set_caption('My Game')
  
# pygame clock for setting frame rate
clock = pygame.time.Clock()
  
class Button:
    hand_cursor = False
    def __init__(self):
        self.text = 'Button'
        self.x = 0
        self.y = 0
        self.font_size = 30
        self.bgcolor = (110, 110, 255)
        self.fgcolor = (255, 255, 255)
        self.border_color = (90, 90, 90)
        self.shadow_color = (180, 180, 180)
        self.pos = pygame.mouse.get_pos()
  
  
    def show(self):
  
        btn_text = pygame.font.SysFont(None, self.font_size)
  
        button_shadow = pygame.Rect(self.x+3, self.y+3, btn_text.size(self.text)[0]*2, \
                                    btn_text.size(self.text)[1]*2+1)
        border = pygame.Rect(self.x-1, self.y-1, (btn_text.size(self.text)[0]*2)+2, \
                             (btn_text.size(self.text)[1]*2)+3)
        button = pygame.Rect(self.x, self.y, btn_text.size(self.text)[0]*2, btn_text.size(self.text)[1]*2)
        text = btn_text.render(f'{self.text}', True, self.fgcolor)
  
        if button.collidepoint(self.pos[0], self.pos[1]):
            Button.hand_cursor = True
            pygame.mouse.set_cursor(hand)
            self.bgcolor = (150,150,255)
            self.fgcolor = (250,250,255)
        else:
            if Button.hand_cursor == False :
                pygame.mouse.set_cursor(arrow)
            else :
                Button.hand_cursor = False
  
  
        pygame.draw.rect(screen, self.shadow_color, button_shadow)
        pygame.draw.rect(screen, self.border_color, border)
        pygame.draw.rect(screen, self.bgcolor, button)
        screen.blit(text, (self.x+button.width/4, self.y+button.height/4))
  
  
# Main program
def main():
    running = True
  
    while running:
        screen.fill('ivory')
  
        btn = Button()
        btn.x = 220
        btn.y = 210
        btn.show()
  
        btn2 = Button()
        btn2.text = 'Button 2'
        btn2.x = 420
        btn2.y = 210
        btn2.show()
  
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
  
  
        pygame.display.update()
        clock.tick(60)
  
if __name__ == '__main__':
    main()
Reply
#3
Works for two buttons but not more. I think I will start from scratch and try again. Thanks for teaching me something new about the class variables. I've not really worked with them before.
I welcome all feedback.
The only dumb question, is one that doesn't get asked.
My Github
How to post code using bbtags
Download my project scripts


Reply
#4
I guess we also needed to know which button was changing the cursor. Here is my latest version that includes acolide_with_pointerinstance variable to keep track of that. Let me know if this helps. I've also taken the button assignments out of the main loop so that they are not recreated over and over.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#! /usr/bin/env python3.10
   
# Do the imports
import pygame
import os
   
# Get current working directory
path = os.getcwd()
   
# Initialize pygame
pygame.init()
   
# Set screen size
screen = pygame.display.set_mode((800,600))
   
# Set and display the window icon
# game_icon = pygame.image.load(f'{path}/icons/ratt.ico')
# pygame.display.set_icon(game_icon)
   
# Set a hand cursor
hand = pygame.SYSTEM_CURSOR_HAND
arrow = pygame.SYSTEM_CURSOR_ARROW
   
# Set and display window title
pygame.display.set_caption('My Game')
   
# pygame clock for setting frame rate
clock = pygame.time.Clock()
   
class Button:
    hand_cursor = False
    def __init__(self):
        self.text = 'Button'
        self.x = 0
        self.y = 0
        self.font_size = 30
        self.bgcolor = (110, 110, 255)
        self.fgcolor = (255, 255, 255)
        self.border_color = (90, 90, 90)
        self.shadow_color = (180, 180, 180)
        self.collide_with_pointer = False
   
    def show(self):
   
        btn_text = pygame.font.SysFont(None, self.font_size)
   
        button_shadow = pygame.Rect(self.x+3, self.y+3, btn_text.size(self.text)[0]*2, \
                                    btn_text.size(self.text)[1]*2+1)
        border = pygame.Rect(self.x-1, self.y-1, (btn_text.size(self.text)[0]*2)+2, \
                             (btn_text.size(self.text)[1]*2)+3)
        button = pygame.Rect(self.x, self.y, btn_text.size(self.text)[0]*2, btn_text.size(self.text)[1]*2)
        text = btn_text.render(f'{self.text}', True, self.fgcolor)
        self.pos = pygame.mouse.get_pos()
        if button.collidepoint(self.pos[0], self.pos[1]):
            self.collide_with_pointer = True
            Button.hand_cursor = True
            pygame.mouse.set_cursor(hand)
            self.bgcolor = (150,150,255)
            self.fgcolor = (250,250,255)
        elif self.collide_with_pointer == True :
            self.collide_with_pointer = False
            pygame.mouse.set_cursor(arrow)
            self.bgcolor = (110, 110, 255)
            self.fgcolor = (255, 255, 255)
 
        pygame.draw.rect(screen, self.shadow_color, button_shadow)
        pygame.draw.rect(screen, self.border_color, border)
        pygame.draw.rect(screen, self.bgcolor, button)
        screen.blit(text, (self.x+button.width/4, self.y+button.height/4))
 
# Main program
def main():
    btn1 = Button()
    btn1.text = 'Button 1'
    btn1.x = 220
    btn1.y = 210
 
    btn2 = Button()
    btn2.text = 'Button 2'
    btn2.x = 420
    btn2.y = 210
 
    btn3 = Button()
    btn3.text = 'Button 3'
    btn3.x = 220
    btn3.y = 280
 
    btn4 = Button()
    btn4.text = 'Button 4'
    btn4.x = 420
    btn4.y = 280
 
    running = True
   
    while running:
 
        screen.fill('ivory')
        btn1.show()
        btn2.show()
        btn3.show()
        btn4.show()
 
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
   
        pygame.display.update()
        clock.tick(60)
   
if __name__ == '__main__':
    main()
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020