Задать вопрос
Ответы пользователя по тегу Tkinter
  • Ошибка "cannot pickle '_tkinter.tkapp' object" при использовании Multiprocessing, почему?

    Vindicar
    @Vindicar
    RTFM!
    Потому что multiprocessing - это не магия, а инструмент с ограничениями.
    В частности, у каждого дочернего процесса полностью своя память. Никаких общих объектов! Любые данные, передающиеся между процессами, упаковываются встроенным модулем pickle, и распаковываются на той стороне. Как следствие, есть довольно ограниченный набор типов данных, которые можно передавать как аргумент, или возвращать как результат из другого процесса. Окна ткинтера в этот набор не входят, о чём тебе и сообщает ошибка.

    Используй пару multiprocessing.Queue или SimpleQueue для коммуникации с работающим процессом. Одна очередь должна содержать команды от главного процесса дочернему, а другая - оповещения от дочернего главному. Сосредоточь всю работу с GUI в главном процессе, а для периодической проверки наличия новых оповещений в очереди используй метод root.after().

    Ну и да, "принудительно остановить" - это вообще не лучшая идея, и не должно быть нормальным подходом. Перепиши свои функции так, чтобы они мониторили какой-нибудь multiprocessing.Event (ну или threading.Event, если хочешь работать в потоках), и останавливались, когда он окажется взведён.
    Ответ написан
    2 комментария
  • Как в tk.Label отобразить содержимое двух списков один над другим?

    Vindicar
    @Vindicar
    RTFM!
    Т.е. тебе нужно конкатенировать списки, а потом преобразовать?
    Простой способ будет:
    all_lists_together = sum(lists, [])  # склеиваем списки в один, по порядку
    all_lists_as_string = '\n'.join(all_lists_together)  # а дальше обрабатываем этот список
    Ответ написан
    1 комментарий
  • Как завершать программу анимированной гифкой?

    Vindicar
    @Vindicar
    RTFM!
    У тебя в коде полно вызовов third_window.grab_set(), хотя а) никакого третьего окна ты не показал и б) даже в коде, который относится к дургим окнам. Копипаст подвел, или так задумано?
    Ответ написан
  • Проблема с customtkinter, параметр command у кнопки и цикл for. Как исправить?

    Vindicar
    @Vindicar
    RTFM!
    Ну классика же, lambda завязывается на саму переменную, а не на её текущее значение. Т.е. если ты изменишь i, то все лямбды это увидят.
    i = 10
    f = lambda: print(i)
    i = 20
    f()  # выведет 20

    Нужно сохранить искомое значение в самой лямбде. Самый простой способ - вот такой хак:
    i = 10
    # сохраняем глобальную i как значение по умолчанию параметра i
    f = lambda i=i: print(i)  
    i = 20
    f()  # выведет 10
    f(30)  # выведет 30

    Как видишь последний вызов работает немножко не так, как мы ожидаем - а ожидаем мы ошибку из-за лишнего параметра. Но можно схитрить так:
    i = 10
    # сохраняем глобальную i как значение по умолчанию параметра i
    # Параметр i может быть передан только по имени: i=30
    f = lambda *,i=i: print(i)  
    i = 20
    f()  # выведет 10
    f(i=30)  # выведет 30
    f(30)  # TypeError: <lambda>() takes 0 positional arguments but 1 was given
    Ответ написан
    1 комментарий
  • Написал код на pycharm с изображениями, но он не работает. Не понимаю что не так. В чём ошибка?

    Vindicar
    @Vindicar
    RTFM!
    Ты указал относительный путь к файлу picture.png.
    Поскольку путь относительный (т.е. не начинается от корня диска), программа ищёт его относительно текущей рабочей директории. Эта директория может различаться по обстоятельствам, но в твоём случае итоговый путь оказывается таким: C:\\Users\\Уваж Руслан Рафэкови\\PycharmProjects\\pythonProject\\Tests\\picture.png
    У тебя точно по этому пути лежит корректный файл изображения? Потому что судя по тексту ошибки, его там нет.
    Ответ написан
    Комментировать
  • Tkinter. Какой метод позиционирование лучше выбрать .pack / .place / .grid?

    Vindicar
    @Vindicar
    RTFM!
    Помести кнопки в Frame, Frame прикрути через pack(). Кнопки внутри фрейма - можно тоже через pack, можно еще как.
    Единственное, при добавлении новых элементов нужно будет сообразить, как указать, чтобы они паковались ДО фрейма с кнопками.

    EDIT: Заверни панель кнопок в ещё один Frame, и помести эту панель внутри внешнего Frame через pack(side='top', anchor='center'). Но учитывая, что у тебя в окне и так уже используется pack(side='top'), то можно обойтись без внешнего Frame - просто убери expand/fill с панели кнопок и запакуй её наверх.
    Пример кода с внешней панелью:
    import tkinter as tk
    
    
    root = tk.Tk()
    root.geometry('200x100')
    frame_outer = tk.Frame(root, bg='blue')
    frame_outer.pack(expand=True, fill='both')
    
    frame = tk.Frame(frame_outer, bg='green')
    btn1 = tk.Button(frame, text='Button1')
    btn2 = tk.Button(frame, text='Button2')
    btn1.pack(side='left', padx=5, pady=5)
    btn2.pack(side='left', padx=5, pady=5)
    frame.pack(side='top', anchor='center')
    
    root.mainloop()
    Ответ написан
    3 комментария
  • Как в название одной переменной внести значение другой переменной?

    Vindicar
    @Vindicar
    RTFM!
    Это можно сделать, но в 99% случаев это не нужно делать. Во-первых, пользователь может ввести строку, которая не является корректным идентификатором. Во-вторых, появляется риск нечаянно перезаписать переменную, которую мы не хотели трогать.
    Вместо этого следует использовать словарь (dict), где ключ - имя "переменной", а значение - её содержимое. Это куда более контролируемо.
    Нет, я хочу выстрелить себе в ногу, и санитары меня не остановят!

    Функция globals() возвращает словарь глобальных переменных, а locals() - словарь локальных.
    При этом эти словари - не копии, а, можно сказать, оригиналы. Добавишь в них новый ключ - появится новая переменная. Вот пример в интерактивной консоли питона:
    Python 3.11.7 (tags/v3.11.7:fa7a6f2, Dec  4 2023, 19:24:49) [MSC v.1937 64 bit (AMD64)] on win32
    Type "help", "copyright", "credits" or "license" for more information.
    >>> l = locals()
    >>> l['x'] = 1
    >>> x
    1
    >>>

    Ответ написан
    Комментировать
  • Как при закрытии главного окна закрывались все остальные окна?

    Vindicar
    @Vindicar
    RTFM!
    class MainWindow(tk.Tk):
        """Главное окно приложения."""
        def __init__(self):
            """Конструктор вызывается при создании окна"""
            super().__init__()
            self.title('Моё окно')
            self.protocol('WM_DELETE_WINDOW', self.__done)  # прописываем реакцию на закрытие окна
            ...  # тут создаёшь элементы управления и проводишь прочую инициализацию
            # в том числе создаёшь и запоминаешь вспомогательные окна
    
        def __done(self):
            """Вызовется при попытке закрытия окна"""
            ...  # тут делаешь что тебе нужно при закрытии
            # например, закрываешь вспомогательные окна
            self.destroy()  # если не сделать этот вызов, окно на самом деле не закроется - иногда это нужно
    
    if __name__ == '__main__':
        root = MainWindow()
        root.mainloop()
    Ответ написан
    2 комментария
  • Как рисовать поверх фото в 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 комментарий