Tkinter Chatbot Speech Bubbles design - python-3.x

First I'm sorry for my bad english. I am designing a chatbot with the tkinter as an amateur. I want to add whatsapp-like balloons to the dialog window. I also want the writings to go from the bottom up in the window. I tried to do it as a canvas but it didn't happen. I tried as a label but gave an error.I'd appreciate it if you could help me with that. "TypeError: can only concatenate str (not "Canvas") to str".
The sample design I want
import tkinter as tk
from tkinter import *
import random
import re
import datetime
from tkinter import messagebox
from tkinter.font import Font
root = tk.Tk()
root.title('deneme')
root.geometry('410x600+400+100')
root.config(bg='lightblue')
buton_işlevi=StringVar(root)
buton_işlevi.set("")
#buton oluşturma ve konumu
buton = tk.Button(root, width=10, height=2, relief='raised',state='active',command=lambda :add_text(pencere,giriş,buton_işlevi))
buton.pack()
buton.place(x=310, y=550)
buton.config(text='GÖNDER', bg='lightblue', font='Verdana 8 bold')
root.bind('<Return>',lambda x:add_text(pencere,giriş,buton_işlevi))
#mesaj yazma alanı ve konumu
giriş = tk.Entry(root, textvariable=buton_işlevi,font=('NanumGothic', 12))
giriş.pack()
giriş.place(x=10, y=550, width=290, height=40)
canvas = Canvas(width=300, height=300, bg='white')
canvas.create_oval(200, 200, 300, 300, width=5, fill='red')
#pencere ve konumu
pencere = tk.Text(root, bg='white', yscrollcommand='YES', font=('NanumGothic', 12))
pencere.config(state='disabled')
pencere.pack()
pencere.place(x=10, y=10, width=390, height=530)
#bot ve user mesaj arka plan rengi
pencere.tag_config('bot_renk', background='#fccbc7', foreground='black')
pencere.tag_config('user_renk', background='yellow')
pencere.config(state='normal')
#bot karşılama mesajı
karşılama = 'Hoşgeldiniz'
soru1 = ['merhaba', 'selam']
cevap1 = ["sanada", "iyiyim"]
soru2 = ["deneme", "merhaba", "selam"]
pencere.insert('end', '\nBOT:\t')
pencere.insert('end', karşılama +'\n', 'bot_renk')
#Mesaj ayarları
def add_text(mw,st,imsg):
#mw:message window/st:state/imsg:input message
bot_mesaj=""
user_mesaj = imsg.get()
if user_mesaj in soru1:
user_mesaj='\nUSER :\t'+imsg.get()+'\n'+canvas
bot_mesaj = '\nBOT :\t'+ random.choice(cevap1)+'\n'
mw.config(state='normal')
mw.insert('end',user_mesaj, 'user_renk')
mw.insert('end',bot_mesaj, 'bot_renk')
imsg.set("")
mw.see('end')
mw.config(state='disabled')
elif user_mesaj in soru2:
user_mesaj='\nERÇİN :\t'+imsg.get()+'\n'
bot_mesaj='\nBOT :\t'+ random.choice(cevap2)+'\n'
mw.config(state='normal')
mw.insert('end',user_mesaj, 'user_renk')
mw.insert('end',bot_mesaj, 'bot_renk')
imsg.set("")
mw.see('end')
mw.config(state='disabled')
else :
user_mesaj='\nUSER:\t' +imsg.get()+'\n'
bot_mesaj='\nBOT:\t' + 'Bu kelimeyi henüz öğrenmedim' +'\n'
mw.config(state='normal')
mw.insert('end',user_mesaj, 'user_renk')
mw.insert('end',bot_mesaj, 'bot_renk')
imsg.set("")
mw.see('end')
mw.config(state='disabled')
root.mainloop()

I ran your code and there is no error. But since you mentioned about Whatsapp bubble, here is a basic version you can work on.
from tkinter import *
from datetime import datetime
root = Tk()
root.config(bg="lightblue")
canvas = Canvas(root, width=200, height=200,bg="white")
canvas.grid(row=0,column=0,columnspan=2)
bubbles = []
class BotBubble:
def __init__(self,master,message=""):
self.master = master
self.frame = Frame(master,bg="light grey")
self.i = self.master.create_window(90,160,window=self.frame)
Label(self.frame,text=datetime.now().strftime("%Y-%m-%d %H:%m"),font=("Helvetica", 7),bg="light grey").grid(row=0,column=0,sticky="w",padx=5)
Label(self.frame, text=message,font=("Helvetica", 9),bg="light grey").grid(row=1, column=0,sticky="w",padx=5,pady=3)
root.update_idletasks()
self.master.create_polygon(self.draw_triangle(self.i), fill="light grey", outline="light grey")
def draw_triangle(self,widget):
x1, y1, x2, y2 = self.master.bbox(widget)
return x1, y2 - 10, x1 - 15, y2 + 10, x1, y2
def send_message():
if bubbles:
canvas.move(ALL, 0, -65)
a = BotBubble(canvas,message=entry.get())
bubbles.append(a)
entry = Entry(root,width=26)
entry.grid(row=1,column=0)
Button(root,text="Send",command=send_message).grid(row=1,column=1)
root.mainloop()

Related

How to add more speech bubbles? - Tkinter Chatbot

I've been working on a chatbot in tkinter and have been using this, https://stackoverflow.com/a/56032923/12406236 as a starting point for my code. I want to be able to add more speech bubbles (I can only make three) and then scroll through them.
How would I be able to accomplish this?
My code:
from tkinter import *
root = Tk()
frame = Frame(root,width=200,height=200)
frame.grid(row=0,column=0,columnspan=2)
canvas = Canvas(frame,bg="white",width=300,height=300,scrollregion=(0,0,500,500))
canvas.pack(side=LEFT,expand=True,fill=BOTH)
vbar = Scrollbar(frame,orient="vertical",command=canvas.yview)
vbar.pack(side=RIGHT,fill=Y)
canvas.configure(yscrollcommand=vbar.set)
bubbles = []
class BotBubble:
def __init__(self,master,message=""):
self.master = master
self.frame = Frame(master,bg="light grey")
self.i = self.master.create_window(90,160,window=self.frame)
Label(self.frame, text=message,font=("Helvetica", 9),bg="light grey").grid(row=1,column=0)
root.update_idletasks()
self.master.create_polygon(self.draw_triangle(self.i),fill="light grey",outline="light grey")
def draw_triangle(self,widget):
x1, y1, x2, y2 = self.master.bbox(widget)
return x1, y2 - 8, x1 - 10, y2 + 5, x1, y2
def send_message(event):
if bubbles:
canvas.move(ALL, 0, -65)
a = BotBubble(canvas,message=entry.get())
bubbles.append(a)
entry = Entry(root,width=100)
entry.grid(row=1,column=0)
entry.bind("<Return>",send_message)
root.mainloop()
I have modified your code:
do not set scrollregion when creating canvas
update scrollregion of canvas after new bubble is added or window is resized
do not scroll up old bubbles, just add the new bubble below last bubble
Updated code:
from tkinter import *
root = Tk()
frame = Frame(root)
frame.pack(fill=BOTH, expand=1)
canvas = Canvas(frame, bg="white")
canvas.pack(side=LEFT, expand=True, fill=BOTH)
vbar = Scrollbar(frame, orient="vertical", command=canvas.yview)
vbar.pack(side=RIGHT, fill=Y)
canvas.configure(yscrollcommand=vbar.set)
bubbles = []
LINE_GAP = 10 # gap between bubbles
class BotBubble:
def __init__(self, master, message=""):
self.master = master
self.frame = Frame(master, bg="light grey")
bbox = self.master.bbox(ALL)
y = (bbox[3] if bbox else 0) + LINE_GAP
self.i = self.master.create_window(15, y, window=self.frame, anchor='nw')
Label(self.frame, text=message, font=("Helvetica",9), bg="light grey").grid(row=1, column=0)
self.master.update()
self.master.create_polygon(self.draw_triangle(self.i), fill="light grey", outline="light grey")
def draw_triangle(self,widget):
x1, y1, x2, y2 = self.master.bbox(widget)
return x1, y2-8, x1-10, y2+5, x1, y2
def update_scrollregion(event=None):
canvas.config(scrollregion=canvas.bbox(ALL))
canvas.yview_moveto(1) # scroll to bottom
def send_message(event):
a = BotBubble(canvas, message=entry.get())
bubbles.append(a)
update_scrollregion()
entry = Entry(root, width=100)
entry.pack(fill=X)
entry.bind("<Return>", send_message)
entry.focus_force()
frame.bind('<Configure>', update_scrollregion)
root.mainloop()

How do I capture keystrokes directly on the tkinter canvas?

I'm having trouble capturing keystrokes from the tkinter canvas. The keystroke is captured properly if I bind it to a label widget but not to the canvas. My code is here:
from tkinter import *
root = Tk()
class keyPresser():
# For test purposes, move the rectangle and print a message.
# Nothing is happening
def handle_down_key(self,event):
self.canvas.focus_set()
self.canvas.move(self.rectangle,10,10)
print('Down arrow key pressed')
def __init__(self):
self.canvas = Canvas(root, width=400, height=400)
self.rectangle = self.canvas.create_rectangle(
0, 0, 20, 20, fill = "black")
self.canvas.bind("<Down>", self.handle_down_key)
self.canvas.focus()
self.canvas.pack()
mm = keyPresser()
root.mainloop()
Thanks for any suggestions.
Here you go !
from tkinter import *
root = Tk()
class keyPresser():
# For test purposes, move the rectangle and print a message.
# Nothing is happening
def handle_down_key(self, event):
self.canvas.focus_set()
self.canvas.move(self.rectangle, 10, 10)
print('Down arrow key pressed')
def __init__(self):
self.canvas = Canvas(root, width=400, height=400)
self.rectangle = self.canvas.create_rectangle(
0, 0, 20, 20, fill="black")
root.bind("<Down>", self.handle_down_key)
self.canvas.focus()
self.canvas.pack()
mm = keyPresser()
root.mainloop()

TKinter Splashscreen not working for GUI based application for Python 3.6

I am trying to build a GUI based code, where there will be a splashcreen, a wait for 5 seconds and then the main GUI should show up. I am using Python 3.6. Here is my code:
from tkinter import Tk, PhotoImage, Canvas, Label
from time import sleep
root = Tk()
root.overrideredirect(True)
width = root.winfo_screenwidth()
height = root.winfo_screenheight()
image_file = 'splash_fig.png'
splashImage = PhotoImage(file = image_file)
w = splashImage.width()
h = splashImage.height()
y = int((height - h) / 2)
x = int((width - w) / 2)
root.geometry('%dx%d+%d+%d' % (w,h,x,y))
canvas = Canvas(root,height = h, width = w, bg = "brown")
canvas.create_image(0,0,image = splashImage, anchor='nw')
canvas.pack()
root.after(5000, root.destroy)
root.mainloop()
root = Tk()
my_label = Label(root, text="Something something")
my_label.pack()
root.mainloop()
What is happening is that the splashscreen does not show up, but the second GUI does! Where is the exact problem here! My question is an extension to this question, where I have closely followed the solution proposed

How to add background image to my application in Tkinter?

The code picture needs to fit the screen size perfectly. I saw a bunch of tutorials but nothing seems to work.I tried adding a canvas but it covers half the screen.All my buttons go under the image itself not over it. It's getting on my nerves .
here's my code :
import tkinter as tk
import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
w = Label(root, text="Send and receive files easily")
w.config(font=('times', 32))
w.pack()
def create_window():
window = tk.Toplevel(root)
window.geometry("400x400")
tower= PhotoImage(file="D:/icons/tower.png")
towlab=Button(root,image=tower, command=create_window)
towlab.pack()
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Bifrost v1.0")
self.pack(fill=BOTH, expand=1)
self.img1 = PhotoImage(file="D:/icons/download.png")
self.img2 = PhotoImage(file="D:/icons/upload.png")
sendButton = Button(self, image=self.img2)
sendButton.place(x=305, y=15)
receiveButton = Button(self, image=self.img1)
receiveButton.place(x=355, y=15)
menu = Menu(self.master)
self.master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
top = Toplevel()
msg = Message(top, text="This is a project developed by Aditi,Sagar and
Suyash as the final year project.",
font=('', '15'))
msg.pack()
top.geometry('200x200')
button = Button(top, text="Okay", command=top.destroy)
button.pack()
top.mainloop()
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()
Overlaying elements is tricky. I think this might be approximately what you're looking for. At least it's a start...
import PIL
from PIL import Image, ImageTk
from tkinter import *
from tkinter import filedialog
from tkinter import messagebox
root = Tk()
class Window:
def __init__(self, master=None):
tower = PIL.Image.open("Images/island.png")
master.update()
win_width = int(master.winfo_width())
win_height = int(master.winfo_height())
# Resize the image to the constraints of the root window.
tower = tower.resize((win_width, win_height))
tower_tk = ImageTk.PhotoImage(tower)
# Create a label to hold the background image.
canvas = Canvas(master, width=win_width, height=win_height)
canvas.place(x=0, y=0, anchor='nw')
canvas.create_image(0, 0, image=tower_tk, anchor='nw')
canvas.image = tower_tk
frame = Frame(master)
frame.place(x=win_width, y=win_height, anchor='se')
master.update()
w = Label(master, text="Send and receive files easily", anchor='w')
w.config(font=('times', 32))
w.place(x=0, y=0, anchor='nw')
master.title("Bifrost v1.0")
self.img1 = PhotoImage(file="Images/logo.png")
self.img2 = PhotoImage(file="Images/magnifier.png")
frame.grid_columnconfigure(0, weight=1)
sendButton = Button(frame, image=self.img2)
sendButton.grid(row=0, column=1)
sendButton.image = self.img2
receiveButton = Button(frame, image=self.img1)
receiveButton.grid(row=0, column=2)
receiveButton.image = self.img1
menu = Menu(master)
master.config(menu=menu)
file = Menu(menu)
file.add_command(label='Exit', command=self.client_exit)
menu.add_cascade(label='File', menu=file)
edit = Menu(menu)
edit.add_command(label='abcd')
menu.add_cascade(label='Edit', menu=edit)
help = Menu(menu)
help.add_command(label='About Us', command=self.about)
menu.add_cascade(label='Help', menu=help)
def callback():
path = filedialog.askopenfilename()
e.delete(0, END) # Remove current text in entry
e.insert(0, path) # Insert the 'path'
# print path
w = Label(root, text="File Path:")
e = Entry(root, text="")
b = Button(root, text="Browse", fg="#a1dbcd", bg="black", command=callback)
w.pack(side=TOP)
e.pack(side=TOP)
b.pack(side=TOP)
def client_exit(self):
exit()
def about(self):
message = "This is a project developed by Aditi,Sagar and"
message += "Suyash as the final year project."
messagebox.showinfo("Delete Theme", message)
root.resizable(0,0)
#size of the window
root.geometry("700x400")
app = Window(root)
root.mainloop()

migrate tkinter code to pyqt

I am trying to migrate the code below (which is in tkinter) to pyqt. I am very new to pyqt. I could not get much details.
import os, sys, time
import os.path
import shutil
import sys
import Tkinter as tk
from Tkinter import *
root = Tk()
frame = Frame(root)
def enable_():
# Global variables
if (var.get()==1):
E5.config(state=NORMAL)
E5.insert(0, 1)
for c in checkbuttons:
c.config(state=NORMAL)
# disable test selection
else:
E5.delete(0, END)
E5.config(state=DISABLED)
for c in checkbuttons:
c.config(state=DISABLED)
# Select geometry
root.geometry("500x570+500+300")
root.title('Test Configure')
# Global variable declaration
global row_me
global col_me
row_me =9
col_me =0
L1 = Label ().grid(row=0,column=1)
Label (text='Target IP Address').grid(row=1,column=0)
E4 = Entry(root, width=20)
E4.grid(row=1,column=1)
L1 = Label ().grid(row=2,column=1)
variable = StringVar()
# Check button creation
var = IntVar()
var_mail = IntVar()
# Create check buttons
R1=Checkbutton(root, text = "Enable Test Suite Selection", variable = var, \
onvalue = 1, offvalue = 0, height=1, \
width = 20, command=enable_)
R1.grid(row=3,column=1)
R2=Checkbutton(root, text = "Send Email", variable = var_mail, \
onvalue = 1, offvalue = 0, height=1, \
width = 20)
R2.grid(row=3,column=2)
L5 = Label (text='Number of Loop').grid(row=4,column=0)
E5 = Entry(root, width=5)
E5.grid(row=4,column=1)
E5.config(state=DISABLED)
L2 = Label ().grid(row=21,column=1)
# List of Tests
bottomframe = Frame(root)
bottomframe.grid(row=24,column=1)
# Reset Button
configbutton = Button(bottomframe, text="Reset", fg="black")
configbutton.grid(row=24,column=2,padx=5, pady=0)
# Quit Button
configbutton = Button(bottomframe, text="Quit", fg="red")
configbutton.grid(row=24,column=3)
# Submit Button
blackbutton = Button(bottomframe, text="Submit", fg="black")
blackbutton.grid(row=24,column=4,padx=5, pady=0)
#Check buttons for test suite selection
test_suite_name=[name for name in os.listdir(".") if (os.path.isdir(name) and name.startswith('test-') )]
L34 = Label (text='Select Test Suite To Be Executed').grid(row=7,column=1)
L11 = Label ().grid(row=9,column=1)
row_me =9
col_me =0
checkbuttons = [create_checkbutton(name) for name in test_suite_name ]
for c in checkbuttons:
c.config(state=DISABLED)
# initiate the loop
root.mainloop()
I have written this code but I am not sure how to make the grid and location for each widget in pyqt:
import sys
from PyQt4 import QtGui
class Example(QtGui.QWidget):
def __init__(self):
super(Example, self).__init__()
self.initUI()
def initUI(self):
SubmitButton = QtGui.QPushButton("OK")
CancelButton = QtGui.QPushButton("Cancel")
ResetButton = QtGui.QPushButton("Reset")
edit1 = QLineEdit()
edit2 = QLineEdit()
cb = QtGui.QCheckBox('Enable Test suite selection', self)
cb.move(150, 100)
#cb.stateChanged.connect(self.changeTitle)
cb2 = QtGui.QCheckBox('Send mail', self)
cb2.move(300, 100)
# cb2.stateChanged.connect(self.changeTitle)
hbox = QtGui.QHBoxLayout()
hbox.addStretch(1)
hbox.addWidget(SubmitButton)
hbox.addWidget(CancelButton)
hbox.addWidget(ResetButton)
hbox.addWidget(edit1)
hbox.addWidget(edit2)
hbox.addWidget(cb)
hbox.addWidget(cb2)
vbox = QtGui.QVBoxLayout()
vbox.addStretch(1)
vbox.addLayout(hbox)
self.setLayout(vbox)
self.setGeometry(100, 100, 500, 650)
self.setWindowTitle('HMI')
self.show()
def main():
app = QtGui.QApplication(sys.argv)
ex = Example()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Thank you!
You can either do the designing part in your code or through a QT Designer which ships with PyQt4. and some examples can be found in the path C:\Python26\Lib\site-packages\PyQt4\examples and documentation in the path C:\Python26\Lib\site-packages\PyQt4\doc\html\modules.html if you are using windows. Hope this helps.

Resources