Я создаю программное обеспечение, в котором есть поток, который запускается при нажатии кнопки. Но я не могу остановить его, даже если он находится в цикле условного времени

#python #multithreading #python-3.9

Вопрос:

Я пытаюсь создать программное обеспечение для сопоставления клавиш, в нем есть кнопка, которая активирует сопоставление клавиш, которое в основном запускает поток, вызывающий функцию, у которой есть условный цикл, проверяющий нажатия клавиш. Но проблема в том, что даже если я устанавливаю глобальную переменную в значение false с помощью кнопки, поток не прекращается, пока я не нажму клавишу на клавиатуре.

это немного расстраивает.. так как вы думаете, что сопоставление клавиш деактивировано, но затем вы пытаетесь закрыть программное обеспечение или пытаетесь активировать другое сопоставление клавиш, оно показывает вам ошибку, и как только вы нажимаете клавишу, чтобы что-то ввести, курсор щелкает по экрану, и вы получаете всплывающее окно, в котором теперь ваше сопоставление клавиш деактивировано…..

вот мой код…. есть какие-нибудь предложения?????

Функция сопоставления Клавиш

 def keymapping():
    
    tree.bind('<Return>',func=lambda event=None:())
    
    global active
    global keymapping_running
    global x_cor
    global y_cor
    global start_range
    global end_range
    global selected
    global selected_iid
    global keymap_name
    
    keymapping_running = True
    
    while active:
        
        key = str(keyboard.read_key()).capitalize()
        
        x = int(str(mouse.get_position()).split('(')[1].split(',')[0])
        y = int(str(mouse.get_position()).split(')')[0].split(', ')[1])
                
        for i in saves[start_range 1:end_range 1]:
            i = str(i).split(" = ")
            if i[0] == key:
                x_cor = int(i[1].split(',')[0])
                y_cor = int(i[1].split(',')[1])
        
        if x_cor and y_cor: 
            
            mouse.move(x_cor-x,y_cor-y,absolute=False,duration=0.01)
            mouse.click('left')
    
            x_cor = 0
            y_cor = 0
            
        else:
            if keyboard.is_pressed('F9'):
                button_switch()
            
            elif keyboard.is_pressed('return'):
                
                if keyboard.is_pressed('return'):
                    pass
                
                if tree.selection() == ():
                    pass
                else:
                    app.wm_attributes("-topmost", 1)
                    tmsg.showerror("Already running",f"'{keymap_name}' is already running.")
                    app.wm_attributes("-topmost", 0)
            
            else:
                pass
                        
    tree.bind('<Return>',func=lambda event=None:button_switch())

    keymapping_running = False
    x_cor = 0
    y_cor = 0
    selected = ''
    selected_iid = ''
    app.wm_attributes("-topmost", 1)
    tmsg.showinfo("Keymapping Deactivated",f"'{keymap_name}' has been deactivated")
    app.wm_attributes("-topmost", 0)
    keymap_name = ''
 

Функция кнопки Включения/Выключения

 def button_switch():
    
    global active
    global keymap_name
    global selected
    global selected_iid
    
    if active:
        tree.item(selected,image=close_img)
        
        active_btn.config(image=on_img)
        active_btn_lbl.config(text='  Activate Keymapping  ')
        active = False
        
    else:
        
        if (not keymapping_running):
            
            if keymap:
                
                selected = tree.focus()
                
                if selected != '':
                    
                    selected_iid = tree.selection()
                    
                    if len(selected_iid) == 1:
                        
                        try:   
                            keymap_name = tree.item(selected,'values')[0]
                            for j in saves:
                                if str(j).split(' :- ')[0] == str(already_keymap_names[int(str(selected_iid).split(",")[0].split("'")[1])]).split(" :- ")[0]:
                                    global start_range
                                    start_range = saves.index(j) 
                                    global end_range
                                    end_range = start_range   int(str(saves[start_range]).split(" :- ")[1].split('(')[1].split(')')[0])     
            
                            active = True 
                            active_btn.config(image=stop_img)
                            tree.item(selected,image=done_img)
                            active_btn_lbl.config(text='Deactivate Keymapping')
                                                   
                            th = threading.Thread(target=keymapping)
                            th.start()
                            
                            tree.selection_remove(tree.focus())
                            
                            app.wm_attributes("-topmost", 1)
                            tmsg.showinfo("Keymapping Activated",f"'{keymap_name}' has been activated")
                            app.wm_attributes("-topmost", 0)
                        
                        except Exception as e:
                            print(e)
                            app.wm_attributes("-topmost", 1)
                            tmsg.showerror("Tampering",f"There has been tampering with the 'Saved_Keymappings.dll' and we are unable to fetch '{keymap_name}'")
                            app.wm_attributes("-topmost", 0)
                    
                    elif len(selected_iid) == 0:
                        app.wm_attributes("-topmost", 1)
                        tmsg.showerror('Nothing selected','Please select a keymapping to activate.')
                        app.wm_attributes("-topmost", 0)
                    
                    else:
                        app.wm_attributes("-topmost", 1)
                        tmsg.showerror("Multiple Selected","You can't run multiple Keymappings together.")
                        app.wm_attributes("-topmost", 0)
                
                else:
                    app.wm_attributes("-topmost", 1)
                    tmsg.showerror('Nothing selected','Please select a keymapping to activate.')
                    app.wm_attributes("-topmost", 0)
            
            else:
                app.wm_attributes("-topmost", 1)
                tmsg.showerror("Nothing to Activate","You have no saved keymappings to activate.nnPlaese create a new keymapping before Activating")
                app.wm_attributes("-topmost", 0)
                
        else:
            app.wm_attributes("-topmost", 1)
            tmsg.showerror("Already running",f"'{keymap_name}' is already running.")
            app.wm_attributes("-topmost", 0)
                
 

Ответ №1:

Не сказать, что интерфейс API, который вы используете (это tkinter ?), но в большинстве кнопки-работа с GUI API-интерфейсов выполняется внутри цикла событий графического интерфейса, который вызывает обратные вызовы на ваш код, когда происходит событие, и ваш обратный вызов должен немедленно вернуться так, что событие-петля можете contintue обработки нескольких событий. Поэтому, если ваш обратный вызов содержит while цикл, который не позволяет ему немедленно вернуться, код обработки событий API графического интерфейса заблокирован для запуска и, следовательно, не выполняет/не может выполнять задачи обработки событий, которые вы ожидаете от него.

Решение: убедитесь, что ваши обратные вызовы всегда возвращают сразу — в частности, не на неопределенный срок-длина while петли внутри вашего обратного вызова; но государство-член-переменную(ы) в вашем классе, чтобы «запомнить», что вы находитесь в середине текущего события, так что в будущем обратных вызовов можете изучить эти члены-переменные, чтобы знать, как поступить правильно.