Задать вопрос
Ответы пользователя по тегу Tkinter
  • Как добавить готовый график в Figure (matplotlib)?

    Vindicar
    @Vindicar
    RTFM!
    Ты можешь добраться до фигуры так
    from matplotlib import pyplot
    plot: Plot = ...  # тут твой Plot
    fig: pyplot.Figure = plot.backend.fig

    И дальше работать с ней в твоём GUI, как обычно.

    Альтернативно, можно почитать исходники класса MatplotlibBackend, сделать его копию, и модифицировать её так, чтобы вместо
    self.fig = self.plt.figure(figsize=parent.size)
    твой бэкэнд принимал Figure как параметр конструктора.
    Ответ написан
    Комментировать
  • Как исправить ошибку взаемодействия Дискорд бота и окна?

    Vindicar
    @Vindicar
    RTFM!
    #
        loop = asyncio.get_event_loop()
        loop.create_task(process_bot_queue())
        loop.run_forever()

    Что вообще вот этот код делает в теле программы, если у тебя вызов create_window() не вернёт управление, пока окно GUI не будет закрыто?
    Ответ написан
    Комментировать
  • Как исправить ошибку взаимодействия окна и дискорд бота?

    Vindicar
    @Vindicar
    RTFM!
    В коде нет работы с потоками, ты даже не импортируешь threading.
    Нужно понимать три вещи:
    1. Рабочий цикл бота займёт весь поток, равно как и рабочий цикл tkinter. Совместить их практически невозможно (технически можно, но это очень нетривиально).
    2. Элементы GUI должны создаваться и использоваться строго в одном и том же потоке.
    3. Нельзя делать await вызовы из одного потока в другой.

    Поэтому я бы посоветовал такое грубое, но простое решение:
    В одном потоке потоке создавай event loop (сам! это важно!) и запускай бота. В другом потоке создавай и запускай GUI.
    Какой поток должен быть главным - скорее всего не принципиально. Попробуй оба варианта.
    Используй пару очередей (queue.Queue) для синхронизации между потоками.

    Одна очередь будет периодически проверяться в потоке GUI с помощью root.after(). Почитай документацию на этот метод, но если коротко - он позволяет запланировать вызов функции в потоке GUI через время. Эта очередь будет содержать сведения о том, что нужно обновить в GUI.
    Формат и смысл сведений определи сам. Это может быть что-то высокоуровневое в духе "есть сообщение от пользователя такого-то с таким-то текстом", и пусть поток gui сам разбирается, что с этим делать. Это может быть и что-то более низкоуровневое, типа "задай такому-то свойству у такого-то элемента управления такое-то значение". Я бы посоветовал первый вариант - он позволит разделить логику программы чётко на две части.
    Код проверки будет примерно вида
    def check_gui_queue():
        try:
            while True:
                command = gui_queue.get_nowait()  # проверяем, есть ли команда для GUI
                gui_queue.task_done()  # на каждый успешный вызов get() - один вызов task_done()
                pass  # как-то обрабатываем команду
        except queue.Empty:  # команды нет
            root.after(100, check_gui_queue)  # даём GUI поработать спокойно 100 мс

    Разумеется, если ты завернёшь GUI в класс (что имеет смысл) код немного изменится. Но суть останется прежней.

    Другая очередь будет содержать команды для бота. Периодически проверяй её в потоке asyncio с помощью простого кода вида
    async def check_bot_queue():
        while True:
            try:
                command = bot_queue.get_nowait()  # проверяем, есть ли новая команда для бота
            except queue.Empty:
                await asyncio.sleep(0.1)  # нет - даём другим корутинам поработать 100 мс
            else:
                bot_queue.task_done()  # на каждый успешный вызов get() - один вызов task_done()
                pass  # есть - как-то её обрабатываем

    Эту корутину запустишь через create_task(), и она позволит коду GUI организовывать вызовы в коде бота.

    Разумеется, придётся подумать, как аккуратно сделать, чтобы эти две функции не разрослись в дикую простыню из if-elif-else. Но общий принцип примерно такой.
    Время ожидания команды можно увеличить - это замедлит время реакции пре передаче данных между потоками, но уменьшит холостую нагрузку на систему.
    Ответ написан
    Комментировать
  • Как позиционировать виджеты tkinter?

    Vindicar
    @Vindicar
    RTFM!
    Если ты используешь менеджер pack(), используй параметр anchor для выравнивания вдоль другой оси. expand и fill - для заполнения вдоль другой оси.
    Ответ написан
    Комментировать
  • Что не так у меня в коде? Мне в терминале выводит большую ошибку.?

    Vindicar
    @Vindicar
    RTFM!
    Ну так читай внимательно текст ошибки.
    _tkinter.TclError: bad option "-tittle": must be -default, -detail, -icon, -message, -parent, -title, or -type

    Разницу видишь?
    А ошибка в строке
    File "c:\Users\Solo\Desktop\MAXIUMAM2035\Go_user.py", line 19, in button_click
    messagebox.showinfo(tittle='Проверка', message=info_str) # Для вывода информации
                        ^^^^^^
    Ответ написан
    1 комментарий
  • Как сделать анимацию загрузки при условии на 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 комментарий