'I need to understand why my tkinter code is implicitly running my bluetooth code without tkinter widget event occuring
It is unclear to me why my tkinter code used to present a top-level tkinter sub-screen called "connect screen" changes in its cosmetic display since I added my bluetooth code to this GUI program. Moreover, when you click on the "connect screen" button in the "main menu" screen and it spawns the top-level screen, this program will implicitly start scanning for bluetooth devices without clicking on the "scan button".
I would love to know why this above functionality is occurring I have zero idea as to why. The only documentation I have found about the potentially issue of this underlying problems was found at this website: https://gordonlesti.com/use-tkinter-without-mainloop/
I am extra curious as to know the underlying issues of this code. Moreover, potential fixes.
My Bluetooth code is below
import bluetooth
class AFLBBluetooth:
def __init__(self):
self.names_of_near_by_devices = []
self.address_of_near_by_devices = []
self.num_of_devices = 0
self.r_port = 1
self.backlog = 1
def isolate_device_data(self, devices):
"""
:param devices:
:return:
"""
for data in devices:
self.address_of_near_by_devices.append(str(data[0]))
self.names_of_near_by_devices.append(str(bluetooth.lookup_name(data[1])))
def look_for_devices(self):
"""
:return:
"""
nearby_devices = bluetooth.discover_devices(lookup_names=True)
self.num_of_devices = len(nearby_devices)
self.isolate_device_data(nearby_devices)
def bind(self, socket, mac_address):
trys = 3
while trys > 0:
try:
socket.bind(mac_address, self.r_port)
return 1
except bluetooth.btcommon.BluetoothError:
trys = trys - 1
self.r_port = self.r_port + 1
continue
return 0
def receive_messages(self, target_bluetooth_mac_address):
client = "" # this initialization has no affect on the code, just to satisfy the python interpreter.
size = 1024
s = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
if self.bind(s, target_bluetooth_mac_address) > 0:
s.listen(self.backlog)
try:
client, clientInfo = s.accept()
while 1:
data = client.recv(size)
if data:
print(data) # test to see if data was received
client.send(data) # Echo back to client
except bluetooth.btcommon.BluetoothError:
client.close()
s.close()
My tkinter code is below
import tkinter as tk
import threading
import bot_blue
class UnlockWindow:
def __init__(self, master):
self.m = master
self.win = tk.Toplevel(self.m)
self.setup_unlock_screen()
def setup_unlock_screen(self):
"""
:return:
"""
self.win.title("Unlock Screen")
self.win.geometry("480x320") # Size of the window
self.win.resizable(False, False)
self.win.maxsize(480, 320)
self.win.minsize(480, 320)
self.create_buttons_for_screen()
def create_buttons_for_screen(self):
"""
This function creates the functionality for each button in the main menu screen. It specifies the size,
padding, name, and function for each button in the container of the main menu widget screen.
"""
# setting up frames
text_frame = tk.Frame(self.win)
num_frame = tk.Frame(self.win)
action_frame = tk.Frame(self.win)
# packing each frame into the parent widget 'unlock_root[0]'
text_frame.pack(side=tk.TOP, expand=tk.YES)
num_frame.pack(side=tk.LEFT, expand=tk.YES)
action_frame.pack(side=tk.RIGHT, expand=tk.YES)
#
# text entry for displaying button presses in unlock screen
e = tk.Entry(text_frame, width=30, font=('arial', 18, 'bold'), fg="white", bg='#567', bd=5, )
bdin = 2
num_w = 10
act_w = 10
num_h = 3
act_h = 4
# num frame buttons
# The first row will comprise of the buttons '7', '8' , '9'
b7 = tk.Button(num_frame, text="7", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(7, e))
b8 = tk.Button(num_frame, text="8", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(8, e))
b9 = tk.Button(num_frame, text="9", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(9, e))
# The third row will comprise of the buttons '4', '5', '6'
b4 = tk.Button(num_frame, text="4", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(4, e))
b5 = tk.Button(num_frame, text="5", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(5, e))
b6 = tk.Button(num_frame, text="6", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(6, e))
# The third row will comprise of the buttons '1', '2', '3'
b1 = tk.Button(num_frame, text="1", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(1, e))
b2 = tk.Button(num_frame, text="2", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(2, e))
b3 = tk.Button(num_frame, text="3", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(3, e))
# the forth row will comprise of the buttons '0', 'backspace', 'clear'
b0 = tk.Button(num_frame, text="0", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.do_num_button(0, e))
bback = tk.Button(num_frame, text="<-", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.back_space(e))
bclear = tk.Button(num_frame, text="C", fg="white", bg='#567', width=num_w, height=num_h, bd=bdin, command=lambda: self.clear_button(e))
# action frame buttons
bUn = tk.Button(action_frame, fg="white", bg='#567', text="Unlock\nLid", width=act_w, height=act_h, command="")
bMain = tk.Button(action_frame, fg="white", bg='#567', text="Main Menu",width=act_w, height=act_h, command=self.return_to_main_menu)
# setting the geometry of each row
# row 1
e.grid(row=0, column=0, columnspan=3)
# row 2
b7.grid(row=0, column=0)
b8.grid(row=0, column=1)
b9.grid(row=0, column=2)
# row 3
b4.grid(row=1, column=0)
b5.grid(row=1, column=1)
b6.grid(row=1, column=2)
# row 4
b1.grid(row=2, column=0)
b2.grid(row=2, column=1)
b3.grid(row=2, column=2)
# row 5
bclear.grid(row=3, column=0)
b0.grid(row=3, column=1)
bback.grid(row=3, column=2)
# action buttons in action frame grid placement
bUn.grid(row=0, column=0)
bMain.grid(row=1, column=0)
def return_to_main_menu(self):
"""
:return:
"""
self.win.destroy()
def unlock_button(self, container):
"""
:return:
"""
current = container.get()
if len(current) < 4:
return
def clear_button(self, container):
"""
:param container:
:return:
"""
container.delete(0, tk.END)
def back_space(self, container):
"""
:param container:
:return:
"""
current = container.get()
new_length = len(current) - 1
container.delete(new_length, tk.END)
def do_num_button(self, button_function, container):
""" Function is the action taken by a number button in the Unlock Screen GUI """
current = container.get()
if len(current) >= 10:
return
self.clear_button(container)
container.insert(0, str(current) + str(button_function))
class ConnectScreen:
def __init__(self, master):
self.m = master
self.win = tk.Toplevel(self.m)
self.setup_connect_screen()
def setup_connect_screen(self):
"""
This function is called to initial all attributes for establishing the connect screen of the
Auto Follow Locker Bot.
"""
self.win.title("Connect Screen")
self.win.geometry("480x320") # Size of the window
self.win.resizable(False, False)
self.win.maxsize(480, 320)
self.win.minsize(480, 320)
self.put_buttons_on_screen()
def return_to_main_menu(self):
"""
:return:
"""
self.win.destroy()
def do_scan(self, list_box_container):
"""
:param list_box_container:
:return:
"""
addrs, names = self.scan_for_devices()
if not addrs:
list_box_container.insert(0, "No Bluetooth Devices Found")
else:
for i in range(len(names)):
list_box_container.insert(i, names[i] + " " + addrs[i])
def scan_for_devices(self):
"""
:return:
"""
b = bot_blue.AFLBBluetooth()
b.look_for_devices()
if b.num_of_devices:
return b.address_of_near_by_devices, b.names_of_near_by_devices
return None, None
def item_selected(self, listbox):
"""
:return:
"""
selected_bluetooth_device = listbox.curselection()
if selected_bluetooth_device:
return selected_bluetooth_device[1]
return None
def do_discovery(self):
pass
# b = bot_blue.AFLBBluetooth()
# b.bluetooth_setup()
def put_buttons_on_screen(self):
"""
:return:
"""
# creating appropriate frames for organization purposes of the connect screen GUI
entry_frame = tk.Frame(self.win)
button_frame = tk.Frame(self.win)
xtra = tk.Frame(self.win)
# positioning frames in a compositional way as desired by the creator
entry_frame.pack(side=tk.RIGHT, expand=tk.YES)
button_frame.pack(side=tk.LEFT, expand=tk.YES)
xtra.pack(side=tk.TOP, expand=tk.YES)
# creating a list box for displaying all bluetooth connection, device, metadata to connect screen
connections = tk.Listbox(entry_frame, width=20, height=7, font=('arial', 18, 'bold'), fg="white", bg='#567', bd=5, selectmode='single')
con_sbv = tk.Scrollbar(entry_frame, width=30, highlightcolor="white", bg='#567', bd=5, orient=tk.VERTICAL)
con_sbh = tk.Scrollbar(entry_frame, width=30, highlightcolor="white", bg='#567', bd=5, orient=tk.HORIZONTAL)
connections.bind('<<ListboxSelect>>', self.item_selected(connections))
# configuring both horizontal and vertical scroll bars of the list box, so the user can scroll and see all
# bluetooth devices in the area and their corresponding metadata
connections.configure(yscrollcommand=con_sbv.set)
connections.configure(xscrollcommand=con_sbh.set)
con_sbv.config(command=connections.yview)
con_sbh.config(command=connections.xview)
# creating button widgets for functionality of the 'connect screen' of the micro controller
scan = tk.Button(button_frame, text="scan", fg="white", bg='#567', width=8, height=5, bd=4,
command=threading.Thread(target=self.do_scan, args=[connections]).start())
discover = tk.Button(button_frame, text="Make Discoverable", fg="white", bg='#567', width=13, height=4, bd=4,
command=threading.Thread(target=self.do_discovery).start())
main_m = tk.Button(button_frame, text="Main Menu", fg="white", bg='#567', width=5, height=5, bd=4,
command=self.return_to_main_menu)
# positioning 'list text widget' in the 'entry_frame'
connections.grid(row=0, column=0)
# positioning 'scroll bars' in the 'entry_frame'
con_sbv.grid(row=0, column=1)
con_sbh.grid(row=1, column=0)
# positioning buttons 'disconnect', 'discover', 'back to main menu' in the button_frame
discover.grid(row=0, column=0)
scan.grid(row=1, column=0)
main_m.grid(row=2, column=0)
class MainMenu:
def __init__(self, master):
self.master = master
self.button_h = 3
self.button_w = 10
self.bdin = 4
def setup_main_menu(self):
"""
:return:
"""
self.master.geometry("480x320")
self.master.title("Auto Follow Locker Bot")
self.master.resizable(False, False)
self.master.maxsize(480, 320)
self.master.minsize(480, 320)
self.do_main_menu_screen()
def do_main_menu_screen(self):
"""
:return:
"""
main_menu_label_frame = tk.Frame()
buttons_frame = tk.Frame()
xtra_buttons_frame = tk.Frame()
main_menu_label_frame.pack(side=tk.TOP, expand=tk.YES)
buttons_frame.pack(side=tk.LEFT, expand=tk.YES)
xtra_buttons_frame.pack(side=tk.RIGHT, expand=tk.YES)
label1 = tk.Label(main_menu_label_frame, text="Main Menu", font=('arial', 16, 'bold'))
label1.pack()
un = tk.Button(buttons_frame, text="Unlock Screen", fg="white", bg='#567', width=self.button_w,
height=self.button_h, bd=self.bdin, command=self.do_unlock_window)
con = tk.Button(buttons_frame, text="Connect Screen", fg="white", bg='#567', width=self.button_w,
height=self.button_h, bd=self.bdin, command=self.do_connect_window)
ex = tk.Button(buttons_frame, text="Exit", fg="white", bg='#567', width=self.button_w,
height=self.button_h, bd=self.bdin, command=exit)
un.grid(row=0, column=0)
con.grid(row=1, column=0)
ex.grid(row=2, column=0)
def do_unlock_window(self):
doun = UnlockWindow(self.master)
doun.win.mainloop()
def do_connect_window(self):
docon = ConnectScreen(self.master)
docon.win.mainloop()
root = tk.Tk()
main = MainMenu(root)
main.setup_main_menu()
root.mainloop()
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
