Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/355.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Z排序控件,控件顶部和底部的碰撞检测_Python_Pygame_Controls_Custom Controls_Z Order - Fatal编程技术网

Python Z排序控件,控件顶部和底部的碰撞检测

Python Z排序控件,控件顶部和底部的碰撞检测,python,pygame,controls,custom-controls,z-order,Python,Pygame,Controls,Custom Controls,Z Order,我正在pygame中创建控件(按钮和标签是唯一完成的,并且为控件设置工具提示)。我以正确的Z顺序绘制控件,但我试图检测鼠标是否在另一个控件上,因此它只激活可见的控件 这在一定程度上是有效的,如果您删除了测试。在底部设置按钮(btnButton7),即使鼠标位于按钮下方的一个按钮上,它也只会触发按钮7,但如果您单击按钮7下方的一个按钮并将鼠标移到按钮7上,它仍然认为原始按钮正在被单击(不应该) 这几天来我一直在思考这个问题,但我就是看不懂怎么解决它 (另外,我今天早上刚刚考虑过,但我应该将每个控件

我正在pygame中创建控件(按钮和标签是唯一完成的,并且为控件设置工具提示)。我以正确的Z顺序绘制控件,但我试图检测鼠标是否在另一个控件上,因此它只激活可见的控件

这在一定程度上是有效的,如果您删除了测试。在底部设置按钮(btnButton7),即使鼠标位于按钮下方的一个按钮上,它也只会触发按钮7,但如果您单击按钮7下方的一个按钮并将鼠标移到按钮7上,它仍然认为原始按钮正在被单击(不应该)

这几天来我一直在思考这个问题,但我就是看不懂怎么解决它

(另外,我今天早上刚刚考虑过,但我应该将每个控件都转换为一个类而不是一个id,所以稍后会对其进行修改)

代码太长,无法发布,下面是

设置状态和触发消息的所有处理都在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
def进程_事件(自):
button=pygame.mouse.get_pressed()
mouse\u pos=pygame.mouse.get\u pos()
对于反向控制id(自身顺序):
state=self.\u控制列表[control\u id]['state']
如果状态为('deleted'、'disabled')或非self.\u control\u列表[控件id]['draw']:
持续
如果self.\u control\u list[control\u id]['rect'].collidepoint(鼠标位置):
#按下鼠标左键
如果按钮[0]:
#此控件的当前状态为“热”,并按下鼠标左键
如果状态==“热”:
对于self.\u z\u顺序中的x[0:控件\u id-1]:
如果self.\u control\u list[x]['state']=='pressed':
自我控制列表[x][“状态”]=“正常”
能改变吗
对于self.\u z\u顺序中的x[控制id+1:]:
如果self.\u control\u list[x]['state']=='pressed':
可以改变吗
打破
#将状态更改为“已按下”
如果您可以更改:
self.\u control\u list[control\u id]['state']='pressed'
self.\u control\u list[control\u id]['mouse\u pos\u lclick']=无
self.\u control\u list[control\u id]['mouse\u pos\u ldown']=鼠标位置
如果self.\u control\u列表[控件id]['在悬停时调用']:
自绘制提示=无
if(time.clock()-self.\u控制\u列表[控制\u id][
'dbl\u timer']>=self.\uu dbl\u单击\u延迟)和\
(time.clock()-self.\u控制列表[control\u id]['timer']=1.5:
#触发悬停
self.\u control\u list[control\u id]['on\u hover\u called']=True
#悬停是函数调用,调用函数
如果self.\u control\u list[control\u id]['on\u hover']['type']=='function':
self.\u控制列表[control\u id]['on\u hover']['func'](self.\u控制列表[control\u id]['on\u hover']['args'])
#悬停是一个提示,将self.\u draw\u tip变量设置为我们需要的提示
其他:
self.\uuu draw\u tip=self.\uu control\u list[control\u id]['on\u hover'].copy()
self.\u draw\u tip['rect'].x=鼠标位置[0]
self.\u draw\u tip['rect'].y=鼠标位置[1]
#鼠标不在控件矩形中,当前状态不正常
elif状态!=“正常”:
#将其设置为正常
self.\u control\u list[control\u id]['state']='normal'
#清除悬停上的东西
如果self.\u control\u列表[控件id]['在悬停时调用']:
self.\u control\u list[control\u id]['on\u hover\u called']=False
自绘制提示=无
如果self.\u control\u列表[控件id]['timer\u on\u hover']:
self.\u控制列表[control\u id]['timer\u on\u hover']=0
(明天24小时超时结束时将选择正确答案)

最后我终于弄明白了,我把事情复杂化了

  • 反向浏览控件列表,.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]
    
    def进程_事件(自):
    button=pygame.mouse.get_pressed()
    mouse\u pos=pygame.mouse.get\u pos()
    top_id=-1
    对于反向控制id(自身顺序):
    如果自我控制列表[控制id][“状态”!=“禁用”和\
    自我控制列表[控制id]['draw']和\
    self.\u control\u list[control\u id]['rect'].碰撞点(鼠标位置):
    top\u id=控制\u id
    打破
    如果top_id!=-1:
    #检查所有的控制装置
    对于以self.\u z_顺序显示的控制id:
    #跳过最顶端的控件和任何已禁用/删除的控件
    如果自我控制列表[控制id][“状态”!=“禁用”和\
    self.\u control\u list[control\u id]['state'!='normal'和\
    控件id!=顶部id:
    #将其设置为正常
    self.\u control\u list[control\u id]['state']='normal'
    #清除悬停上的东西
    如果self.\u control\u列表[控件id]['在悬停时调用']:
    self.\u control\u list[control\u id]['on\u hover\u called']=False
    自绘制提示=无
    如果是自控制列表[contro