'Exception in tkinter callback' and '[Errno 24] Too many open files.' - python-3.x

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()

Related

PySimpleGUI - Updating a listbox on a button event

I'm trying to make a Python program with a UI that shows simple widget like a frame, a listbox and a table. I would like to populate the listbox with input from the user. So I create the listbox and "fill it" qith a blank list, then the user type in a name, click the button and the list will have that name in it and the name will be shown in the listbox. I quite manage to do this, but the name in the listbox are in vertical, and the element of the list are every single characters entered bu the user in the Input field. Furthermore, the elements will are overwritten when the user types another name in the inputbox.
This is the code
import PySimpleGUI as sg
from openpyxl import Workbook
from openpyxl import load_workbook
createColony_Layout=[]
firstWindow_Layout=[]
colonyList = []
# Software theme
# FIRST WINDOW
# Layouts
menuBar_Layout = [
['&File', ['&Inserisci file ICM Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['Undo']],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
['&Help', ['&About...']]
]
createColony_Layout = [
[sg.Text('Insert researcher name', size=20)],
[sg.Input(size=15, key='c')],
[sg.Button(button_text='Create', button_type=7)]
]
createColonyFrame = sg.Frame('Create new colony', createColony_Layout, size=(200, 100))
firstWindow_Layout = [
[sg.MenubarCustom(menuBar_Layout)],
[sg.Push(), sg.Text('Colony management',
justification=('Center'), font=('Helvetica', 30)), sg.Push()],
[createColonyFrame],
[sg.Listbox(colonyList, size =(50, 25), key='lista')]
]
# Create window
window = sg.Window('Colony management', firstWindow_Layout, size=(1300, 700),
auto_size_text= True, resizable=True, finalize=True)
window.TKroot.minsize(500,250)
#window.TKroot.maxsize(600, 700)
# Program loop
while True:
event,values = window.read()
if event == 'Create':
window['list'].update(values['c'])
if event == sg.WINDOW_CLOSED:
break
window.close()
And this is a screen of the window
I hope this is enough for you to help me, thank you.
The call to update for Listbox takes a list/tuple as the first argument. A string looks like a list of single characters in Python. To add a single value, make it a tuple instead of a string.
window['list'].update(values['c'])
becomes
window['lista'].update((values['c'],))
There is also a call to set the minimum size for a window that you can use instead of the TKroot access you've got in your code.
If you want a minimum size of (500, 250), then use this call:
window.set_min_size((500, 250))
import PySimpleGUI as sg
# from openpyxl import Workbook
# from openpyxl import load_workbook
createColony_Layout=[]
firstWindow_Layout=[]
colonyList = []
# Software theme
# FIRST WINDOW
# Layouts
menuBar_Layout = [
['&File', ['&Inserisci file ICM Ctrl-O', '&Save Ctrl-S', '&Properties', 'E&xit']],
['&Edit', ['Undo']],
['&Toolbar', ['---', 'Command &1::Command_Key', 'Command &2', '---', 'Command &3', 'Command &4']],
['&Help', ['&About...']]
]
createColony_Layout = [
[sg.Text('Insert researcher name', size=20)],
[sg.Input(size=15, key='c')],
[sg.Button(button_text='Create', button_type=7)]
]
createColonyFrame = sg.Frame('Create new colony', createColony_Layout, size=(200, 100))
firstWindow_Layout = [
[sg.MenubarCustom(menuBar_Layout)],
[sg.Push(), sg.Text('Colony management',
justification=('Center'), font=('Helvetica', 30)), sg.Push()],
[createColonyFrame],
[sg.Listbox(colonyList, size =(50, 25), key='lista')]
]
# Create window
window = sg.Window('Colony management', firstWindow_Layout, size=(1300, 700),
auto_size_text= True, resizable=True, finalize=True)
window.set_min_size((500, 250))
# window.TKroot.minsize(500,250)
#window.TKroot.maxsize(600, 700)
# Program loop
while True:
event,values = window.read()
if event == 'Create':
window['lista'].update((values['c'],))
if event == sg.WINDOW_CLOSED:
break
window.close()

Missing Argument / issues opening GUI program on macOS Big Sur

This is my first GUI program and I am having some major issues. I really need some help. First, I cannot get the program to open on my computer (mac). When running in Idle IDE I get this error message: import Tkinter
ModuleNotFoundError: No module named 'Tkinter'.
I have 3.9 installed which I thought had a GUI interface.
When debugging in VS Code i get this error message # line 44:
Exception has occurred: TypeError
init() takes at least 4 arguments (3 given)
I think I have 4
I'm not sure where to begin with these issues. From my research it appears that there is an issue running GUI programs on macs updated higher then 11.1.
Code is below
# Create a Tkinter GUI program that converts Celsius Temp to Fahrenheit
# F == Fahrenheit
# C == Celsius
# Tkinter imported
import Tkinter
# Global variable used
temp_val = 'Celsius'
#Set value for drop down menu
def store_temp (set_temp):
global temp_val
temp_Val = set_temp
class TemperatureConverter:
def __init__(self):
# create main window
self.main_window = Tkinter.Tk()
# create a title for window
self.main_window.title('Temperature Converter')
# create three frames
self.top_frame = Tkinter.Frame()
self.option_frame = Tkinter.Frame()
self.mid_frame = Tkinter.Frame()
self.bottom_frame = Tkinter.Frame()
#create widget for top frame
self.prompt_label = Tkinter.Label(self.top_frame, text= 'Enter a temperature in Celsius: ')
#pack top frame
self.prompt_label.pack(side='left')
# create str variable obj to hold empty string variable
self.inputNumber = Tkinter.StringVar()
self.var = Tkinter.StringVar()
# create widget for option drop down menu
self.entry = Tkinter.Entry(self.option_frame, textvariable=self.inputNumber )
self.dropDownList = ['Celsius','Fahrenheit']
self.drop_down = Tkinter.OptionMenu(self.option_frame, value=self.var , values=self.dropDownList, command=store_temp)
self.var.set(dropDownList[0])
# option widgets packed
self.entry.pack(side='right')
self.dropDownList.pack(side='left')
#create widget for middle frame
self.result_label = Tkinter.Label(self.mid_frame)
# create widgets for bottom frame
self.call_convert = (call_convert , result_label, inputNumber)
self.convert_button = Tkinter.Button(self.bottom_frame, text='Convert', command=self.call_convert)
self.quit_button= Tkinter.Button(self.bottom_frame, text= 'Quit', command= self.main_window.destroy)
#pack the buttons
self.convert_button.pack(side='left')
self.quit_button.pack(side='left')
#pack the frames
self.top_frame.pack()
self.option_frame.pack()
self.mid_frame.pack()
self.bottom_frame.pack()
#Enter the tkinter main loop
Tkinter.mainloop()
# convert method is callback fucntion for convert button
def call_convert(self):
if temp_Val == 'Celsius':
f = float((float(temp)* 9/5)+32)
self.result_label.config(text='The temperature in Fahrenhiet is:')
if temp_Val == 'Fahrenheit':
c = float((float(temp)-32) * 5 / 9)
self.result_label.config(text='The temperature in Celsius is:')
if __name__ == '__main__':
temp_converter = TemperatureConverter()
There were a lot of bugs in your code. I fixed all of them (I think). I had to guess where you wanted to put the label with the results. I also had to fix all of the indentations. This is the working code:
# Create a tkinter GUI program that converts Celsius Temp to Fahrenheit
# F == Fahrenheit
# C == Celsius
# tkinter imported
import tkinter
class TemperatureConverter:
def __init__(self):
# create main window
self.main_window = tkinter.Tk()
# create a title for window
self.main_window.title("Temperature Converter")
# create three frames
self.top_frame = tkinter.Frame(self.main_window)
self.option_frame = tkinter.Frame(self.main_window)
self.mid_frame = tkinter.Frame(self.main_window)
self.bottom_frame = tkinter.Frame(self.main_window)
# create widget for top frame
self.prompt_label = tkinter.Label(self.top_frame, text="Enter a temperature in Celsius:")
# pack top frame
self.prompt_label.pack(side="left")
# create str variable obj to hold empty string variable
self.inputNumber = tkinter.StringVar(self.main_window)
self.var = tkinter.StringVar()
# create widget for option drop down menu
self.entry = tkinter.Entry(self.option_frame, textvariable=self.inputNumber)
self.dropDownList = ["Celsius", "Fahrenheit"]
self.drop_down = tkinter.OptionMenu(self.option_frame, self.var, *self.dropDownList)
self.var.set(self.dropDownList[0])
# option widgets packed
self.entry.pack(side="right")
self.drop_down.pack(side="left")
# create widget for middle frame
self.result_label = tkinter.Label(self.mid_frame)
# create widgets for bottom frame
self.convert_button = tkinter.Button(self.bottom_frame, text="Convert", command=self.call_convert)
self.quit_button= tkinter.Button(self.bottom_frame, text= "Quit", command=self.main_window.destroy)
# pack the buttons
self.convert_button.pack(side="left")
self.quit_button.pack(side="left")
# pack the frames
self.top_frame.pack()
self.option_frame.pack()
self.mid_frame.pack()
self.bottom_frame.pack()
# It is better to call `<tkinter.Tk>.mainloop()`
self.main_window.mainloop()
# convert method is callback fucntion for convert button
def call_convert(self):
if self.var.get() == "Celsius":
f = float((float(self.entry.get())* 9/5)+32)
self.result_label.config(text="The temperature in Fahrenhiet is: "+str(f))
if self.var.get() == "Fahrenheit":
c = float((float(self.entry.get())-32) * 5 / 9)
self.result_label.config(text="The temperature in Celsius is: "+str(c))
self.result_label.pack(side="bottom")
if __name__ == "__main__":
temp_converter = TemperatureConverter()
Look at what I did for the OptionMenu and look at how I fixed you call_convert function. If you have any specific questions, tell me and I will try to answer them.
By the way I don't think any of the errors you were getting were caoused by your OS. Also I suggest that next time you use import tkinter as tk as it will make it way easier to write code.

Python3, difficulty with classes and tkinter

First of all to kick it off,
I'm not great at programming,
I have difficulty with understanding most basics,
I always try doing my uterly best to solve things like this myself.
I'm trying to create a simple gui that makes json files. Everything works fine. Fine in the sense that I'm able to create the files.
Now I wanted to get my code cleaned up and to the next level. I have added tabs to the tkinter screen and that is where the troubles starts. Because when I'm, on a differend tab, the function doesn't get the current selected items, so I added buttons to save that list and then move to different tab.
I have a function(Save_List_t), which looks at the selected items from the listbox(a_lsb1) and saves them to a list(choice_list_t). This function runs when I press button(a_button).
After doing that I got a problem, I don't want to use "global" but I need the list in a other function(Mitre_Gen_Techs) to generate the files. This function runs when I press a button on the third tab.(c.button1)
To tackel this problem, I saw a post where someone uses a class to fix it. However even after reading to the documentation about classes I still don't truely get it.
Now I'm stuck and get the error. Which I don't find that strange, it makes sense to me why it gives the error but what am I doing wrong or how do I solve this issue.
The error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\thans\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
TypeError: Save_List_t() missing 1 required positional argument: 'self'
The code I wrote:
from tkinter import *
from attackcti import attack_client
from mitretemplategen import *
from tkinter import ttk
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Mitre ATT&Ck
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
ac = attack_client()
groups = ac.get_groups()
groups = ac.remove_revoked(groups)
techs = ac.get_enterprise_techniques()
techs = ac.remove_revoked(techs)
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Tkinter screen setup
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
root = Tk()
root.title("Mitre Att&ck")
root.minsize(900, 800)
root.wm_iconbitmap('')
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# Functions / classes
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
class Screen(object):
def __init__(self):
self.choice_list_t = []
self.choice_list_g = []
def Save_List_t(self):
for item in a_lsb2.curselection():
self.choice_list_t.append(a_lsb2.get(item))
print(self.choice_list_t)
def Save_List_g(self):
choice_list_g = []
for item in b_lsb1.curselection():
self.choice_list_g.append(b_lsb1.get(item))
print(self.choice_list_g)
def Mitre_Gen_Techs(self):
# Gen the json file
# mitre_gen_techs(self.choice_list_t, techs)
#testing class
print(self.choice_list_t)
def Mitre_Gen_Groups(self):
# Gen the json file
# mitre_gen_groups(self.choice_list_g, groups)
#testing class
print(self.choice_list_g)
def main():
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
# First Tkinter tab
# =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
rows = 0
while rows < 50:
root.rowconfigure(rows, weight=1)
root.columnconfigure(rows, weight=1)
rows += 1
# Notebook creating tabs
nb = ttk.Notebook(root)
nb.grid(row=1, column=0, columnspan=50, rowspan=50, sticky='NESW')
# Create the differend tabs on the notebook
tab_one = Frame(nb)
nb.add(tab_one, text='APG')
tab_two = Frame(nb)
nb.add(tab_two, text='Actors')
tab_gen = Frame(nb)
nb.add(tab_gen, text='test')
# =-=- First Tab -=-=
# List box 1
a_lsb1 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
# List with techs
a_lsb2 = Listbox(tab_one, height=30, width=30, selectmode=MULTIPLE)
for t in techs:
a_lsb2.insert(END, t['name'])
# Save list, to later use in Screen.Mitre_Gen_Techs
a_button = Button(tab_one, text="Save selected", command=Screen.Save_List_t)
# =-=- Second Tab -=-=
# List with TA's
b_lsb1 = Listbox(tab_two, height=30, width=30, selectmode=MULTIPLE)
for g in groups:
b_lsb1.insert(END, g['name'])
# Save list, to later use in Screen.Mitre_Gen_Groups
b_button = Button(tab_two, text="Save selected", command=Screen.Save_List_g)
# =-=- Third tab -=-=
c_button = Button(tab_gen, text="Print group json", command=Screen.Mitre_Gen_Groups)
c_button1 = Button(tab_gen, text="Print techs json", command=Screen.Mitre_Gen_Techs)
# Placing the items on the grid
a_lsb1.grid(row=1, column=1)
a_lsb2.grid(row=1, column=2)
b_lsb1.grid(row=1, column=1)
a_button.grid(row=2, column=1)
b_button.grid(row=2, column=1)
c_button.grid(row=2, column=1)
c_button1.grid(row=2, column=2)
root.mainloop()
# If main file then run: main()
if __name__ == "__main__":
main()
The application:
Image
I found someone who explained what was wrong.
Credits to Scriptman ( ^ , ^ ) /
simply adding:
sc = Screen()
And changing:
Button(tab_apg, text="Save selected", command=sc.Save_List_t)
Resolved the issue.

tkinter dialog window not working inside while loop?

Apparently, tkinter doesn't allow you to use a while loop as it already runs its own loop so I need help on making my code work with the while loop. I believe it has something to do with "mainloop()" but I'm not sure how to use it.
Code below (works without loop):
while (1):
choice = input("Choose 1 to open dialog, 2 to end the program.\n")
if choice == "1":
from tkinter import *
root = Tk()
root.withdraw()
fileName = filedialog.askopenfilename(filetypes = ([("Text file","*.txt")]),title='Please select a text file')
file = open(fileName)
sentence = file.read()
file.close()
elif choice == "2":
break
Once you've witdrawn the window with root.witdraw() all the code associated with the root will not run, so you need to keep the window open while the user is opening dialog
You could stick a label on the window saying "Choose some dialogue to open", or as Bryan Oakley said you could use either command line or graphical interface
choice = ""
while choice != "2": # no need for brackets here
choice = input("Choose 1 to open dialog, 2 to end the program.\n")
if choice == "1":
from tkinter import *
root = Tk()
root.title("Choose dialog")
#root.withdraw() this causes the problem
fileName = filedialog.askopenfilename(filetypes = ([("Text file","*.txt")]),title='Please select a text file')
if fileName != "": # if they choose not to open a file
file = open(fileName)
sentence = file.read()
print(sentence)
file.close()
root.destroy() # destroys the window
I've tested it and this does work, hope this helps you

tkinter need to click in shell to get gui fields to update

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.

Resources