tkinter need to click in shell to get gui fields to update - python-3.x

I have a tkinter gui with Python 3.4.2 in which there are various buttons, a user entry field and a text field. Everything works except that I appear to have to click in the Python shell (IDLE) and out of the gui to get fields to update in response to button presses. The updates are immediate when I click on the shell. I have copied this tkintergui from http://ubuntuforums.org/showthread.php?t=1156637 which gives the same problem on my Mac. Immediate update if IDLE shell clicked or very slow update in the GUI
#!/usr/bin/python
from tkinter import *
from tkinter.filedialog import *
class SimpleEdApp:
def __init__(self, parent=Tk()):
self.mainWindow = (parent)
self.mainWindow.title("Simple Editor")
self.mainWindow.resizable(0, 0)
self.make_mnu()
self.make_txt()
def make_txt(self):
self.text = Text(self.mainWindow, width = 80, height = 40, background = 'white')
self.scrollY = Scrollbar(self.mainWindow, orient = VERTICAL, command = self.text.yview, troughcolor = 'white')
self.text["yscrollcommand"] = self.scrollY.set
self.scrollY.pack(side = RIGHT, fill = Y)
self.text.pack(expand = TRUE, fill = BOTH)
def make_mnu(self):
self.menubar = Menu(self.mainWindow)
self.filemenu = Menu(self.menubar, tearoff = 0)
self.filemenu.add_command(label = "Open", command = self.file_open)
self.filemenu.add_command(label = "Save as...", command = self.file_save)
self.filemenu.add_separator()
self.filemenu.add_command(label = "Exit", command = self.mainWindow.destroy)
self.menubar.add_cascade(label = "File", menu = self.filemenu)
self.mainWindow.config(menu = self.menubar)
def file_open(self):
filename =askopenfilename(filetypes=[("pythonfiles","*.py"),("tclfiles","*.tcl"),("allfiles","*")])
f = open(filename, 'r')
data = f.read()
f.close()
self.text.delete(1.0, END)
self.text.insert(1.0, data)
def file_save(self):
filename =asksaveasfilename(filetypes=[("pythonfiles","*.py"),("tclfiles","*.tcl"),("allfiles","*")])
f = open(filename, 'w')
data = self.text.get(1.0, END)
f.write(data)
f.close()
app = SimpleEdApp()
app.mainWindow.mainloop()
Grateful for correct implementation

There is nothing wrong with your code. This looks to be a bug in IDLE.
In the comments you asked how to run the program outside of IDLE. To do that, open up a prompt and type the command python myfile.py, where myfile.py is the name of your python file (assuming "python" is in your PATH).
*note: depending on what is installed in your system, you may need to use python3 rather than python.

Related

How to remove the option to select what's inside a text widget, (not by using state = disabled)

I have tried using exportselection = False
this is the code I use to get the input from the user, if the user is highlighting the text widget (while inputting their answer), they are able to edit where the input get's printed
import tkinter as tk
from tkinter import ttk
window = tk.Tk()
numb_of_times = 5
window.geometry('1920x1080')
window.configure(bg = 'blue')
input_board = tk.Text(window,state = "disabled")
input_board.pack()
input_board.place(x = 100,y = 40)
def send():
input_board.configure(state="normal")
input_board.insert(tk.INSERT, '%s\n' % user_input)
input_board.configure(state="disabled")
for i in range(numb_of_times):
user_input = input()
print(user_input)
send()
window.mainloop()
I have tried using exportselection = False
When the selection changes in the text widget, it emits a <<Selection>> event. You can bind to that event and remove the selection. This should prevent any text from being selected.
The selection is represented by the tag "sel", which you can pass to tag_remove.
The solution might look something like this:
def remove_selection(event):
event.widget.tag_remove("sel", "1.0", "end")
input_board.bind("<<Selection>>", remove_selection)

'Exception in tkinter callback' and '[Errno 24] Too many open files.'

quite new to Python and come across a problem that I'm struggling to diagnose.
I am working on a project involving a Tkinter menu and using an ADC connected to a potentiometer (which will hopefully be replaced by a muscle sensor once I've gotten the essential code working). I am using a raspberry Pi and breadboard for this, with my IDE as Thonny.
The imports are:
from time import sleep
import busio
import digitalio
import board
import adafruit_mcp3xxx.mcp3008 as ADC
from adafruit_mcp3xxx.analog_in import AnalogIn
import tkinter as tk
from tkinter import Menu
import easygui
import RPi.GPIO as GPIO
The overall menu and code works until I try to use the Run() function, which uses all of the files and compares AnalogIn to a threshold value previously found. When the Run button is clicked, it comes up with the error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib/python3.9/tkinter/__init__.py", line 1892, in __call__
File "/home/pi/Documents/NEA_Python/NEA2023.py", line 280, in Run
File "/usr/local/lib/python3.9/dist-packages/adafruit_mcp3xxx/analog_in.py", line 53, in value
File "/usr/local/lib/python3.9/dist-packages/adafruit_mcp3xxx/mcp3xxx.py", line 80, in read
File "/usr/local/lib/python3.9/dist-packages/adafruit_bus_device/spi_device.py", line 93, in __enter__
File "/usr/local/lib/python3.9/dist-packages/busio.py", line 335, in configure
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 650, in any_embedded_linux
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 532, in any_raspberry_pi
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/board.py", line 205, in _pi_rev_code
File "/usr/local/lib/python3.9/dist-packages/adafruit_platformdetect/__init__.py", line 42, in get_cpuinfo_field
OSError: [Errno 24] Too many open files: '/proc/cpuinfo'
Run() Function code:
def Run():
threshold_valid = False
output_valid = False
#validity checks for all necessary fields
if threshold_valid == False:
thres = open('Threshold.txt', 'r')
threshold = thres.read()
if threshold == '':
print("Missing threshold voltage. Please refer to Main Menu/Options/Edit Muscle Data/Find threshold voltage")
else:
threshold_valid = True
if output_valid == False:
output = open('OutputOption.txt', 'r')
outputOption = output.read()
if outputOption == '':
print("Missing output option. Please refer to Main Menu/Options/Edit Muscle Data/Choose output/ in order to select output")
elif outputOption == 'notification':
with open('Message.txt', 'r') as message:
if message.read() == '':
print("Missing message to display. Please refer to Main Menu/Options/Edit Muscle Data/Choose output/Display message/")
else:
output_valid = True
message.close()
elif outputOption() == 'LED':
output_valid = True
else:
print("Something went wrong. Try deleting stored data at Main Menu/Options/Edit Muscle Data/Delete Data/ and try again")
while threshold_valid == True and output_valid == True:
spiBus = busio.SPI(clock=board.SCK, MISO=board.MISO, MOSI=board.MOSI)
# create the chip select
chipSelect = digitalio.DigitalInOut(board.D22)
#creates the object for adc
adc = ADC.MCP3008(spiBus, chipSelect)
#creates analogue input channel on ADC's pin 0
analogueInChan = AnalogIn(adc, ADC.P0)
instantaneousAIn = analogueInChan.value
if instantaneousAIn> int(threshold):
if outputOption == 'LED':
output_flashLED()
elif outputOption == 'notification':
output_notification()
thres.close()
output.close()
All of the validity checks for this work fine, but it fails once it reaches the part inside the 'while threshold_valid == True and output_valid == True:' statement.
The menu is a menubar with cascade menus coming off of it.
The Tkinter menu code is:
#Root window
root = tk.Tk()
root.title("Main Menu")
#Creates a menubar
menubar = Menu(root, bg = 'powderblue', activebackground = '#84b7c4', tearoff = 0)
root.config(menu = menubar)
#Creates the main menu with the menubar as its parent window
#bg is the natural background colour, activebackground is the colour when the mouse hovers over it
main_menu = Menu(menubar, bg = 'lightcyan', activebackground = 'powderblue', tearoff = 0)
#Adds option to main_menu
main_menu.add_command(
label = "Instructions",
command = instructions
)
main_menu.add_command(
label= "Run",
command = Run
)
#Adds the main_menu as cascade to the menubar
menubar.add_cascade(
label = "Options",
menu = main_menu
)
#Creates menu muscleData_menu with main_menu as parent window
muscleData_menu = Menu(main_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')
#Adds option to muscleData_menu
muscleData_menu.add_command(
label = "Instructions",
command = instructions
)
muscleData_menu.add_command(
label = "Find threshold voltage",
command = findThreshold
)
#Creates menu output_menu with muscleData_menu as parent window
output_menu = Menu(muscleData_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')
#Adds option to output_menu
output_menu.add_command(
label = "Flash LED",
command = menuoption_flashLED
)
output_menu.add_command(
label = "Display message",
command = menuoption_notification
)
#Adds output_menu as cascade within muscleData_menu
muscleData_menu.add_cascade(
label = "Choose output",
menu = output_menu
)
#Creates menu deleteData_menu with muscleData_menu as parent window
deleteData_menu = Menu(muscleData_menu, tearoff = 0, bg = 'lightcyan', activebackground = 'powderblue')
#Adds option to deleteData_menu
deleteData_menu.add_command(
label = "Delete stored threshold voltage",
command = deleteThreshold
)
deleteData_menu.add_command(
label = "Delete stored output option",
command = deleteOutput
)
deleteData_menu.add_command(
label = "Delete stored notification message",
command = deleteMessage
)
deleteData_menu.add_command(
label = "Delete all stored data",
command = wipeData
)
#adds deleteData_menu as cascade to the muscleData_menu
muscleData_menu.add_cascade(
label = "Delete stored data",
menu = deleteData_menu
)
muscleData_menu.add_command(
label = "Run",
command = Run
)
#Adds muscleData_menu as cascade within main_menu
main_menu.add_cascade(
label = "Edit Muscle Data",
menu = muscleData_menu,
)
#Ends menu program
#root.destroy completely erases root/menu
main_menu.add_command(
label = "Quit",
command=root.destroy,
)
#Runs menu continuously until quit, awaiting user inputs
root.mainloop()
The actual menu works fine, the issue resides inside of the Run() function, however it is a Tkinter related issue. As I understand it, the menu works by the root looping continuously in the background whilst allowing other parts of the code to work, so this may be the issue but I'm not sure how to fix it. I have checked and in all instances of me opening the textfiles across the code, I have closed them again directly after. I have changed the ulimit and it continues to show the same error. I couldn't find a working solution in other stackoverflow answers and so believed it was an issue more localised to my exact code, but apologies if this is a repetition.
The full code is in this google doc, if anyone finds it relevant:
https://docs.google.com/document/d/1Oj5M6jSTXepXSBm9kjj4o_41AN4IhGcgc63iedZSMdQ/edit?usp=sharing
Can you limit the number of files that have to be open at the same time?
I was also reading from this thread,
IOError: [Errno 24] Too many open files:
Please have a look , it might help.
You need to use a with block to deal with your files, so they actually get closed and you won't run out of file descriptors.
Replace things like
thres = open('Threshold.txt', 'r')
threshold = thres.read()
with
with open('Threshold.txt', 'r') as f:
threshold = f.read()

python : tkinter treeview colors are not updating

This is my first post, please excuse me if I made mistake in the format, I will gladly change it if required.
I'm creating an interface for scientific datas analysis using Tkinter. For a list of molecules, four can be represented in separate plots. On the side, I use a Treeview to show some numbers about all molecules. (not just the displayed ones) When a treeview row is about a displayed plot, i want that row's text to be the same color.
For each displayed graph, I place a different tag on the row that represents it and then use the tag method to change the foreground color to the plot's color.
The code used to work fine, but now it has stopped working without any changes to the my code. The setting of the foreground color with the tags doesn't change the color. A few lines later, I also use that method to change a row to be bold and it works fine.
I managed to confirm that the lines of code are read correctly : if i set the color to a value that is unrecognized, i get a tkinter error when executing as expected. Furthermore, using some prints, the if/elif are executed as expected at the correct moment (no error in the logic tests).
The code works fine on another computer leading me to believe there is a problem with some python packages. The two computers have the same ttk version (0.3.1) and I updated all my modules after noticing the problem to be sure it is not an outdated package.
The only change that was made to the computer is the removal and re-installation of anaconda and the environment now with the added installation (with pip) of pyinstaller in the used environment (when I installed pyinstaller in the original environment, I had modified other important package by mistake and had to reinstall anaconda from scratch to have it work again)
I have tried creating another identical environment without the pyinstaller module and I get the same result.
I have lost count of how many times I have uninstalled and reinstalled anaconda to fix problems. If possible, I would really like not to have to reinstall it all over again.
I have isolated the piece of the interface's code that makes the treeview object. After testing, the snip of code bellow gives me the same issue.
import tkinter as tk
from tkinter import ttk
import numpy as np
class Testy():
def __init__(self, root):
#Values set in other part of the interface
self.Classes = ['Molecule1','Molecule2','Molecule3','Molecule4',
'Molecule5','Molecule6']
self.Single_Kinetic_Menu_Var = [tk.StringVar(value = 'Molecule1'),
tk.StringVar(value = 'Molecule3'),
tk.StringVar(value = 'Molecule4'),
tk.StringVar(value = 'Molecule5')]
self.Experiment_Count = np.zeros([len(self.Classes),2])
#Treeview widget making
Tree = ttk.Treeview(root)
Tree.grid(column = 0, row = 0)
Headings = ('first count','second count')
Tree['column'] = Headings
Tree.column("#0", width=100, minwidth=100)
Tree.heading("#0",text="Class")
for i in range(len(Headings)) :
Tree.column(Headings[i])
Tree.heading(Headings[i], text = Headings[i])
#Insert all classes and their counts
Empty = []
Total = []
Total = list(Total)
for Idx, Class in enumerate(self.Classes) :
Values = []
if Idx == len(self.Classes)-1 :
for Number in self.Experiment_Count[Idx,:] :
Values.append(str(Number))
Empty.append('-')
Total.append(0)
else :
for Number in self.Experiment_Count[Idx,:] :
Values.append(str(Number))
Values = tuple(Values)
if Class == self.Single_Kinetic_Menu_Var[0].get() :
Tree.insert("", Idx, text = Class, values=Values, tags = ('BLUE'))
Tree.tag_configure('BLUE', foreground = 'blue')
elif Class == self.Single_Kinetic_Menu_Var[1].get() :
Tree.insert("", Idx, text = Class, values=Values, tags = ('RED'))
Tree.tag_configure('RED', foreground = 'red')
elif Class == self.Single_Kinetic_Menu_Var[2].get() :
Tree.insert("", Idx, text = Class, values=Values, tags = ('GREEN'))
Tree.tag_configure('GREEN', foreground = 'green')
elif Class == self.Single_Kinetic_Menu_Var[3].get() :
Tree.insert("", Idx, text = Class, values=Values, tags = ('CYAN'))
Tree.tag_configure('CYAN', foreground = 'cyan')
else :
Tree.insert("", Idx, text = Class, values=Values)
Tree.insert('', len(self.Classes), text = '-', values = tuple(Empty))
Total = np.sum(self.Experiment_Count[:,:], axis = 0)
Tree.insert('',len(self.Classes)+1, text = 'TOTAL', values = tuple(Total),
tags = ('BOLD'))
Tree.tag_configure('BOLD', font = ('Calibri', 12, 'bold'))
def main():
Master = tk.Tk()
Master.title("interface")
Testy(Master)
Master.mainloop()
if __name__ == '__main__' :
main()
As you might see by running the code, I expect the text of molecules 1, 3, 4 and 5 to be colored blue, red, green and cyan respectively. However, I can only see them in black.
As already mentioned this is a known issue with the tkinter library > 8.6.8. This version of tkinter is preinstalled with newer versions of Python (> 3.7).
A work around for this has been proposed here:
https://core.tcl-lang.org/tk/tktview?name=509cafafae
Define the function that filters out arguments
def fixed_map(option):
# Returns the style map for 'option' with any styles starting with
# ("!disabled", "!selected", ...) filtered out
# style.map() returns an empty list for missing options, so this should
# be future-safe
return [elm for elm in style.map("Treeview", query_opt=option)
if elm[:2] != ("!disabled", "!selected")]
Map the styling using the new function
style = ttk.Style()
style.map("Treeview",
foreground=fixed_map("foreground"),
background=fixed_map("background"))
With this the tag_configure() should work as intended.
-what version of python are you using (python -V) in cmd
-the last version(3.7) of python seems like it has bugs to color tags
-if you are using python (3.7) just install python 3.6 (it may work with newer version also)
Try this at start
style = ttk.Style()
aktualTheme = style.theme_use()
style.theme_create("dummy", parent=aktualTheme)
style.theme_use("dummy")
example, updating treeView using thread & Button... using spinbox to update nth row.............
from tkinter import *
from tkinter import ttk,messagebox
import time
import threading
def thd():
time.sleep(4)
pos = int(xs.get())
stg= "Row"
pf = "updated"
tv.item(pos, text='', values=(stg,pf), tags = ('fail',))
def helloCallBack():
thd()
ws = Tk()
ws.title('Vik')
ws.geometry('400x300')
ws['bg']='#fb0'
style = ttk.Style()
aktualTheme = style.theme_use()
style.theme_create("dummy", parent=aktualTheme)
style.theme_use("dummy")
tv = ttk.Treeview(ws)
tv['columns']=('Stage', 'Status', )
tv.column('#0', width=0, stretch=NO)
tv.column('Stage', anchor=CENTER, width=80)
tv.column('Status', anchor=CENTER, width=80)
# tv.column('Badge', anchor=CENTER, width=80)
tv.heading('#0', text='', anchor=CENTER)
tv.heading('Stage', text='Id', anchor=CENTER)
tv.heading('Status', text='rank', anchor=CENTER)
# tv.heading('Badge', text='Badge', anchor=CENTER)
tv.insert(parent='', index=0, iid=0, text='', values=('1','1'), tags = 'pass')
tv.insert(parent='', index=1, iid=1, text='', values=('2','2'), tags = 'pass')
tv.insert(parent='', index=2, iid=2, text='', values=('3','3'), tags = 'pass')
tv.insert(parent='', index=3, iid=3, text='', values=('4','4'), tags = 'pass')
tv.insert(parent='', index=4, iid=4, text='', values=('5','5'), tags = 'pass')
tv.tag_configure('fail', foreground='red', background='white', font=('Calibri', 11))
tv.tag_configure('pass', foreground='green', background='white',font=('Calibri', 9))
tv.pack()
xs = Spinbox(ws, from_=0, to=4)
xs.pack()
global posi
posi = int(xs.get())
ins_button = ttk.Button(
ws,
text='Insert',
command=helloCallBack
)
ins_button.pack(
ipadx=3,
ipady=3,
expand=True
)
exit_button = ttk.Button(
ws,
text='Exit',
command=lambda: ws.quit()
)
exit_button.pack(
ipadx=3,
ipady=3,
expand=True
)
th = threading.Thread(target=thd)
th.start()
ws.mainloop()

Bringing dialog window in from of Python window

My application has two separate dialog windows prior to opening the main application window. I am unable to figure out how to get the second dialog window (the calendar) to open in from of the black python screen (I apologize for my ignorance I don't know the name).
The messagebox contained in "rundate" opens first. If "no" is selected then the app_window opens. It is the app_window that gets hidden
conn = pyodbc.connect('Driver={Microsoft Access Driver (*.mdb, *.accdb)};Dbq='+db)
cur = conn.cursor()
app_window = tk.Tk()
app_window.geometry("1x1+0+0")
app_window.overrideredirect(True)
app_window.transient()
def rundate():
result = tkinter.messagebox.askyesno(title="Rundate", message="back 7 days?")
if result == True:
end = date.today()
start = date.today() - timedelta(7)
daterange = [pd.date_range(start, end)]
for single_date in daterange:
x = single_date.strftime("%m/%d/%Y")
rundate = x
print(rundate)
return rundate
else:
app_window.wm_title("Pick1")
app_window.geometry("250x150+100+100")
app_window.overrideredirect(False)
#app_window.mainloop()
cm = pick1.CalendarFrame(app_window)
cm.grid()
app_window.wait_variable(cm.wait_for_result)
return cm.rundate
rundate = rundate()
print(rundate)
Then a whole bunch of code for queries and whatnot then
After the messagebox is returned "yes" OR the dates are selected from the calendar then the interface gets initiated
# Initiate interface
root = Tk()
master = Frame(root, name='master')
master.pack(fill=BOTH)
root.geometry("800x800+300+100")
root.title('WeeklyReport')
menu_bar = Menu(root)
def exit():
root.destroy()
root.wait_window
I finally figured it out by adding "lift" Thank you!
app_window = tk.Tk()
app_window.geometry("1x1+0+0")
app_window.overrideredirect(True)
app_window.transient()
app_window.lift()

What is a way to convert text to a string in Python 3.3.0

Hi so i'm having a hard time getting Text from my program on Python to convert to a string so i can write it to a file without it just writing numbers in the file. i put this code :
from tkinter import *
a = Tk()
a.title("i need help")
a.geometry("600x600")
entryText = StringVar(None)
codeEdit = Text(a)
codeEdit.insert(END, "")
codeEdit.pack(side='top')
text = str(codeEdit)
def setLoc():
saveFile = open("DATA\Test.txt", "w")
saveFile.write(text)
saveFile.close()
return
writeButton = Button(text="Write",command=setLoc)
writeButton.pack(side='bottom')
so thats the code to write the obj locFile to the file Test.txt but when i type something in the Text box on the program and hit the writButton it will write to the file just not what i typed in it puts .50132192 so i wanted to know how i could convert it to a String?
You need to use the Text widget's get method to get all of the text from '1.0' (line 1, character 0) to END.
Here's a modified version of your code that does this in a write_text function. I also added scroll bars and switched to using grid instead of pack.
from tkinter import *
from tkinter import ttk
def write_text():
text = edit.get('1.0', END)
with open("DATA/Test.txt", "w") as f:
f.write(text)
root = Tk()
root.title("This May Help")
root.geometry("600x600")
edit = Text(root, width=80, height=25, wrap=NONE)
edit.insert('1.0', '[enter text]')
edit.grid(column=0, row=0, sticky=(N,W,E,S))
yscroll = ttk.Scrollbar(root, orient=VERTICAL, command=edit.yview)
yscroll.grid(column=1, row=0, sticky=(N,S))
edit['yscrollcommand'] = yscroll.set
xscroll = ttk.Scrollbar(root, orient=HORIZONTAL, command=edit.xview)
xscroll.grid(column=0, row=1, sticky=(W,E))
edit['xscrollcommand'] = xscroll.set
write_button = Button(text="Write", command=write_text)
write_button.grid(column=0, row=2)

Resources