Как использовать overlay Vkeyboard на холсте в tkinter?

#python #python-3.x #tkinter #tkinter-canvas #tkinter-entry

#python #python-3.x #tkinter #tkinter-холст #tkinter-запись

Вопрос:

У меня есть код Vkeyboard, написанный на tkinter с использованием grid . Я хочу реализовать это на своем холсте и выше на фоновом изображении.

Ниже приведен мой код.

 from tkinter import *


Keyboard_App = Tk()

canvas = Canvas(Keyboard_App, width=400, height=400)
canvas.pack(side="top", fill="both", expand=True)

background = PhotoImage(file="Images/background.png")
canvas.create_image(400,400,image=background, tags="B")

buttons = [
    '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '=',
    'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '<-',
    'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '"',
    'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 'SHIFT',
    ' Space ',
]
curBut = [-1,-1]
buttonL = [[]]
entry = Text(Keyboard_App, width=97, height=8)
entry.grid(row=0, columnspan=15)

varRow = 1
varColumn = 0

def leftKey(event):
    if curBut == [-1,-1]:
        curBut[:] = [0,0]
        buttonL[0][0].configure(highlightbackground='red')
    elif curBut[0] == 4:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [0,10]
        buttonL[0][10].configure(highlightbackground='red')
    else:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [curBut[0], (curBut[1]-1)%11]
        buttonL[curBut[0]][curBut[1]%11].configure(highlightbackground='red')

def rightKey(event):
    if curBut == [-1,-1]:
        curBut[:] = [0,0]
        buttonL[0][0].configure(highlightbackground='red')
    elif curBut[0] == 4:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [0,0]
        buttonL[0][0].configure(highlightbackground='red')
    else:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [curBut[0], (curBut[1] 1)%11]
        buttonL[curBut[0]][curBut[1]%11].configure(highlightbackground='red')

def upKey(event):
    if curBut == [-1,-1]:
        curBut[:] = [0,0]
        buttonL[0][0].configure(highlightbackground='red')
    elif curBut[0] == 0:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [(curBut[0]-1)%5, 0]
        buttonL[curBut[0]][curBut[1]%11].configure(highlightbackground='red')
    else:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [(curBut[0]-1)%5, curBut[1]]
        buttonL[curBut[0]][curBut[1]%11].configure(highlightbackground='red')

def downKey(event):
    if curBut == [-1,-1]:
        curBut[:] = [0,0]
        buttonL[0][0].configure(highlightbackground='red')
    elif curBut[0] == 3:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [(curBut[0] 1)%5, 0]
        buttonL[curBut[0]][curBut[1]%11].configure(highlightbackground='red')
    else:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
        curBut[:] = [(curBut[0] 1)%5, curBut[1]]
        buttonL[curBut[0]][curBut[1]%11].configure(highlightbackground='red')

def select(value, x, y):
    if curBut != [-1,-1]:
        buttonL[curBut[0]][curBut[1]].configure(highlightbackground='#d9d9d9')
    curBut[:] = [x,y]
    buttonL[x][y].configure(highlightbackground='red')
    if value == "<-":
        input = entry.get("1.0", 'end-2c')
        entry.delete("1.0", END)
        entry.insert("1.0", input, END)

    elif value == " Space ":
        entry.insert(END, ' ')

    elif value == "Tab":
        entry.insert(END, '   ')

    else:
        entry.insert(END, value)

for button in buttons:
    if button != " Space ":
        but = Button(Keyboard_App, text=button, width=5, bg="#000000", fg="#ffffff", highlightthickness=4, 
                       activebackground="#ffffff", activeforeground="#000000", relief="raised", padx=12,
                       pady=4, bd=4, command=lambda x=button, i=varRow-1, j=varColumn: select(x, i, j))
        buttonL[varRow-1].append(but)
        but.grid(row=varRow, column=varColumn)

    if button == " Space ":
        but = Button(Keyboard_App, text=button, width=60, bg="#000000", fg="#ffffff", highlightthickness=4, 
                       activebackground="#ffffff", activeforeground="#000000", relief="raised", padx=4,
                       pady=4, bd=4, command=lambda x=button, i=varRow-1, j=varColumn: select(x, i, j))
        buttonL[varRow-1].append(but)
        but.grid(row=6, columnspan=16)

    varColumn  = 1
    if varColumn > 10:
        varColumn = 0
        varRow  = 1
        buttonL.append([])

Keyboard_App.bind('<Left>', leftKey)
Keyboard_App.bind('<Right>', rightKey)
Keyboard_App.bind('<Up>', upKey)
Keyboard_App.bind('<Down>', downKey)
Keyboard_App.mainloop()

 

Это вызывает сообщение об ошибке, _tkinter.TclError: cannot use geometry manager grid inside . which already has slaves managed by pack потому что я не могу использовать grid и то, и pack другое в одном кадре. Я так запутался в коде, например, как я должен это решить. Кто-нибудь может дать мне подсказку, как попасть на правильный путь, используя мой код? Спасибо.

Ответ №1:

Как указано в ошибке, вы просто не можете использовать оба grid и pack в одном фрейме. Вам нужно удалить вызов, чтобы .pack() он работал.

 canvas = Canvas(Keyboard_App, width=400, height=400)
canvas.place(x=0, y=0, relwidth=1, relheight=1)

background = PhotoImage(file="Images/background.png")
canvas.create_image(400,400,image=background, tags="B")
 

Вам также необходимо вызвать .place() его, чтобы узнать, где отображать в вашем окне. relwidth и relweight это только ширина и вес относительно основного объекта, и они здесь необязательны.

Обратите внимание, что это не приводит к правильному изменению размера изображения, хотя, если ваш старый код справился с этим. Я рекомендую использовать библиотеку PIL , если вы хотите изменить ее размер, я могу показать вам код, который будет работать в вашем случае; Я считаю, что это также возможно просто с вашим PhotoImage , но не практично.

Комментарии:

1. Спасибо за комментарий! Сделав это, эта ошибка была устранена, но можем ли мы сначала получить фоновое изображение, а затем VKeyboard и Entry на нем?

2. @Deepakpal Моя ошибка, я забыл, что у вас есть фоновое изображение. Я скоро отредактирую его.

3. @Deepakpal Отредактировал и добавил гораздо больше деталей!

4. Большое вам спасибо! Это работает!! Просто возникла одна проблема, когда я попытался заменить Entry на canvas.create_text , она показывает эту ошибку -> self.canvas_textbox.insert(END, value) AttributeError: 'int' object has no attribute 'insert'

5. @Deepakpal canvas_textbox В вашем коде этого нет, но, как указывает ошибка, это int то, для чего вы пытаетесь вызвать метод с именем .insert() , которого у него, очевидно, нет, поскольку это просто число.