@LanixGame

Кнопка включения и выключения Python?

Вот мой код:

import sys
import os
import customtkinter
import tkinter
import random
import runpy
import subprocess
from subprocess import call

customtkinter.set_appearance_mode("white")  # Modes: system (default), light, dark
customtkinter.set_default_color_theme("blue")
 

 
window = customtkinter.CTk()
window.title('Pet Clicker III')
window.geometry('600x600')


def RebithFunc():
    import AutoRebith

btn_clicker = customtkinter.CTkCheckBox(window, text='AutoClicker')
btn_clicker.place(x=350, y=150)
 
btn_Rebith = customtkinter.CTkCheckBox(window, text='AutoRebith', command=RebithFunc)
btn_Rebith.place(x=150, y=150)

#btn_clear = customtkinter.CTkCheckBox(window, text='AutoClicker')
#btn_clear.place(x=350, y=150)
 
#btn_generate = customtkinter.CTkCheckBox(window, text='AutoRebith')
#btn_generate.place(x=150, y=150)

 
window.mainloop()

Мне нужно что бы при включении и выключении CTkCheckBox скрипт включался и выключался.
Точнее когда я нажму на галочку скрипт включится а когда уберу её выключится.
Я искал в интернете как это сделать но данный способ устарел.
  • Вопрос задан
  • 491 просмотр
Пригласить эксперта
Ответы на вопрос 1
Vindicar
@Vindicar
RTFM!
При текущем устрйостве кода - никак.
Я так понимаю, ты просто выполняешь скрипт AutoRebith, и больше с ним никак не взаимодействуешь. Поэтому и сказать ему "стоп" ты не можешь. Не зная, что творится в том скрипте, сказать ничего нельзя, но кое-что я всё же подскажу.

1. Для работы оконного интерфейса поток приложения (обычно главный поток, в котором исполняется тело программы) должен выполнять цикл обработки сообщений. В твоём случае этот цикл спрятан в методе window.mainloop(). Но как следствие, нельзя выполнять длительные действия в обработчиках событий интерфейса! Т.е. по нажатию на кнопку нельзя просто взять и заняться чем-то на полчасика - окно программы на это время перестанет отвечать.
Так что тебе придётся вытащить твою секретную операцию в отдельный поток выполнения, например, через модуль threading. Про это надо читать. Но тут ждёт вторая подстава - оконные приложения не любят обращения к элементам из нескольких потоков. Наладить общение между интерфейсом и потоком - отдельная задача.

2. Прервать поток - задача тоже непростая. Есть средства принудительной остановки, но они легко могут покорёжить остальную программу. Так что тебе придётся переделать свой секретный скрипт так, чтобы ему можно было сказать "стоп". А для этого надо будет как минимум завернуть операцию в класс.

Могу показать упрощённый пример, как это делается. Но его нужно будет подгонять под свою задачу, и да, твой код придётся переписать почти с нуля.
Пример
import threading
import tkinter
from tkinter import ttk
import time

# Этот класс описывает длительную операцию, выполняемую в потоке.
class LongRunningOperation(threading.Thread):
    # если твоя операция требует аргументы, они передаются через конструктор
    def __init__(self, my_argument):
        super().__init__(daemon=True)  # если главный поток завершился, мы тоже должны
        self._my_argument = my_argument  # и сохраняются в self
        self._stop_flag = threading.Event()  # а это - признак "Пора останавливаться"
        self._progress = 0  # эта переменная отслеживает прогресс
        # этот объект гарантирует, что наш и внешний потоки не будут трогать self._progress одновременно
        self._progress_lock = threading.Lock()  
    
    # От threading.Thread() мы унаследуем два важных метода
    #     start() вызывается снаружи потока и запускает наш поток
    #     wait() вызывается снаружи потока и ждёт, пока наш поток не остановится
    
    # Этот метод вызывается снаружи потока и сигнализирует об остановке
    # Но остановиться поток должен будет сам
    def stop(self):
        self._stop_flag.set()  # threading.Event безопасен для использования несколькими потоками.
    
    # Этот метод вызывается снаружи потока и позволяет узнать прогресс длительной операции
    def get_progress(self):
        with self._progress_lock:  # любые обращения к self._progress заворачиваются в такой блок
            # вообще, для чисел Lock не требуется. Но если ты хочешь сообщать что-то большее, это надо делать.
            return self._progress
    
    # Тело этого метода будет выполняться в отдельном потоке.
    # Именно этот метод реализует длительную операцию.
    def run(self):
        # я не знаю, что творится у тебя в коде. 
        # Тебе придётся адаптировать свой код под этот шаблон.
        self._progress = 0
        self._stop_flag.clear()
        print('Operation started')
        while not self._stop_flag.is_set():  # пока нам не сказали остановиться
            # Тут ты выполняешь порцию своей длительной работы. Например, одну итерацию цикла.
            print('Operation with my_argument =', self._my_argument)
            time.sleep(0.1)  # это просто для примера - ждём 0.1 секунды. 
            # Выше ты выполняешь порцию своей длительной работы. Например, одну итерацию цикла.
            with self._progress_lock:
                self._progress += 1  # наращиваем прогресс
                if self._progress == 100:
                    # в данном случае прерываем цикл, если прогресс дошел до 100 - дело сделано
                    # если у тебя цикл "пока снаружи не остановят", то условие и break можно убрать
                    break  
        print('Operation stopped')


class MainWindow(tkinter.Tk):  # окно приложения
    def __init__(self):
        super().__init__()
        self._operation = None  # а вот тут будет храниться экземпляр класса LongRunningOperation

        self.title('Pet Clicker III')
        self.geometry('600x600')
        
        self._progress = tkinter.IntVar()  # переменная для прогресса в окне
        # прогрессбар подхватит эту переменную, так как мы её указали в параметрах
        self._progressbar = ttk.Progressbar(self, maximum=100, variable=self._progress, mode='determinate')
        self._progressbar.pack(side='top', expand=True, fill='x')
        
        self._button = tkinter.Button(self, text='Start', command=self._start_stop)  # кнопка пуск/стоп
        self._button.pack(side='top', expand=True, fill='x')
        
        self.after(500, self._check_progress)  # через 500 мс надо вызвать _check_progress()
        
    def _check_progress(self):  # показывает прогерсс операции в окне, если есть что показывать
        if self._operation is not None:  # операция сейчас выполняется?
            progress = self._operation.get_progress()
            self._progress.set(progress)  # задаём новое значение прогресса
            if not self._operation.is_alive():  # поток уже остановился?
                self._progress.set(0)  # сбрасываем прогресс
                self._button.config(text='Start')  # переименовываем кнопку
                self._operation = None  # забываем про объект операции
        self.after(500, self._check_progress)  # ещё через 500 мс вызовем функцию снова
    
    def _start_stop(self):  # запускает или останавливает операцию
        if self._operation is None:  # операции нет - запускаем её
            self._operation = LongRunningOperation(42)  # передаём аргументы в операцию. В нашем случае my_argument = 42.
            self._progress.set(0)  # сбрасываем прогресс
            self._button.config(text='Stop')  # переименовываем кнопку
            self._operation.start()  # запускаем второй поток, который будет выполнять операцию
        else:  # операция уже запущена - останавливаем её
            self._operation.stop()  # даём сигнал "остановись"
            self._operation.join()  # ждём, пока она действительно не остановится
            self._progress.set(0)  # сбрасываем прогресс
            self._button.config(text='Start')  # переименовываем кнопку
            self._operation = None  # забываем про объект операции

wnd = MainWindow()
wnd.mainloop()
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы