-3

I am trying to use a ttk.notebook in python3 on a Linux (Ubuntu 14.04LTS) system to read Blockquote`# -- coding: utf-8 --data from experiments and perform several curve fits on this data in order to calculate the coefficients needed for a Finite Element calculation. The actual calculation of these curves I have already performed without tkinter. I am now setting up the user interface. All works well, until I want to fill in the variable a as global variable, noting is exported to the Ipython shell (using spyder2). The variables: CreepData and path2 which are made global in the same way are visble in the Ipython shell. I am not sure if the way I am extracting values from the combo boxes or the Entry fields on the notebook page select units and run work in the intended way. See the code below:

""" Created on Sat Jan 16 18:56:16 2016

@author: peterk

Derived frpm a lot of posted examples """ import csv from copy import
deepcopy import numpy as np import matplotlib  import scipy import
matplotlib matplotlib.use("TkAgg") from
matplotlib.backends.backend_tkagg import
FigureCanvasTkAgg,NavigationToolbar2TkAgg from matplotlib.figure
import Figure from matplotlib import pyplot as plt from scipy import
stats from scipy.optimize import curve_fit from tkinter import *
import tkinter as tk import tkinter.font as tkFont import tkinter.ttk
as ttk from tkinter import filedialog path2="./creep.csv"

class CreepNotebook(ttk.Frame):

def __init__(self, isapp=True, name='notebookdemo'):
    ttk.Frame.__init__(self, name=name)
    self.pack(expand=True, fill="both")
    self.master.title('Creep fit')
    self.isapp = isapp
    self._create_widgets()
    self.master.minsize(1920,1000)
def _create_widgets(self):      
    self._create_main_panel()         
def _create_main_panel(self):
    mainPanel = ttk.Frame(self, name='demo')
    mainPanel.pack( expand=True, side="top",  fill="both")                 
    # create the notebook
    nb = ttk.Notebook(mainPanel, name='notebook')
    # extend bindings to top level window allowing
    #   CTRL+TAB - cycles thru tabs
    #   SHIFT+CTRL+TAB - previous tab
    #   ALT+K - select tab using mnemonic (K = underlined letter)
    nb.enable_traversal()
    nb.pack(fill="both", padx=2, pady=3,expand=True)
    self._create_readme_tab(nb)
    self._create_import_data_tab(nb)
    self._create_select_units_run_tab(nb)
    self._create_text_tab(nb)                      
def _create_readme_tab(self, nb):
    # frame explaining the app
    frame = ttk.Frame(nb, name='readMeFirst')

    # widgets to be displayed on 'Description' tab
    msg = ["Ttk is the new Tk themed widget set. One of the widgets ",
           "it includes is the notebook widget, which provides a set ",
           "of tabs that allow the selection of a group of panels, ",
           "each with distinct content. They are a feature of many ",
           "modern user interfaces. Not only can the tabs be selected ",
           "with the mouse, but they can also be switched between ",
           "using Ctrl+Tab when the notebook page heading itself is ",
           "selected. Note that the second tab is disabled, and cannot "
           "be selected."
           " aaaaaaaaaaaaaaa      aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
           "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
           "ccccccccccccccccccccccccccccccccccccccccccccccccccccccc",            

           "dddddd",               
            "eeeee",              
           "f",              
           "a",               
           "b",               
           "c",               
           "d",               
           "e",               
           "f",               
           "g",               
           "h",               
          " here is text too"]

    lbl = ttk.Label(frame, wraplength='4i', justify=tk.LEFT, anchor=tk.CENTER,
                    text=''.join(msg))
    neatVar = tk.StringVar()
    btn = ttk.Button(frame, text='Neat!', underline=0,
                     command=lambda v=neatVar: self._say_neat(v))
    neat = ttk.Label(frame, textvariable=neatVar, name='neat')

    # position and set resize behaviour
    lbl.grid(row=0, column=0, columnspan=2, sticky='new', pady=5)
    btn.grid(row=1, column=0, pady=(2,4))
    neat.grid(row=1, column=1,  pady=(2,4))
    frame.rowconfigure(1, weight=1)
    frame.columnconfigure((0,1), weight=1, uniform=1)

    # bind for button short-cut key
    # (must be bound to topplevel window)
    self.winfo_toplevel().bind('<Alt-n>', lambda e, v=neatVar: self._say_neat(v))

    # add to notebook (underline = index for short-cut character)
    nb.add(frame, text='ReadMeFirst', underline=0, padding=2)

def _say_neat(self, v):
    v.set('Yeah, I know...')
    self.update()
    self.after(500, v.set(''))

#        return path2
# =============================================================================
def _create_import_data_tab(self, nb):
    # Populate the second pane. 
    frame = ttk.Frame(nb, name="import data")
    global l
    global k
    global sigma
    global creepData
    global filen
    global path2
    butn=ttk.Button(frame, text='select csv file', command=self.askopenfilename2)
    butn.pack(side="top")
    self.file_opt = options = {}
    options['defaultextension'] = '.csv'
    options['filetypes'] =[('csv files', '.csv'),('all files', '.*')]
    options['initialdir'] = '.'
    options['initialfile'] = 'creep2.csv'
    options['parent'] = nb
    options['title'] = 'Select csv file'
    global creepData
    print("path2 in _create_import_data_tab")
    print (path2)
    nb.add(frame, text='Import data', underline=0)
def askopenfilename2(self):
    global path2
    global creepData
    path2 = filedialog.askopenfilename(**self.file_opt)
    print("path2 in askopenfilename2")
    print(path2)    
    creepReader=csv.reader(open(path2, newline=""), delimiter=',')
    creepData=list(creepReader)
#enter code here
========================================
def _create_text_tab(self, nb):
    # populate the third frame with a text widget
    frame = ttk.Frame(nb)

    txt = tk.Text(frame,  width=40, height=10)
    vscroll = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=txt.yview)
    txt['yscroll'] = vscroll.set
    vscroll.pack(side=tk.RIGHT)
#   txt.pack(tk.fill=BOTH, tk.expand=True)
    txt.pack() #        btn2l.pack(side="top", pady=5)
#   btn2.pack(side="top", pady=2)
#   w.pack(side="top", pady=2)
#   neatVar = tk.StringVar()
#        btn = ttk.Button(frame, text='Neat!', underline=0,
#                         command=lambda v=neatVar: self._say_neat(v))
#        neat = ttk.Label(frame, textvariable=neatVar, name='neat')
#    def _say_neat(self, v):
#        v.set('Yeah, I know...')
#        self.update()
#        self.after(500, v.set(''))
    # add to notebook (underline = index for short-cut character)
    nb.add(frame, text='Text Editor', underline=0)
#============================================================
def _create_select_units_run_tab(self, nb):
    # select units and perform the calculation
    frame = ttk.Frame(nb, name="select units and calculate")
    global l
    global k
    global sigma
    global creepData
    global a
    a=tk.StringVar()
    frame.grid(column=0, row=0, rowspan=12, columnspan=5,sticky=(N,S,E,W))

    units = ('m,kg,s', 'mm,Mg,s', 'mm,kg,ms')
    a=tk.StringVar()
    cbl0 = ttk.Label(frame, text='Select or fill in the required fields and push the run button')
    cbl1 = ttk.Label(frame, text='Select units used in your FE-prgram')
    cb1 = ttk.Combobox(frame, value=units, state='readonly')
#        cbl1.pack(side="top")
#        cb1.pack(side="top")
    time_units=('hrs', 's','ms')
    cbl2=ttk.Label(frame, text='Select time units used in the csv file')
    cb2 = ttk.Combobox(frame, value=time_units, state='readonly')
#        cbl2.pack(side="top")
#        cb2.pack(side="top") 
    strain_units=('strain [%]', 'strain [-]','CreepModulus [MPa]')
    cbl3=ttk.Label(frame, text='Select strain or modulus  units used in the csv file')
    cb3 = ttk.Combobox(frame, value=strain_units, state='readonly')
#        cbl3.pack(side="top")
#        cb3.pack(side="top")
    yml=ttk.Label(frame, text=' Input Anisotropic Youngs Modulus in MPa')
    ym=Entry(frame)
#        yml.pack(side="top")
#        ym.pack(side="top")
    isfl=ttk.Label(frame, text='Input Isotropic factor')
    isf=Entry(frame)
#        isfl.pack(side="top")
#        isf.pack(side="top")
    run1Var = tk.StringVar()
    btn2 = ttk.Button(frame, text='Run', underline=0,
                     command=lambda w=run1Var: self._run1(w))
    btn2l = ttk.Label(frame, textvariable=run1Var, name='run1')
    cbl0.grid(column=0, row=0, sticky=W, pady=100)
    cbl1.grid(column=6, row=1, sticky=W, pady=25)
    cb1.grid(column=6, row=2, sticky=W, pady=2)
    cbl2.grid(column=6, row=3, sticky=W, pady=25)
    cb2.grid(column=6, row=4, sticky=W, pady=2)
    cbl3.grid(column=6, row=5, sticky=W, pady=25)
    cb3.grid(column=6, row=6, sticky=W, pady=2)
    yml.grid(column=6, row=7, sticky=W, pady=25)
    ym.grid(column=6, row=8,  sticky=W ,pady=2)
    isfl.grid(column=6, row=9, sticky=W, pady=25)
    isf.grid(column=6, row=10, sticky=W, pady=2)        
    btn2l.grid(column=6, row=11, sticky=W, pady=25)
    btn2.grid(column=6, row=12, sticky=W, pady=2)        
    nb.add(frame, text='Select data and run', underline=0, padding=2)
    a=cb1.get()
    print(a)
    print(cb1.get())
    yms=ym.get()
    isfs=isf.get()                  

def _run1(self, w):
#        global CreepData
#        global creepDat
#        creepDat=deepcopy(creepData)
    w.set('CreepData is copied')
    self.update()
    self.after(500, w.set(''))

#===================================================================
if __name__ == '__main__':
    CreepNotebook().mainloop()`

If needed I can upload the csv.files on my repro, but I do not think it is needed for answering the question. The run1 function would be used to fit the data curves and return a message that the calculations were performed.

pk28831
  • 67
  • 5
  • 1
    Please see http://www.stackoverflow.com/help/mcve to make a minimal, complete, and verifiable example (no one wants to read through hundreds of lines of code). – AMACB Jan 24 '16 at 16:28
  • 1
    @AMACB correction; **very few people are willing** to take the time to read through hundreds of lines of **unorganized** code – Tadhg McDonald-Jensen Jan 24 '16 at 16:52
  • @pk28831, please keep in mind that the easier it is for others to read and understand your question the easier it is to answer and sooner you are likely to get one :) – Tadhg McDonald-Jensen Jan 24 '16 at 16:54

1 Answers1

0

CHANGED - sorry I did not initially understand your question, prehaps this is more helpful:

first I'd recommend taking a look at both of these:

when to use global statement

Share variables between methods

second, you are creating the input entries in _create_select_units_run_tab and then you do:

def _create_select_units_run_tab:
    ...
    a = cb1.get()
    ...

this will get the contents immediately after being created and even before .mainloop() is called so it will absolutely always be an empty string, in order to get the content later in _run1 you need to keep track of the entries instead:

def _create_select_units_run_tab:
    ...
    self.input_fields = [cb1,cb2,cb3,ym,isf]
    #this will give all other methods access to the input fields

#then to get them back you can use this:
def get_inputs(self):
    return [entry.get() for entry in self.input_fields]

#then in run you can get the data in the fields
def _run1(self, w):
    inp_data = self.get_inputs()
    print(inp_data)
    if "" in inp_data:
        w.set("you need to fill everthing in first!")
    else:
        w.set(str(inp_data))
    ...

While testing the code I cancelled the file dialog window which threw an error because path2 == "" so you may want a check:

def askopenfilename2(self):
    ...
    if path2 is not "":
        creepReader=csv.reader(open(path2, newline=""), delimiter=',')
        creepData = list(creepReader)
    #else:
    #    creepData = None # or just leave it as the last used value?
    ...

not to mention the open() is never closed (Input and Output Python documentation):

It is good practice to use the with keyword when dealing with file objects. This has the advantage that the file is properly closed after its suite finishes, even if an exception is raised on the way. It is also much shorter than writing equivalent `try-finally` blocks:
    with open('workfile', 'r') as f:
    ...     read_data = f.read()
    >>> f.closed
    True

So you may want to implement that too:

    with open(path2, newline="") as file_obj:
        creepReader=csv.reader(file_obj, delimiter=',')

Lastly I'd like to draw attention to:

self.after(500,w.set('')

w.set('') is being called immediately and using the return value None in self.after, to instead call w.set with the argument you need to do this:

self.after(500,w.set,'')

then tkinter will call it after 500ms forwarding any extra arguments it receives in after

There may be other issues with your code that I missed but I hope this helped.

Community
  • 1
  • 1
Tadhg McDonald-Jensen
  • 20,699
  • 5
  • 35
  • 59
  • 1
    Thanks for this answer. I used upto now Fortran95. I read the part on namespace of the python3 course, but if I want to use/overwrite creepData in one function (reading the file) and use it in another function for the calculation and fit of the parameters, than I have to make it global or not ? The same goes for a=cb1.get() in the def _create_select_units_run_tab(self, nb). No value is printed. – pk28831 Jan 24 '16 at 18:48
  • Sorry for the crude way, but the number of characters was limited – pk28831 Jan 24 '16 at 18:59
  • when `a = cb1.get()` it returns the current contents of cb1 which is a place for the user to enter information correct? but cb1 was just barely defined in the same function so the user wouldn't have any time to type anything in before it is checked and reported as an empty string, `print(a)` will display a blank line but `print(repr(a))` will display`''` (empty string quotes) – Tadhg McDonald-Jensen Jan 24 '16 at 19:00
  • I've started this chat if you would like to further discuss http://chat.stackoverflow.com/rooms/101530/chat-about-global-variables – Tadhg McDonald-Jensen Jan 24 '16 at 19:07
  • sorry I missed this invitation yesterday. Is it possible to discuss it today between 20:00 and 20:30 CET? – pk28831 Jan 25 '16 at 15:53
  • I have changed the answer to actually answer the question you asked, first time I read it I thought "...variable a as global..." was a typo of "...variable as a global..." but now I realize you were talking about the variable `a`, next time try adding a code block of the relevant lines as well as the runnable block. :) – Tadhg McDonald-Jensen Jan 26 '16 at 01:16
  • @Tadhing McDonad-Jensen. I have implemented your changes and it does the job. However if I try to do the same for another button, to read and check if the data is read, I get a traceback error. in the import data tab. If I click a second time on the select csv button, the csv file is read, but the second button still gives a traceback error. see for the code below – pk28831 Feb 01 '16 at 07:13