python : tkinter treeview colors are not updating - python-3.x

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

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)

How to handle variables of multiple check buttons inside a menu in Tkinter?

I wanted to make a multi-selection dropdown list in Tkinter so browsing online I came to the solution of using add_checkbuttons into a menu. The solution it's working, at least graphically, but now I want the GUI to actually do something when a check is marked. I tried with a simple function that print the value as a command for each check button but it's only being called once.
Here's my code so far:
root = tk.Tk()
groceries = ['Apple', 'Banana', 'Carrot']
def print_groceries(bucket,item):
print(bucket[item].get())
menubar = tk.Menu(root)
viewMenu = tk.Menu(menubar, tearoff = 0)
bucket={}
for item in groceries:
bucket[item] = tk.BooleanVar(False)
viewMenu.add_checkbutton(label = item, variable = bucket[item], command=print_groceries(bucket,item))
menubar.add_cascade(menu = viewMenu, label = "Buy")
root.config(menu = menubar)
root.mainloop()
You have assigned the return value of print_groceries to the command parameter. Therefore, when your code is executed, print_groceries is executed thrice at the time of defining the checkbuttons. As all the checkbuttons are unchecked initially, you see that False is printed thrice.
Solution:
The command parameter takes a function, not the value returned by a function (unless the return value is itself a function).
To create a simple function, you can use lambda as shown below:
lambda <parameter-1>,<parameter-2>,... : <task-to-perform>
Also, you must use lambda bucket=bucket, item=item: print_groceries(bucket,item) and not lambda : print_groceries(bucket,item). You can find the reason for the same in this answer.
Working Code:
import tkinter as tk
root = tk.Tk()
groceries = ['Apple', 'Banana', 'Carrot']
def print_groceries(bucket,item):
print(bucket[item].get())
menubar = tk.Menu(root)
viewMenu = tk.Menu(menubar, tearoff = 0)
bucket={}
for item in groceries:
bucket[item] = tk.BooleanVar(False)
func = lambda bucket=bucket, item=item: print_groceries(bucket,item)
viewMenu.add_checkbutton(label = item, variable = bucket[item], command = func)
menubar.add_cascade(menu = viewMenu, label = "Buy")
root.config(menu = menubar)
root.mainloop()

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.

How to append a list from QLineEdit with iterations (only last value is showing)

I think I am missing a basic idea and structure in this problem.
I used QTDesigner 4 to design a UI for pyqt5. In this UI the user will input a number into a QLineEdit widget named self.elaexpect and a second number into a second QLineEdit widget named self.elaact. The user will then click a pushbutton named addnew. The button then sends the information to a QTableWidget in the same Ui window (MainWindow). This is all working as intended. My trouble lies in the next desired outcome.
I would like to have the numbers then divide (expected/actual) to form a ratio, which is then stored in a list (not part of the Ui). After this step I want to have the program find the average in a percentage. So, in math terms, it will look something like {[(Expected/Actual)+(Expected2+Actual2)]/2}*100. This result will populate a QTextBrowser with a line stating what the percentage is.
My roadblock is attempting to have the ratios stored in a list. As you'll see in my code, I have tried to use list.append() to no avail, storing it in a for loop. I've also tried to use copy.deepcopy after reading that I needed to append a copy of the list. What happens when I build the code is that the Ui opens, I input my numbers, and the interpreter processes the ratio and prints the ratio. Then I enter two more numbers and press the button, the interpreter processes this ratio and prints, but instead of having two numbers, I get only the last one. I'm stuck here and have spent about 10 hours attempting different solutions, but can't shake the feeling that I am missing something basic.
Here is my code:
import sys
import copy
from PyQt5 import QtCore, QtGui, QtWidgets
from app3 import Ui_MainWindow
class Accapp(QtWidgets.QMainWindow, Ui_MainWindow):
def __init__(self):
super().__init__()
Ui_MainWindow.__init__(self)
Ui_MainWindow.__init__(self)
self.setupUi(self)
self.retranslateUi(self)
self.elaaddnew.clicked.connect(self.elaaddRow)
def elaaddRow(self):
# Retrieve text from QLineEdit
eladate = self.eladate.text()
elatname = self.elaname.text()
elaexpect = self.elaexp.text()
elaactual = self.elaact.text()
# Create a empty row at bottom of table
numRows = self.elatable.rowCount()
self.elatable.insertRow(numRows)
# Add text to the row
self.elatable.setItem(numRows, 0, QtWidgets.QTableWidgetItem(eladate))
self.elatable.setItem(numRows, 1, QtWidgets.QTableWidgetItem(elatname))
self.elatable.setItem(numRows, 2, QtWidgets.QTableWidgetItem(elaexpect))
self.elatable.setItem(numRows, 3, QtWidgets.QTableWidgetItem(elaactual))
# divide expected and actual times for ratio
elaratio= int(elaexpect)/int(elaactual)
# convert ratio to string
elaratiostr = str(elaratio)
#Split string to enter into list
elastrsp = elaratiostr.split()
# Create list
elaratiolst = []
#Create deepcopy of list
elaratiolstc = copy.deepcopy(elaratiolst)
#append values into list
for x in elastrsp:
elaratiolstc.append(x)
#Print list in python interpreter (not Ui)
print(elaratiolstc)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = Accapp()
window.show()
sys.exit(app.exec_())
And here is the relevant part from the Ui (in reality it is properly aligned):
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1044, 936)
self.elatab = QtWidgets.QWidget()
self.elatab.setObjectName("elatab")
self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.elatab)
self.verticalLayout_9.setObjectName("verticalLayout_9")
self.elagrpbx = QtWidgets.QGroupBox(self.elatab)
self.elagrpbx.setMinimumSize(QtCore.QSize(994, 812))
self.elagrpbx.setTitle("")
self.elagrpbx.setObjectName("elagrpbx")
self.formLayout_3 = QtWidgets.QFormLayout(self.elagrpbx)
self.formLayout_3.setObjectName("formLayout_3")
self.formLayout_2 = QtWidgets.QFormLayout()
self.formLayout_2.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
self.formLayout_2.setObjectName("formLayout_2")
self.elaname = QtWidgets.QLineEdit(self.elagrpbx)
self.elaname.setMaximumSize(QtCore.QSize(78, 20))
self.elaname.setObjectName("elaname")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.FieldRole, self.elaname)
self.label_35 = QtWidgets.QLabel(self.elagrpbx)
font = QtGui.QFont()
font.setPointSize(11)
self.label_35.setFont(font)
self.label_35.setObjectName("label_35")
self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.LabelRole, self.label_35)
self.elaexp = QtWidgets.QLineEdit(self.elagrpbx)
self.elaexp.setMaximumSize(QtCore.QSize(78, 20))
self.elaexp.setObjectName("elaexp")
self.formLayout_2.setWidget(5, QtWidgets.QFormLayout.FieldRole, self.elaexp)
self.elaaddnew = QtWidgets.QPushButton(self.elagrpbx)
self.elaaddnew.setMaximumSize(QtCore.QSize(75, 23))
self.elaaddnew.setObjectName("elaaddnew")
self.formLayout_2.setWidget(9, QtWidgets.QFormLayout.FieldRole, self.elaaddnew)
self.eladate = QtWidgets.QDateEdit(self.elagrpbx)
self.eladate.setMaximumSize(QtCore.QSize(79, 22))
self.eladate.setMinimumDate(QtCore.QDate(2018, 9, 14))
self.eladate.setObjectName("eladate")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.FieldRole, self.eladate)
self.label_33 = QtWidgets.QLabel(self.elagrpbx)
font = QtGui.QFont()
font.setPointSize(11)
self.label_33.setFont(font)
self.label_33.setObjectName("label_33")
self.formLayout_2.setWidget(1, QtWidgets.QFormLayout.LabelRole, self.label_33)
self.label_34 = QtWidgets.QLabel(self.elagrpbx)
font = QtGui.QFont()
font.setPointSize(11)
self.label_34.setFont(font)
self.label_34.setAlignment(QtCore.Qt.AlignCenter)
self.label_34.setWordWrap(True)
self.label_34.setObjectName("label_34")
self.formLayout_2.setWidget(2, QtWidgets.QFormLayout.LabelRole, self.label_34)
self.label_36 = QtWidgets.QLabel(self.elagrpbx)
font = QtGui.QFont()
font.setPointSize(11)
self.label_36.setFont(font)
self.label_36.setObjectName("label_36")
self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.LabelRole, self.label_36)
self.elaact = QtWidgets.QLineEdit(self.elagrpbx)
self.elaact.setMaximumSize(QtCore.QSize(78, 20))
self.elaact.setObjectName("elaact")
self.formLayout_2.setWidget(7, QtWidgets.QFormLayout.FieldRole, self.elaact)
self.formLayout_3.setLayout(0, QtWidgets.QFormLayout.LabelRole, self.formLayout_2)
self.elatable = QtWidgets.QTableWidget(self.elagrpbx)
self.elatable.setMinimumSize(QtCore.QSize(729, 600))
self.elatable.setMaximumSize(QtCore.QSize(729, 619))
self.elatable.setObjectName("elatable")
self.elatable.setColumnCount(4)
self.elatable.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.elatable.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.elatable.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.elatable.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
item.setTextAlignment(QtCore.Qt.AlignCenter)
self.elatable.setHorizontalHeaderItem(3, item)
self.elatable.horizontalHeader().setDefaultSectionSize(175)
self.elatable.verticalHeader().setCascadingSectionResizes(False)
self.elatable.verticalHeader().setDefaultSectionSize(46)
self.formLayout_3.setWidget(0, QtWidgets.QFormLayout.FieldRole, self.elatable)
Thanks
Answer was a simple fix as expected, thanks to u/Thomasedv on the r/learnpython subreddit. Solution was to include:
self.ratio_list=[]
in the __init__ class then add
self.ratio_list.append(elaratio)
in elaaddrow.
This solved the problem.

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