Ответы пользователя по тегу Tkinter
  • Как рисовать поверх фото в tkinter?

    Vindicar
    @Vindicar
    RTFM!
    Вместо того, чтобы изобретать велосипед, используй элемент Canvas. Он и рисовать позволяет, и изображение вставить.
    Ответ написан
    Комментировать
  • Как мне правильно запустить поток с ткинтером?

    Vindicar
    @Vindicar
    RTFM!
    root.withdraw() для скрытия и root.deiconify() для показа пробовал?
    Ответ написан
    1 комментарий
  • Как принимать значение entry в customtkinter?

    Vindicar
    @Vindicar
    RTFM!
    Как ни странно, почитать документацию.
    Ответ написан
    Комментировать
  • Как создавать фреймы в неопределённом кол-ве?

    Vindicar
    @Vindicar
    RTFM!
    Простой вариант - складывай нужные объекты в список. Если что, можно сделать список кортежей.
    Чуть более сложный вариант - опиши класс, описывающий пару кнопка-label, и реализующий логику выбора файла, и складывай в список экземпляры этого класса.
    Ответ написан
    Комментировать
  • Как создать выпадающий список с данными из postgres на python?

    Vindicar
    @Vindicar
    RTFM!
    select "Route_num" from "Route TB"
    Во-первых, ты кавычки не перепутал? В SQL вроде имена столбцов и таблиц экранируются `бэктиками`, а не "кавычками".
    Во-вторых, ты просишь выбрать одно значение на каждой строке. Но в то же время обращаешься к item[1], т.е. ко второму элементу строки. Которого быть не может, так как ты выбираешь только один.
    Ответ написан
    6 комментариев
  • Попытался перенести код на tkinter в формат ооп, до этого выводил всё корректно, сейчас же выводит только пустое окно, что делать?

    Vindicar
    @Vindicar
    RTFM!
    1. Оформи код. Кнопка </> в помощь. Сейчас нечитаемо.
    2. Включить голову и разобраться, как же работает графический интерфейс (потому что принципы одинаковые в любом языке практически). Ну и немножко подучить Питон на более простых примерах.

    root_changes_2.mainloop() запускает основной рабочий цикл. В нём программа получает сообщения от ОС о действиях пользователя и реагирует на них. Цикл прерывается, когда закрывается основное окно (ты хранишь ссылку на него в root_changes_2).
    Как следствие, программа будет стоять на этой строке, пока ты не закроешь окно, и ТОЛЬКО ПОТОМ перейдёт к объявлению класса Main_window.

    Это объявление, разумеется, ничего не даёт - ведь ты просто объявил класс, но не создал его экземпляр. А после объявления класса у тебя ничего нет, поэтому скрипт завершает работу.
    Я ФЗ что такое ttkbootstrap, поэтому покажу простой пример на голом tkinter.

    import tkinter as tk
    import tkinter.messagebox as tkmb
    
    class MainWindow(tk.Tk):
        """Главное окно программы наследуется от Tk. 
        Вспомогательные окна - от TopLevel.
        Составные элементы управления - от Frame."""
        
        def __init__(self):
            """Метод __init__() автоматически вызывается при создании нового экземпляра класса."""
            super().__init__()  # обязательно вызываем конструктор родительского класса!
            # при закрытии нашего окна вызовется метод __done()
            # если эта функциональность не нужна, можно убрать эту строку
            self.protocol('WM_DELETE_WINDOW', self.__done)  
            # пример создания элементов управления
            # имена, начинающиеся с __, не видны снаружи класса
            # мы присваиваем не просто переменным, а полям объекта. Эти поля будут видны в других методах.
            self.__entry = tk.Entry(self)  # поле ввода будет вложено непосредственно в наше окно
            self.__entry.pack(side=tk.TOP, fill=tk.X, expand=True)
            self.__btn = tk.Button(self, text='Нажми меня', command=self.__btn_pressed)  # кнопка и реакция на неё
            self.__btn.pack(side=tk.TOP)
        
        def __done(self):
            """Мы прописали вызов этого метода при закрытии окна. 
            Тут мы можем корректно завершить работу нашей программы, а потом подтвердить закрытие."""
            self.destroy()  # подтверждаем закрытие. Если этот вызов не сделать, окно не закроется. Иногда это нужно.
        
        def __btn_pressed(self):
            """Реакция на кнопку."""
            text = self.__entry.get()  # мы можем обращаться к полям объекта
            tkmb.showinfo(
                title='Вы ввели',
                message=text,
                parent=self
            )
    
    
    if __name__ == '__main__':  
        # это условие выполнится, только если скрипт запущен непосредственно
        # оно не выполнится, если скрипт импортируется другим скриптом
        # поэтому в такое условие обычно заворачивают "тело" скрипта
        wnd = MainWindow()  # создаём окно
        wnd.mainloop()  # главный рабочий цикл
        # сюда управление будет передано после закрытия окна
        print('Окно закрыто, пока!')
    Ответ написан
  • Как исправить ошибку tkinter Python?

    Vindicar
    @Vindicar
    RTFM!
    Значит, ты в какой-то момент делаешь в глобальной области видимости присваивание вида execute = tkinter.Button(...)
    Ответ написан
    1 комментарий
  • Как сделать консоль в tkinter python?

    Vindicar
    @Vindicar
    RTFM!
    Создай многострочное поле ввода, у запущенного процесса периодически опрашивай стандартный вывод. Если удалось что-то прочитать - добавляй прочитанное в поле ввода.
    Ответ написан
    Комментировать
  • Почему энтри объект игнорирует запросы?

    Vindicar
    @Vindicar
    RTFM!
    зашитая в кнопку команда объектом энтри игнорируется

    Ты в обработчике кнопки сам создаёшь новый экземпляр класса Put_Entry (который является виджетом), нигде его не размещаешь, а просто что-то с ним делаешь. Конечно, уже существующие экземпляры от этого никак не изменяются - твоя кнопка про них ничего не знает и никак их не трогает.

    Короче, читай учебник, для начала. У тебя, похоже, полнейшая каша в голове. Разбирайся в понятиях области видимости и времени жизни, для начала - тогда будет понятнее, что где хранить и что куда передавать.
    Не говоря уже о том, что я тебе уже два раза показывал, как хоть немного правильно создавать свои UI-классы, но как об стенку горох.
    Ответ написан
    4 комментария
  • Метод insert не работает, как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Ну тут сразу возникает вопрос: какую задачу выполняет этот метод. Ты говоришь, что метод используется другим классом. Окей, это норма. Для чего он используется? Какую задачу другой класс хочет решить вызовом этого метода?
    Вопрос связан с тем, что ты почему-то создаёшь элементы управления в методе put_wigets(). По идее, если твой класс представляет собой группу элементов управления, он должен создавать дочерние элементы в своём конструкторе, и сохранять ссылки на них в приватные (ну, насколько это можно в питоне) поля класса. Методы класса должны к этим полям обращаться. Исходи из того, что локальная переменная в методе (как Ent_numberBox ) живёт только во время вызова этого метода, и не должна содержать ничего, что переживёт этот метод (если это не возвращаемое значение).

    Например, так:
    import tkinter as tk
    
    class InputBox(tk.Frame):
        def __init__(self, master, **kwargs):
            # вызываем унаследованный конструктор
            super().__init__(master, **kwargs)
            # переменные tkinter можно связывать с элементами управления
            # тогда изменение в переменной отобразится в элементе, и наоборот
            # это бывает удобнее, чем дёргать элемент напрямую
            # а ещё можно самим реагировать на изменения значения такой переменной
            self.__value = tk.StringVar()
            # наше поле ввода
            self.__entry = tk.Entry(self, justify=tk.RIGHT, width=22, textvariable=self.__value)
            self.__entry.pack(side=tk.RIGHT, padx=10, pady=15)
            # метка с пояснением
            self.__helptext = tk.Label(self, bg=self['background'], height=3, text="Введите мат. выражение:")
            self.__helptext.pack(side=tk.LEFT)
        
        def get_value(self) -> str:
            """Возвращает введённую строку."""
            return self.__value.get()  # метод get() позволяет прочитать значение переменной tkinter
        
        def set_value(self, value: str) -> None:
            """Заменяет содержимое введённой строки новым."""
            self.__value.set(value)  # метод set() позволяет задать новое значение для переменной
            
        def append(self, symbol: str) -> None:
            """Добавляет символ(ы) к уже введённой строке."""
            self.__value.set(self.__value.get() + symbol)
    
    
    if __name__ == '__main__':
        root = tk.Tk()
        box = InputBox(root)
        box.pack(side=tk.TOP, expand=True, fill=tk.BOTH)
        box.set_value('Hello')
        box.append(', world!')
        root.mainloop()


    Я в этом примере исходил из своего понимания твоей задачи.
    Если это поле ввода, то мы хотим иметь возможность получить введённое значение. Поэтому метод get_value().
    Также ты упомянул необходимость в том, чтобы изменить это значение извне, из другого класса. Значит, нужен метод set_value().
    Также, если это - часть калькулятора, у тебя будет часто встречаться задача "добавить один символ в конец строки". Это можно реализовать через пару get_value()/set_value(), но будет удобнее иметь отдельный метод append().
    Один метод - одна решаемая задача.
    Ответ написан
    3 комментария
  • Кнопка и окно ввода в разных классах, не получается добавить кнопке возможность вставлять знаки в Entry объект?

    Vindicar
    @Vindicar
    RTFM!
    Во-первых, какой виджет за что отвечает? Что такое inputBox? В чём его роль? В идеале одним предложением.

    Во-вторых, не следует лазать в кишки класса без нужды. Вместо этого имеет смысл добавить этому классу удобный метод, который сделает всё что нужно, с пониманием внутреннего устройства класса. Тогда те, кто класс использует, не должны будут знать его внутреннее устройство - только его видимый интерфейс (методы, свойства). Это называется инкапсуляция.
    Ответ написан
    2 комментария
  • Странная не последовательная работа функции в tkinter python?

    Vindicar
    @Vindicar
    RTFM!
    Потому что перерисовка окна - это отдельное событие. Когда ты изменяешь текст метки, она помечает своё окно как нуждающееся в перерисовке. Да, каждый элемент управления - это тоже окно. Это идёт из нижележащего оконного менеджера, и под виндой, и под никсами. Это сделано, чтобы не перерисовывать окно двести раз, если ты делаешь серию изменений в интерфейсе.
    Эта перерисовка будет выполнена после того, как закончит выполняться твой обработчик события.
    Ты можешь попробовать вызвать label1.update_idletasks() после изменения текста, чтобы попросить tkinter перерисовать окно немедленно.
    Ответ написан
    1 комментарий
  • Как добавить готовый график в 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. Применить в своём проекте.
    Ответ написан