_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack
Не понимаю в чем прикол. Вот код, который есть у меня:
text_lab = Label(self, text="Create Text: ")
text_lab.grid(row=4, column=0, padx=5)
text_entry.pack(side=BOTTOM)
Так он работает. Но если я убираю .pack на .grid, то выдает ошибку, что grid и pack не могут быть вместе. Хотя вместе они работают, а убирая pack перестают. Что я не понимаю ?
text_lab = Label(self, text="Create Text: ")
text_lab.grid(row=4, column=0, padx=5)
text_entry.grid(row=4, column=1)
В таком виде выдает ошибку:
_tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack.
Полная версия кода:
from tkinter import *
from tkinter import messagebox
from tkinter.tix import *
# import os
# import matplotlib.pyplot as plt
from PIL import Image, ImageTk, ImageGrab
from tkinter.filedialog import askopenfilename, asksaveasfile
import keyboard
class Paint(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.cursor_position_print()
print(parent)
self.parent = parent
self.color = "black"
self.brush_size = 2
self.setUI()
def cursor_position_print(self):
global x, y
x = self.winfo_pointerx() - self.winfo_rootx()
y = self.winfo_pointery() - self.winfo_rooty()
# print('Позиция курсора: {}, {}'.format(x, y))
self.after(1, self.cursor_position_print)
# Поиск координат курсора
def set_color(self, new_color):
self.color = new_color
def set_brush_size(self, new_size):
self.brush_size = new_size
def line(self, event):
global mode, x, y, x1, x2, y1, y2, countLine
if (mode == 4):
if (countLine == 1):
x2 = x - 5
y2 = y - 110
countLine = 2
print('Вторая точка {}:{}'.format(x2, y2))
paint.canv.create_line(x1, y1, x2, y2, width=self.brush_size, fill=self.color)
if (countLine == 0):
x1 = x - 5
y1 = y - 110
countLine += 1
print('Первая точка {}:{}'.format(x1,y1))
if (countLine == 2):
countLine = 0
def rectangle(self, event):
global mode, x, y
if (mode == 2):
x1 = x - self.brush_size - 5
y1 = y + self.brush_size - 110
x2 = x + self.brush_size - 5
y2 = y - self.brush_size - 110
self.canv.create_rectangle(x1, y1, x2, y2, fill=self.color, outline=self.color)
def circle(self, event):
global mode, x, y
if (mode == 3):
x1 = x - self.brush_size - 5
y1 = y + self.brush_size - 110
x2 = x + self.brush_size - 5
y2 = y - self.brush_size - 110
self.canv.create_oval(x1, y1, x2, y2, fill=self.color, outline=self.color)
def draw(self, event):
global mode
if (mode == 1):
self.canv.create_oval(event.x - self.brush_size,
event.y - self.brush_size,
event.x + self.brush_size,
event.y + self.brush_size,
fill=self.color, outline=self.color)
# Непосредственно функция, которая будет отвечать за
# появление "линии" на холсте, если выбрана кисть
def setScroll(self):
sw = ScrolledWindow(self, scrollbar=Y)
sw.pack(fill=BOTH, expand=1)
def setUI(self):
global mode, master
# Создаем переменную, которая в дальнейшем будет отвечать
# за активный инструмент
self.pack(fill=BOTH, expand=1)
# Размещаем активные элементы на родительском окне
self.columnconfigure(7, weight=1)
# Даем седьмому столбцу возможность растягиваться, благодаря
# чему кнопки не будут разъезжаться при ресайзе
self.rowconfigure(5, weight=1)
# То же самое для четвертого ряда. Там будет холст
self.canv = Canvas(self, bg='white')
# Создаем поле для рисования, устанавливаем белый фон
self.canv.grid(row=5, column=0, columnspan=8, padx=5, pady=5, sticky=E + W + S + N)
# Прикрепляем канвас методом grid. Он будет находится в 3м ряду, первой колонке,
# и будет занимать 7 колонок, задаем отступы по X и Y в 5 пикселей, и заставляем
# растягиваться при растягивании всего окна
self.canv.bind("<B1-Motion>", self.draw)
# Привязываем обработчик к канвасу. <B1-Motion> означает "при движении
# зажатой левой кнопки мыши" вызывать функцию draw
color_lab = Label(self, text="Color: ")
# Создаем метку для кнопок изменения цвета кисти
color_lab.grid(row=0, column=0, padx=5)
# Устанавливаем созданную метку в первый ряд и
# первую колонку, задаем горизонтальный отступ в 6 пикселей
red_btn = Button(self, text="Red", width=8, command=lambda: self.set_color("red"))
# Создание кнопки: Установка текста кнопки, задание ширины
# кнопки (10 символов), функция вызываемая при нажатии кнопки.
red_btn.grid(row=0, column=1)
# Устанавливаем кнопку
# Создание остальных кнопок повторяет ту же логику, что и создание
# кнопки установки красного цвета, отличаются лишь аргументы.
green_btn = Button(self, text="Green", width=8, command=lambda: self.set_color("green"))
green_btn.grid(row=0, column=2)
blue_btn = Button(self, text="Blue", width=8, command=lambda: self.set_color("blue"))
blue_btn.grid(row=0, column=3)
black_btn = Button(self, text="Black", width=8, command=lambda: self.set_color("black"))
black_btn.grid(row=0, column=4)
white_btn = Button(self, text="White", width=8, command=lambda: self.set_color("white"))
white_btn.grid(row=0, column=5)
purple_btn = Button(self, text="Purple", width=8, command=lambda: self.set_color("purple"))
purple_btn.grid(row=0, column=6)
yellow_btn = Button(self, text="Yellow", width=8, command=lambda: self.set_color("yellow"))
yellow_btn.grid(row=0, column=7, sticky=W)
# clear_btn = Button(self, text="Очистить", width=8, command=lambda: self.canv.delete("all"))
# clear_btn.grid(row=0, column=6, sticky=W)
size_lab = Label(self, text="Brush size: ")
size_lab.grid(row=1, column=0, padx=5)
one_btn = Button(self, text="2", width=8, command=lambda: self.set_brush_size(2))
one_btn.grid(row=1, column=1)
two_btn = Button(self, text="5", width=8, command=lambda: self.set_brush_size(5))
two_btn.grid(row=1, column=2)
five_btn = Button(self, text="10", width=8, command=lambda: self.set_brush_size(10))
five_btn.grid(row=1, column=3)
seven_btn = Button(self, text="20", width=8, command=lambda: self.set_brush_size(20))
seven_btn.grid(row=1, column=4)
twenty_btn = Button(self, text="40", width=8, command=lambda: self.set_brush_size(40))
twenty_btn.grid(row=1, column=5)
thirty_btn = Button(self, text="50", width=8, command=lambda: self.set_brush_size(50))
thirty_btn.grid(row=1, column=6)
activeMode_lab = Label(self, text="Tools: ")
activeMode_lab.grid(row=2, column=0, padx=5)
brush_btn = Button(self, text='Brush', width=8, command=lambda:
[setBrush(), paint.canv.bind("<B1-Motion>", self.draw), print('Brush on')])
brush_btn.grid(row=2, column=1)
rectangle_btn = Button(self, text='Square', width=8, command=lambda:
[setRectangle(), print('Rectangle on'), paint.canv.bind("<ButtonPress-1>", paint.rectangle)])
rectangle_btn.grid(row=2, column=2)
oval_btn = Button(self, text='Circle', width=8, command=lambda:
[setCircle(), print('Circle on'), paint.canv.bind("<ButtonPress-1>", paint.circle)])
oval_btn.grid(row=2, column=3)
line_lab = Label(self, text="Create Line: ")
line_lab.grid(row=3, column=0, padx=5)
line_btn = Button(self, text='Line', width=8, command=lambda:
[setLine(), print('Line on'), paint.canv.bind("<ButtonPress-1>", paint.line)])
line_btn.grid(row=3, column=1)
infoLine1_lab = Label(self, text="-->")
infoLine1_lab.grid(row=3, column=4, padx=5)
infoLine_lab = Label(self, text="First click - First point. Second click - Second Point")
infoLine_lab.grid(row=3, column=7, padx=5)
text_lab = Label(self, text="Create Text: ")
text_lab.grid(row=4, column=0, padx=5)
text_entry.grid(row=4, column=1)
# oladka_btn = Button(self, text='mode = ?', width=8, command=lambda: print(mode))
# oladka_btn.grid(row=3, column=2)
def setBrush():
global mode
mode = 1
def setRectangle():
global mode
mode = 2
def setCircle():
global mode
mode = 3
def setLine():
global mode, countLine
mode = 4
countLine = 0
def importImage():
global paint
fname = askopenfilename(filetypes=[("Изображения", "*.jpeg;*.jpg;*.png;*.gif")])
if fname is not None:
try:
img = ImageTk.PhotoImage(Image.open(fname))
paint.canv.background = img
paint.canv.create_image(0, 0, anchor=NW, image=img)
except Exception as err:
messagebox.showerror("Ошибка загрузки файла", err)
# Функция импорта изображения на холст
def saveImg():
global paint
fname = asksaveasfile(mode='w', defaultextension=".jpg", filetypes=[("JPEG", ".jpg")])
if fname is None:
return
x = paint.canv.winfo_rootx() + 2
y = paint.canv.winfo_rooty() + 2
xx = x + paint.canv.winfo_width() - 4
yy = y + paint.canv.winfo_height() - 4
ImageGrab.grab(bbox=(x, y, xx, yy)).save(fname)
# Функция сохранения нарисованного на холсте
def main():
global paint, mode, master
mode = 1
root = Tk()
root.title('Analoque ImageEditor')
root.geometry("850x650+250+50")
# Создание окна, смена его названия, размера и положения
root.iconbitmap('Icons\Icon.ico')
mainmenu = Menu(root)
root.config(menu=mainmenu)
filemenu = Menu(mainmenu, tearoff=0)
filemenu.add_command(label="Очистить холст", command=lambda: paint.canv.delete("all"))
filemenu.add_command(label="Импорт", command=importImage)
filemenu.add_command(label="Сохранить нарисованное", command=saveImg)
filemenu.add_command(label="Выход", command=root.quit)
# helpmenu = Menu(mainmenu, tearoff=0)
# helpmenu.add_command(label="Помощь")
# helpmenu.add_command(label="О программе")
mainmenu.add_cascade(label="Файл", menu=filemenu)
# mainmenu.add_cascade(label="Справка", menu=helpmenu)
# Добавление меню и его дальнейшее наполнение с подменю
global text, text_entry
text = StringVar()
text_entry = Entry(textvariable=text)
paint = Paint(root)
# Функция, открывающая возможность рисовать
keyboard.add_hotkey('Ctrl + S', lambda: saveImg())
# Сохранение нарисованного через сочетание клавиш "Ctrl + S"
root.mainloop()
if __name__ == '__main__':
main()
# Основа, которая запускает main(), если данный файл является
# главным в запуске
Ответы (1 шт):
Обратите внимание на эту строку в
text_entry.grid(row=4, column=1)
внутри метода setUI. Дело в том, что text_entry - вражеский засланец, созданный не внутри метода setUI, а созданный внутри функции main, и прикрепленный к объекту root:
text_entry = Entry(textvariable=text)
(если родитель не указан, то используется корневое окно)
Объект Paint также прикреплен к root, но размещается при помощи pack, что и вызывает конфликт.
В данном случае нужно или перетащить создание text_entry внутрь метода setUI с указанием родителя self, или перетащить его размещение в main, и соответственно размещать через pack, а не grid. Также и размещение объекта Paint стоит выполнять не в самом Paint а в создающем его коде.
Еще у вас в коде есть глобальная проблема: использование global. Если вы уже доросли до ООП, то global вам не нужно.