Z Ordering Controls,控件顶部和底部的碰撞检测

时间:2017-04-29 19:36:45

标签: python pygame controls custom-controls z-order

我正在使用pygame创建控件(按钮和标签是唯一完成的,以及为控件设置工具提示)。我正在以正确的Z顺序绘制控件,但我试图检测到鼠标没有超过另一个控件,所以它只激活可见的那个。

如果删除test.set_on_bottom(btnButton7),这有点有效,即使鼠标位于其下方的一个按钮上,它也只会触发button7,但是如果你点击button7下方的一个按钮并移动鼠标悬停在button7上,它仍然认为原始按钮被点击(当它不应该被点击时)

现在围绕这个问题缠绕我的大脑几天了,我只是看不清楚。

(另外,我今天早上只考虑过这个问题,但是我应该把每个控件都变成一个类而不是一个id,所以这将在以后重新编写)

代码太长而无法发布,这里是pastebin link

设置状态和触发消息的所有处理都在process_events方法

中完成
<Button x:Name="ChestTotal" Text="{Binding ChestAmount}" BackgroundColor="{Binding ChestAmount, Converter={StaticResource intToColor}}" TextColor="White" WidthRequest="150"></Button>

1 个答案:

答案 0 :(得分:0)

(明天将在24小时超时后选择正确答案)

结束搞清楚。我让它复杂化了。

  1. 反过来查看控件列表,第一个.collidepoint成功的控件,保存该控件并打破循环
  2. 浏览所有控件和未禁用且当前不正常的控件,设置为正常
  3. 使用已根据需要保存的控件

    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]