Z 排序控件,控件顶部和底部的碰撞检测
Z Ordering Controls, collision detection on top and bottom of control
我正在 pygame 中创建控件(仅完成按钮和标签,以及为控件设置工具提示)。我正在以正确的 Z 顺序绘制控件,但我正在尝试检测鼠标是否在另一个控件上,因此它只会激活可见的控件。
如果您删除 test.set_on_bottom(btnButton7),这在一定程度上会起作用,它只会触发 button7,即使鼠标位于其下方的其中一个按钮上,但如果您单击下方的其中一个按钮button7 并将鼠标移到 button7 上它仍然认为原始按钮正在被点击(当它不应该被点击时)
几天来我一直在为这个问题绞尽脑汁,但就是想不通。
(另外,我今天早上才想到,但我应该把每个控件都变成一个 class 而不是一个 id,所以稍后会重新处理)
代码太长post,这里是pastebin link
设置状态和触发消息的所有处理都在 process_events 方法中完成
def process_events(self):
button = pygame.mouse.get_pressed()
mouse_pos = pygame.mouse.get_pos()
for control_id in reversed(self.__z_order):
state = self.__control_list[control_id]['state']
if state in ('deleted', 'disabled') or not self.__control_list[control_id]['draw']:
continue
if self.__control_list[control_id]['rect'].collidepoint(mouse_pos):
# left mouse is pressed
if button[0]:
# current state of this control is hot and left mouse is pressed on it
if state == 'hot':
for x in self.__z_order[0:control_id - 1]:
if self.__control_list[x]['state'] == 'pressed':
self.__control_list[x]['state'] = 'normal'
can_change = True
for x in self.__z_order[control_id + 1:]:
if self.__control_list[x]['state'] == 'pressed':
can_change = False
break
# change the state to pressed
if can_change:
self.__control_list[control_id]['state'] = 'pressed'
self.__control_list[control_id]['mouse_pos_lclick'] = None
self.__control_list[control_id]['mouse_pos_ldown'] = mouse_pos
if self.__control_list[control_id]['on_hover_called']:
self.__draw_tip = None
if (time.clock() - self.__control_list[control_id][
'dbl_timer'] >= self.__dbl_click_delay) and \
(time.clock() - self.__control_list[control_id]['timer'] <= self.__dbl_click_speed):
if self.__event_mode:
if self.__control_list[control_id]['on_dbl_lclick']:
self.__control_list[control_id]['on_dbl_lclick']()
else:
self.__messages.append(self.Message(control_id, PGC_LBUTTONDBLCLK))
# print('Double click', self.__control_list[control_id]['text'])
self.__control_list[control_id]['dbl_timer'] = time.clock()
self.__control_list[control_id]['timer'] = -1
break
# go through the controls from top to bottom first
for control_id in reversed(self.__z_order):
state = self.__control_list[control_id]['state']
if state in ('deleted', 'disabled') or not self.__control_list[control_id]['draw']:
continue
# check if the mouse is over this control
if self.__control_list[control_id]['rect'].collidepoint(mouse_pos):
# left mouse is not down
if not button[0]:
# state is currently pressed
if state == 'pressed':
# check if there's a timer initiated for this control
# this prevents 2 clicks + a double click message
if self.__control_list[control_id]['timer'] >= 0:
self.__control_list[control_id]['dbl_timer'] = -1
self.__control_list[control_id]['timer'] = time.clock()
# if the event mode
if self.__event_mode:
# call the function if there is one
if self.__control_list[control_id]['on_lclick']:
self.__control_list[control_id]['on_lclick']()
else:
# post the message to the messages queue
self.__messages.append(self.Message(control_id, PGC_LBUTTONUP))
# print('Click', self.__control_list[control_id]['text'])
# the timer is < 0 (should be -1), double click just happened
else:
# reset the timer to 0 so clicking can happen again
self.__control_list[control_id]['timer'] = 0
# go through all of the ids below this control
for x in self.__z_order[0:control_id - 1]:
# set all the hot controls to normal
if self.__control_list[x]['state'] == 'hot':
self.__control_list[x]['state'] = 'normal'
can_change = True
# go through all the controls on top of this control
for x in self.__z_order[control_id + 1:]:
# something else is on top of this and it's already hot, can't change this control
if self.__control_list[x]['state'] == 'hot':
can_change = False
break
if can_change:
self.__control_list[control_id]['state'] = 'hot'
self.__control_list[control_id]['mouse_pos_lclick'] = mouse_pos
self.__control_list[control_id]['mouse_pos_ldown'] = None
# state is not currently hot (but we're hovering over this control)
elif state != 'hot':
# check for any other contorls
for x in self.__z_order[0:control_id - 1]:
if self.__control_list[x]['state'] == 'hot':
self.__control_list[x]['state'] = 'normal'
can_change = True
for x in self.__z_order[control_id + 1:]:
if self.__control_list[x]['state'] == 'hot':
can_change = False
break
# change the state to hot
if can_change:
self.__control_list[control_id]['state'] = 'hot'
self.__control_list[control_id]['mouse_pos_hover'] = mouse_pos
# used to start a tooltip (needs work)
self.__control_list[control_id]['mouse_pos_rect'] = pygame.Rect(mouse_pos[0] - 7,
mouse_pos[1] - 7,
mouse_pos[0] + 7,
mouse_pos[1] + 7)
# state is currently 'hot'
else:
# timer for on_hover hasn't been initialized
if self.__control_list[control_id]['timer_on_hover'] == 0:
self.__control_list[control_id]['timer_on_hover'] = time.clock()
# mouse is in the area
if self.__control_list[control_id]['mouse_pos_rect'].collidepoint(mouse_pos):
# if the on_hover hasn't been triggered and there is a timer for the on_hover
if not self.__control_list[control_id]['on_hover_called'] and self.__control_list[control_id]['timer_on_hover']:
# if the mouse has been in the hover area for 1.5 seconds or more
if time.clock() - self.__control_list[control_id]['timer_on_hover'] >= 1.5:
# trigger the hover
self.__control_list[control_id]['on_hover_called'] = True
# on_hover is a function call, call the function
if self.__control_list[control_id]['on_hover']['type'] == 'function':
self.__control_list[control_id]['on_hover']['func'](self.__control_list[control_id]['on_hover']['args'])
# on_hover is a tip, set the self.__draw_tip variable to the tip we need
else:
self.__draw_tip = self.__control_list[control_id]['on_hover'].copy()
self.__draw_tip['rect'].x = mouse_pos[0]
self.__draw_tip['rect'].y = mouse_pos[1]
# mouse is not in the control rect and the state is not currently normal
elif state != 'normal':
# set it to normal
self.__control_list[control_id]['state'] = 'normal'
# clear the on_hover stuff
if self.__control_list[control_id]['on_hover_called']:
self.__control_list[control_id]['on_hover_called'] = False
self.__draw_tip = None
if self.__control_list[control_id]['timer_on_hover']:
self.__control_list[control_id]['timer_on_hover'] = 0
(明天24小时超时后,将select作为正确答案)
终于搞清楚了。我太复杂了。
- 反向浏览控件列表,第一个 .collidepoint 成功的控件,保存该控件并打破循环
- 检查所有控件和一个未禁用且当前不正常的控件,设置为正常
根据需要使用已保存的控件
def process_events(self):
button = pygame.mouse.get_pressed()
mouse_pos = pygame.mouse.get_pos()
top_id = -1
for control_id in reversed(self.__z_order):
if self.__control_list[control_id]['state'] != 'disabled' and \
self.__control_list[control_id]['draw'] and \
self.__control_list[control_id]['rect'].collidepoint(mouse_pos):
top_id = control_id
break
if top_id != -1:
# go through all of the controls
for control_id in self.__z_order:
# skip the top most control and any that are disabled/deleted
if self.__control_list[control_id]['state'] != 'disabled' and \
self.__control_list[control_id]['state'] != 'normal' and \
control_id != top_id:
# set it to normal
self.__control_list[control_id]['state'] = 'normal'
# clear the on_hover stuff
if self.__control_list[control_id]['on_hover_called']:
self.__control_list[control_id]['on_hover_called'] = False
self.__draw_tip = None
if self.__control_list[control_id]['timer_on_hover']:
self.__control_list[control_id]['timer_on_hover'] = 0
else:
for control_id in self.__z_order:
if self.__control_list[control_id]['state'] != 'disabled':
# set it to normal
self.__control_list[control_id]['state'] = 'normal'
# clear the on_hover stuff
if self.__control_list[control_id]['on_hover_called']:
self.__control_list[control_id]['on_hover_called'] = False
self.__draw_tip = None
if self.__control_list[control_id]['timer_on_hover']:
self.__control_list[control_id]['timer_on_hover'] = 0
return
if button[0]:
# current state of this control is hot and left mouse is pressed on it
if self.__control_list[top_id]['state'] == 'hot':
self.__control_list[top_id]['state'] = 'pressed'
self.__control_list[top_id]['mouse_pos_lclick'] = None
self.__control_list[top_id]['mouse_pos_ldown'] = mouse_pos
if self.__control_list[top_id]['on_hover_called']:
self.__draw_tip = None
if (time.clock() - self.__control_list[top_id][
'dbl_timer'] >= self.__dbl_click_delay) and \
(time.clock() - self.__control_list[top_id]['timer'] <= self.__dbl_click_speed):
if self.__event_mode:
if self.__control_list[top_id]['on_dbl_lclick']:
self.__control_list[top_id]['on_dbl_lclick']()
else:
self.__messages.append(self.Message(top_id, PGC_LBUTTONDBLCLK))
# print('Double click', self.__control_list[top_id]['text'])
self.__control_list[top_id]['dbl_timer'] = time.clock()
self.__control_list[top_id]['timer'] = -1
elif not button[0]:
# state is currently pressed
if self.__control_list[top_id]['state'] == 'pressed':
# check if there's a timer initiated for this control
# this prevents 2 clicks + a double click message
if self.__control_list[top_id]['timer'] >= 0:
self.__control_list[top_id]['dbl_timer'] = -1
self.__control_list[top_id]['timer'] = time.clock()
# if the event mode
if self.__event_mode:
# call the function if there is one
if self.__control_list[top_id]['on_lclick']:
self.__control_list[top_id]['on_lclick']()
else:
# post the message to the messages queue
self.__messages.append(self.Message(top_id, PGC_LBUTTONUP))
# print('Click', self.__control_list[top_id]['text'])
# the timer is < 0 (should be -1), double click just happened
else:
# reset the timer to 0 so clicking can happen again
self.__control_list[top_id]['timer'] = 0
# go through all of the ids below this control
for x in self.__z_order[0:top_id - 1]:
# set all the hot controls to normal
if self.__control_list[x]['state'] == 'hot':
self.__control_list[x]['state'] = 'normal'
can_change = True
# go through all the controls on top of this control
for x in self.__z_order[top_id + 1:]:
# something else is on top of this and it's already hot, can't change this control
if self.__control_list[x]['state'] == 'hot':
can_change = False
break
if can_change:
self.__control_list[top_id]['state'] = 'hot'
self.__control_list[top_id]['mouse_pos_lclick'] = mouse_pos
self.__control_list[top_id]['mouse_pos_ldown'] = None
# state is not currently hot (but we're hovering over this control)
elif self.__control_list[top_id]['state'] != 'hot':
self.__control_list[top_id]['state'] = 'hot'
self.__control_list[top_id]['mouse_pos_hover'] = mouse_pos
# used to start a tooltip (needs work)
self.__control_list[top_id]['mouse_pos_rect'] = pygame.Rect(mouse_pos[0] - 7,
mouse_pos[1] - 7,
mouse_pos[0] + 7,
mouse_pos[1] + 7)
# state is currently 'hot'
else:
# timer for on_hover hasn't been initialized
if self.__control_list[top_id]['timer_on_hover'] == 0:
self.__control_list[top_id]['timer_on_hover'] = time.clock()
# mouse is in the area
if self.__control_list[top_id]['mouse_pos_rect'].collidepoint(mouse_pos):
# if the on_hover hasn't been triggered and there is a timer for the on_hover
if not self.__control_list[top_id]['on_hover_called'] and \
self.__control_list[top_id]['timer_on_hover']:
# if the mouse has been in the hover area for 1.5 seconds or more
if time.clock() - self.__control_list[top_id]['timer_on_hover'] >= 1.5:
# trigger the hover
self.__control_list[top_id]['on_hover_called'] = True
# on_hover is a function call, call the function
if self.__control_list[top_id]['on_hover']['type'] == 'function':
self.__control_list[top_id]['on_hover']['func'] \
(self.__control_list[top_id]['on_hover']['args'])
# on_hover is a tip, set the self.__draw_tip variable to the tip we need
else:
self.__draw_tip = self.__control_list[top_id]['on_hover'].copy()
self.__draw_tip['rect'].x = mouse_pos[0]
self.__draw_tip['rect'].y = mouse_pos[1]
我正在 pygame 中创建控件(仅完成按钮和标签,以及为控件设置工具提示)。我正在以正确的 Z 顺序绘制控件,但我正在尝试检测鼠标是否在另一个控件上,因此它只会激活可见的控件。
如果您删除 test.set_on_bottom(btnButton7),这在一定程度上会起作用,它只会触发 button7,即使鼠标位于其下方的其中一个按钮上,但如果您单击下方的其中一个按钮button7 并将鼠标移到 button7 上它仍然认为原始按钮正在被点击(当它不应该被点击时)
几天来我一直在为这个问题绞尽脑汁,但就是想不通。
(另外,我今天早上才想到,但我应该把每个控件都变成一个 class 而不是一个 id,所以稍后会重新处理)
代码太长post,这里是pastebin link
设置状态和触发消息的所有处理都在 process_events 方法中完成
def process_events(self):
button = pygame.mouse.get_pressed()
mouse_pos = pygame.mouse.get_pos()
for control_id in reversed(self.__z_order):
state = self.__control_list[control_id]['state']
if state in ('deleted', 'disabled') or not self.__control_list[control_id]['draw']:
continue
if self.__control_list[control_id]['rect'].collidepoint(mouse_pos):
# left mouse is pressed
if button[0]:
# current state of this control is hot and left mouse is pressed on it
if state == 'hot':
for x in self.__z_order[0:control_id - 1]:
if self.__control_list[x]['state'] == 'pressed':
self.__control_list[x]['state'] = 'normal'
can_change = True
for x in self.__z_order[control_id + 1:]:
if self.__control_list[x]['state'] == 'pressed':
can_change = False
break
# change the state to pressed
if can_change:
self.__control_list[control_id]['state'] = 'pressed'
self.__control_list[control_id]['mouse_pos_lclick'] = None
self.__control_list[control_id]['mouse_pos_ldown'] = mouse_pos
if self.__control_list[control_id]['on_hover_called']:
self.__draw_tip = None
if (time.clock() - self.__control_list[control_id][
'dbl_timer'] >= self.__dbl_click_delay) and \
(time.clock() - self.__control_list[control_id]['timer'] <= self.__dbl_click_speed):
if self.__event_mode:
if self.__control_list[control_id]['on_dbl_lclick']:
self.__control_list[control_id]['on_dbl_lclick']()
else:
self.__messages.append(self.Message(control_id, PGC_LBUTTONDBLCLK))
# print('Double click', self.__control_list[control_id]['text'])
self.__control_list[control_id]['dbl_timer'] = time.clock()
self.__control_list[control_id]['timer'] = -1
break
# go through the controls from top to bottom first
for control_id in reversed(self.__z_order):
state = self.__control_list[control_id]['state']
if state in ('deleted', 'disabled') or not self.__control_list[control_id]['draw']:
continue
# check if the mouse is over this control
if self.__control_list[control_id]['rect'].collidepoint(mouse_pos):
# left mouse is not down
if not button[0]:
# state is currently pressed
if state == 'pressed':
# check if there's a timer initiated for this control
# this prevents 2 clicks + a double click message
if self.__control_list[control_id]['timer'] >= 0:
self.__control_list[control_id]['dbl_timer'] = -1
self.__control_list[control_id]['timer'] = time.clock()
# if the event mode
if self.__event_mode:
# call the function if there is one
if self.__control_list[control_id]['on_lclick']:
self.__control_list[control_id]['on_lclick']()
else:
# post the message to the messages queue
self.__messages.append(self.Message(control_id, PGC_LBUTTONUP))
# print('Click', self.__control_list[control_id]['text'])
# the timer is < 0 (should be -1), double click just happened
else:
# reset the timer to 0 so clicking can happen again
self.__control_list[control_id]['timer'] = 0
# go through all of the ids below this control
for x in self.__z_order[0:control_id - 1]:
# set all the hot controls to normal
if self.__control_list[x]['state'] == 'hot':
self.__control_list[x]['state'] = 'normal'
can_change = True
# go through all the controls on top of this control
for x in self.__z_order[control_id + 1:]:
# something else is on top of this and it's already hot, can't change this control
if self.__control_list[x]['state'] == 'hot':
can_change = False
break
if can_change:
self.__control_list[control_id]['state'] = 'hot'
self.__control_list[control_id]['mouse_pos_lclick'] = mouse_pos
self.__control_list[control_id]['mouse_pos_ldown'] = None
# state is not currently hot (but we're hovering over this control)
elif state != 'hot':
# check for any other contorls
for x in self.__z_order[0:control_id - 1]:
if self.__control_list[x]['state'] == 'hot':
self.__control_list[x]['state'] = 'normal'
can_change = True
for x in self.__z_order[control_id + 1:]:
if self.__control_list[x]['state'] == 'hot':
can_change = False
break
# change the state to hot
if can_change:
self.__control_list[control_id]['state'] = 'hot'
self.__control_list[control_id]['mouse_pos_hover'] = mouse_pos
# used to start a tooltip (needs work)
self.__control_list[control_id]['mouse_pos_rect'] = pygame.Rect(mouse_pos[0] - 7,
mouse_pos[1] - 7,
mouse_pos[0] + 7,
mouse_pos[1] + 7)
# state is currently 'hot'
else:
# timer for on_hover hasn't been initialized
if self.__control_list[control_id]['timer_on_hover'] == 0:
self.__control_list[control_id]['timer_on_hover'] = time.clock()
# mouse is in the area
if self.__control_list[control_id]['mouse_pos_rect'].collidepoint(mouse_pos):
# if the on_hover hasn't been triggered and there is a timer for the on_hover
if not self.__control_list[control_id]['on_hover_called'] and self.__control_list[control_id]['timer_on_hover']:
# if the mouse has been in the hover area for 1.5 seconds or more
if time.clock() - self.__control_list[control_id]['timer_on_hover'] >= 1.5:
# trigger the hover
self.__control_list[control_id]['on_hover_called'] = True
# on_hover is a function call, call the function
if self.__control_list[control_id]['on_hover']['type'] == 'function':
self.__control_list[control_id]['on_hover']['func'](self.__control_list[control_id]['on_hover']['args'])
# on_hover is a tip, set the self.__draw_tip variable to the tip we need
else:
self.__draw_tip = self.__control_list[control_id]['on_hover'].copy()
self.__draw_tip['rect'].x = mouse_pos[0]
self.__draw_tip['rect'].y = mouse_pos[1]
# mouse is not in the control rect and the state is not currently normal
elif state != 'normal':
# set it to normal
self.__control_list[control_id]['state'] = 'normal'
# clear the on_hover stuff
if self.__control_list[control_id]['on_hover_called']:
self.__control_list[control_id]['on_hover_called'] = False
self.__draw_tip = None
if self.__control_list[control_id]['timer_on_hover']:
self.__control_list[control_id]['timer_on_hover'] = 0
(明天24小时超时后,将select作为正确答案)
终于搞清楚了。我太复杂了。
- 反向浏览控件列表,第一个 .collidepoint 成功的控件,保存该控件并打破循环
- 检查所有控件和一个未禁用且当前不正常的控件,设置为正常
根据需要使用已保存的控件
def process_events(self): button = pygame.mouse.get_pressed() mouse_pos = pygame.mouse.get_pos() top_id = -1 for control_id in reversed(self.__z_order): if self.__control_list[control_id]['state'] != 'disabled' and \ self.__control_list[control_id]['draw'] and \ self.__control_list[control_id]['rect'].collidepoint(mouse_pos): top_id = control_id break if top_id != -1: # go through all of the controls for control_id in self.__z_order: # skip the top most control and any that are disabled/deleted if self.__control_list[control_id]['state'] != 'disabled' and \ self.__control_list[control_id]['state'] != 'normal' and \ control_id != top_id: # set it to normal self.__control_list[control_id]['state'] = 'normal' # clear the on_hover stuff if self.__control_list[control_id]['on_hover_called']: self.__control_list[control_id]['on_hover_called'] = False self.__draw_tip = None if self.__control_list[control_id]['timer_on_hover']: self.__control_list[control_id]['timer_on_hover'] = 0 else: for control_id in self.__z_order: if self.__control_list[control_id]['state'] != 'disabled': # set it to normal self.__control_list[control_id]['state'] = 'normal' # clear the on_hover stuff if self.__control_list[control_id]['on_hover_called']: self.__control_list[control_id]['on_hover_called'] = False self.__draw_tip = None if self.__control_list[control_id]['timer_on_hover']: self.__control_list[control_id]['timer_on_hover'] = 0 return if button[0]: # current state of this control is hot and left mouse is pressed on it if self.__control_list[top_id]['state'] == 'hot': self.__control_list[top_id]['state'] = 'pressed' self.__control_list[top_id]['mouse_pos_lclick'] = None self.__control_list[top_id]['mouse_pos_ldown'] = mouse_pos if self.__control_list[top_id]['on_hover_called']: self.__draw_tip = None if (time.clock() - self.__control_list[top_id][ 'dbl_timer'] >= self.__dbl_click_delay) and \ (time.clock() - self.__control_list[top_id]['timer'] <= self.__dbl_click_speed): if self.__event_mode: if self.__control_list[top_id]['on_dbl_lclick']: self.__control_list[top_id]['on_dbl_lclick']() else: self.__messages.append(self.Message(top_id, PGC_LBUTTONDBLCLK)) # print('Double click', self.__control_list[top_id]['text']) self.__control_list[top_id]['dbl_timer'] = time.clock() self.__control_list[top_id]['timer'] = -1 elif not button[0]: # state is currently pressed if self.__control_list[top_id]['state'] == 'pressed': # check if there's a timer initiated for this control # this prevents 2 clicks + a double click message if self.__control_list[top_id]['timer'] >= 0: self.__control_list[top_id]['dbl_timer'] = -1 self.__control_list[top_id]['timer'] = time.clock() # if the event mode if self.__event_mode: # call the function if there is one if self.__control_list[top_id]['on_lclick']: self.__control_list[top_id]['on_lclick']() else: # post the message to the messages queue self.__messages.append(self.Message(top_id, PGC_LBUTTONUP)) # print('Click', self.__control_list[top_id]['text']) # the timer is < 0 (should be -1), double click just happened else: # reset the timer to 0 so clicking can happen again self.__control_list[top_id]['timer'] = 0 # go through all of the ids below this control for x in self.__z_order[0:top_id - 1]: # set all the hot controls to normal if self.__control_list[x]['state'] == 'hot': self.__control_list[x]['state'] = 'normal' can_change = True # go through all the controls on top of this control for x in self.__z_order[top_id + 1:]: # something else is on top of this and it's already hot, can't change this control if self.__control_list[x]['state'] == 'hot': can_change = False break if can_change: self.__control_list[top_id]['state'] = 'hot' self.__control_list[top_id]['mouse_pos_lclick'] = mouse_pos self.__control_list[top_id]['mouse_pos_ldown'] = None # state is not currently hot (but we're hovering over this control) elif self.__control_list[top_id]['state'] != 'hot': self.__control_list[top_id]['state'] = 'hot' self.__control_list[top_id]['mouse_pos_hover'] = mouse_pos # used to start a tooltip (needs work) self.__control_list[top_id]['mouse_pos_rect'] = pygame.Rect(mouse_pos[0] - 7, mouse_pos[1] - 7, mouse_pos[0] + 7, mouse_pos[1] + 7) # state is currently 'hot' else: # timer for on_hover hasn't been initialized if self.__control_list[top_id]['timer_on_hover'] == 0: self.__control_list[top_id]['timer_on_hover'] = time.clock() # mouse is in the area if self.__control_list[top_id]['mouse_pos_rect'].collidepoint(mouse_pos): # if the on_hover hasn't been triggered and there is a timer for the on_hover if not self.__control_list[top_id]['on_hover_called'] and \ self.__control_list[top_id]['timer_on_hover']: # if the mouse has been in the hover area for 1.5 seconds or more if time.clock() - self.__control_list[top_id]['timer_on_hover'] >= 1.5: # trigger the hover self.__control_list[top_id]['on_hover_called'] = True # on_hover is a function call, call the function if self.__control_list[top_id]['on_hover']['type'] == 'function': self.__control_list[top_id]['on_hover']['func'] \ (self.__control_list[top_id]['on_hover']['args']) # on_hover is a tip, set the self.__draw_tip variable to the tip we need else: self.__draw_tip = self.__control_list[top_id]['on_hover'].copy() self.__draw_tip['rect'].x = mouse_pos[0] self.__draw_tip['rect'].y = mouse_pos[1]