Ответы пользователя по тегу Tkinter
  • Как сделать анимацию загрузки при условии на python tkinter?

    Vindicar
    @Vindicar
    RTFM!
    1. Подумать.
    2. Сделать.

    А если серьёзно, вынеси загрузку в отдельный поток, в идеале - обёрнутый в класс. Поток НЕ ДОЛЖЕН обращаться напрямую к элементам интерфейса - только к полям своего класса.
    По нажатию кнопки запускай этот поток. Только запуск, без ожидания.

    Чтобы обнаружить завершение, после запуска потока сделай цикл с помощью window.after(). Подробности в доках, но если кратко, метод after() позволяет вызвать функцию в потоке GUI спустя некоторое время. При этом функция может снова запланировать свой вызов через after(), тем самым создавая как-бы цикл. Если не запланируешь новый вызов - цикл прервётся.
    Соответственно, идея в том, что эта функция будет проверять, не закончил ли поток работу (например, читать какое-нибудь логическое значение). Если закончил - она будет вправе обратиться к элементам GUI, чтобы вывести результат. Если не закончил - она снова запланирует свой вызов через after(), скажем, через 200 миллисекунд.

    Ну и да - исключения, чёрт побери! Обрабатывай исключения!
    Ответ написан
    2 комментария
  • Кнопка включения и выключения Python?

    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()
    Ответ написан
  • Как подсвечивать разными цветами текст в виджете text tkinter?

    Vindicar
    @Vindicar
    RTFM!
    1. Почитать документацию о том как работают теги. В частности, методы tag_add(), tag_remove() и tag_config().
    2. Сделать простой пример, чтобы убедиться, что ты понял, как оно работает.
    3. Применить в своём проекте.
    Ответ написан
  • Как задать значение по умолчанию для всех созданных combobox в Tkinter?

    Vindicar
    @Vindicar
    RTFM!
    По итогам ряда экспериментов у меня получилось следующее...

    Когда ты ставишь ссылку на переменную Tk (например, экземпляр StringVar) для элемента управления, элемент запоминает внутреннее имя этой переменной (если ты его не задал явно, оно будет иметь вид PY_VAR*), а не хранит ссылку на сам экземпляр класса StringVar. Поэтому переменная умирает, когда значение питоновской переменной value перезаписывается на следующей итерации, что ломает логику работы.
    Ты должен сам хранить ссылки на все StringVar на всё время жизни твоего окна. Например, так:
    variables = {}
    
    def s():
        unique_types = ['1', '2', '3', '4', '5']
        entry = {}
        label = {}
        combo_list = []
        types = ['Соответсвия нет', 'A', 'B', 'C']
    
        for row, name in enumerate(unique_types, 0):
            value = StringVar()
            variables[name] = value
            lb = ttk.Label(root, text=name)
            lb.grid(row=row, column=0)
            label[name] = lb
    
            combobox = ttk.Combobox(root, textvariable=value, values=types, width=90, state="readonly")
            combobox.current(0)
            combobox.grid(row=row, column=2, padx=10, pady=5)
            combo_list.append(combobox)
            entry[name] = combobox
    
        b = ttk.Button(root, text="Print all", command=lambda: print_all_entries(unique_types, entry, label))
        b.grid(row=row + 1, column=2, padx=10, pady=5)


    Одна из причин, почему я обычно советую описывать окно как класс-наследник tkinter.Frame. В конструкторе создаёшь переменные, сохраняешь в поля класса, и они лежат себе. Когда экземпляр класса умрёт, они тоже уничтожатся.
    А потом этот экземпляр пакуешь уже в окно верхнего уровня.
    Ответ написан
  • Возможно ли сделать обработку кнопки в сокете на python?

    Vindicar
    @Vindicar
    RTFM!
    WOLF3252, ты не понимаешь как работает Tkinter, для начала.
    tkinter.Button(btn_0)
    Ты попытался создать новую кнопку, передав её в качестве родителя какую-то строку (а нужно передать родительский виджет), и тут же эту кнопку выбросил, ничего с ней не сделав. Вместо того, чтобы конфигурировать (configure()) уже существующую кнопку.
    А то я думал, что только текст передавать можно

    Через сокеты можно передавать только поток байт. И точка.
    Фокус в том, как ты этот поток байт интерпретируешь, т.е. какой у тебя протокол передачи данных. Например, ты можешь решить, что будешь передавать два числа (известного размера в байтах), где первое число - номер кнопки, второе - номер цвета в некотором списке. По нажатию кнопки одна сторона сформирует и отправит эту пару чисел, а другая, увидев, что поступили новые данные, их примет, прочитает и интерпретирует. Это будет очень простой протокол, но он будет работать.

    Главная сложность в таких приложениях в другом. По умолчанию сетевые операции останавливаются (блокируют поток) на время своего выполнения. Т.е. если тебе не передали данные, а ты вызвал recv() - программа не вернётся из recv() пока данные не придут или пока соединение не разорвётся.
    А оконным приложениям для работы нужен непрерывно работающий цикл обработки действий пользователя, им нельзя "задумываться", иначе приложение на вид "зависает". Бороться с этим можно разными способами, я бы посоветовал освоить функцию select(), чтобы заранее (до вызова recv()) понять, есть ли непрочитанные данные или нет.
    Ответ написан
    Комментировать
  • Как сделать так, что бы при нажатии на Button активировался CheckButton?

    Vindicar
    @Vindicar
    RTFM!
    Назначь but_5 обработчик клика, который сделает but_4.config(state='normal')
    И приучайся давать осмысленные имена переменным.
    Ответ написан
  • Как исправить TypeError: object of type 'Entry' has no len()?

    Vindicar
    @Vindicar
    RTFM!
    Достаточно включить голову. У тебя написано
    x = phonenumbers.parse(self.ent_1, 'None')
    В то же время ниже:
    self.ent_1 = Entry(self,width=36)
    Я очень сомневаюсь, что метод parse() принимает первым параметром поле ввода. Скорее, ему нужна строка, т.е. содержимое поля ввода. Как извлечь содержимое поля ввода, можно нагуглить. Подсказка: у поля ввода есть метод get().

    Вообще в коде много странного. Например,
    carrier_2 = print(carrier_1)
    carrier_2 всегда будет None, так как print() выводит текст в консоль и возвращает None.
    Что ты тут пытался сделать?
    Ответ написан
    Комментировать
  • Как вставлять текст в поле Enter (tkinter)?

    Vindicar
    @Vindicar
    RTFM!
    Только что проверил, Ctrl-V работает.
    Если тебе нужно другое сочетание клавиш, то ЕМНИП это делается так
    entry_widget.event_generate('<<Paste>>')
    Привязываешь свою функцию к нужному сочетанию клавиш (это гуглится), и выполняешь эту команду, когда нужно вставить текст.

    Наконец, можно использовать Python пакет clipboard, чтобы читать прямо из буфера обмена.
    Ответ написан
  • Не отображается окно tkinter при выполнение функции, из-за чего?

    Vindicar
    @Vindicar
    RTFM!
    Потому что ты не понимаешь разницу между передачей ссылки на функцию и вызовом функции.
    screen.protocol("WM_DELETE_WINDOW", block_mouse())
    Ты пытаешься задать в качестве обработчика результат вызова функции block_mouse(), а не саму функцию.
    А поскольку это происходит в block_mouse(), то программа уходит в рекурсию.
    Ответ написан
  • В чем моя ошибка?

    Vindicar
    @Vindicar
    RTFM!
    root.mainloop()
    Этот вызов показывает окно Tkinter и уходит в цикл обработки событий. Цикл длится пока окно не закрыто (т.е. пока твоя программа работает).
    Твой цикл while 1: не будет выполнен до этого момента.
    Так что лучше производи весь ввод-вывод в обработчике choose_color(), или добавь отдельную кнопку для отправки.
    Ответ написан
    Комментировать
  • Как изменить код чтобы список выводил слово нормально ,а не с абзаца каждую букву?

    Vindicar
    @Vindicar
    RTFM!
    А зачем так делать?
    Не проще будет prods_listbox.insert(END, message_entry.get())
    Ответ написан
    Комментировать
  • Нужно создать список чтобы элементы в нем были из ввода в message .В чем ошибка?

    Vindicar
    @Vindicar
    RTFM!
    ты пересоздаёшь Listbox() при каждом щелчке на кнопке, зачем?
    Создай его один раз, а потом уже обращайся к нему.

    a = msg.pack()
    Что это вообще такое?
    Ответ написан
    Комментировать
  • Почему не показывается картинки в окне tkinter?

    Vindicar
    @Vindicar
    RTFM!
    image = ImageTk.PhotoImage(Image.open("tk0.jpg"))
    Потому что ты ничего не делаешь с полученным объектом image?
    Без отступов понять невозможно где у тебя что, оформи код.
    Ответ написан
  • Как исправить ошибку при использовании библиотеки tkinter python?

    Vindicar
    @Vindicar
    RTFM!
    http.client.RemoteDisconnected: Remote end closed connection without response

    Сайт, на который ты слал запросы, тебя послал по известному адресу.
    Вообще нужно исходить из того, что любая операция с сетью может выкинуть исключение (а то и молча подвиснуть на неопределённый срок).
    Как минимум, нужно учиться ловить исключения, чтобы проблемы с сетью не роняли всю программу.
    Ответ написан
    1 комментарий
  • Как заставить окно постоянно обновляться в tkinter?

    Vindicar
    @Vindicar
    RTFM!
    Потому что под капотом большинства оконных фреймворков крутится вечный цикл вида "получить оконное сообщение - определить событие - вызвать обработчик события". И следующее оконное сообщение не будет обработано, пока обработчик события не завершится. Как следствие, длительный код в обработчике "подвешивает" окно программы.
    Быстрое и грязное решение - дёргать метод update_idletasks() (погугли про него). Он позволит выполнить перерисовку компонентов GUI, не выходя из обработчика события.
    Чуть менее грязное - разбить выполняемую работу на маленькие блоки, выполнять блок, затем планировать выполнение следующего блока через метод after(). Тогда в промежутке между вызовом after() и фактическим выполнением кода у GUI будет время обработать поступающие сообщения. Но не всегда это возможно, да и о конкуррентном запуске надо думать (что если юзер кликнет кнопку дважды, а не однажды?)
    Ещё менее грязное - вынести длительный код в отдельный поток, научить поток оповещать о своём состоянии (например, менять содержимое переменной), а через after() реализовывать только опрос этой переменной и обновление GUI. Но переменную надо будет защищать мьютексом, чтобы не словить конфликт при одновременном обращении двух потоков.
    Ответ написан
    2 комментария
  • Вместо дуги рисуется линия. Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    По-моему, ты некорректно передаёшь параметры в create_line().
    To create a canvas line object on a canvas C, use:
    id = C.create_line(x0, y0, x1, y1, ..., xn, yn, option, ...)
    The line goes through the series of points (x0, y0), (x1, y1), … (xn, yn).
    Ответ написан
    Комментировать
  • Почему не работает позиционирование в tkinter?

    Vindicar
    @Vindicar
    RTFM!
    1. Для одного элемента можно использовать только один менеджер геометрии. Если ты положил кнопку на форму через place(), не делай ей pack().
    2. В рамках одного контейнера можно использовать только один менеджер геометрии. Если ты положил один элемент на панель/в окно через place()/pack()/grid(), другие элементы, положенные непосредственно в ту же панель/окно, должны использовать тот же самый менеджер.
    Ответ написан
    Комментировать
  • Как собрать 32-битный exe файл?

    Vindicar
    @Vindicar
    RTFM!
    Поплярные упаковщики питона в exe просто засовывают туда весь интерпретатор питона (ну может выбирает только используемые модули) вместе с кодом скрипта. Это НЕ настоящая компиляция.
    Так что делай вывод сам, можно ли упаковать скрипт в 32-битный экзешник, не имея 32хбитного питона на машине.
    Если есть полноценный транслятор Питона в C++ или подобный честный комплируемый язык, он мне не известен.
    Ответ написан
    Комментировать
  • Как оптимизировать работу приложения?

    Vindicar
    @Vindicar
    RTFM!
    Вместо цикла и win.update() научись использовать win.after().
    Ответ написан
    2 комментария