1
votes

I have the following Tkinter application which basically helps you to configure a new network just by inserting in the entry box a new value. This value entered by the user it is saved somewhere in a file using the template. This script runs well, but problem is that I am seeing the Tenant entry box upper than Network name entry box. The same is happening with their labels. Then, when we click on the Add network and getting another 2 entry box, are displayed very strange way.

How can I align the labels + entry boxes and how can I have them displayed each group of label+entry box one bellow the other?

Something like:

Tenant [entrybox] Network [entrybox]

Tenant [entrybox] Network [entrybox]

....................................

import Tkinter as tk

class SampleApp(tk.Tk):
    def __init__(self):
        tk.Tk.__init__(self)
        self._frame = None
        self.networks = []
        self.switch_frame(StartPage)
    def switch_frame(self, frame_class):
        """Destroys current frame and replaces it with a new one."""
        new_frame = frame_class(self)
        if self._frame is not None:
            self._frame.destroy()
        self._frame = new_frame
        self._frame.pack()

class StartPage(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        start_label = tk.Label(self, text="This is the start page")
        network_button = tk.Button(self, text="Create the networks", command=lambda: master.switch_frame(Networks))
        start_label.pack(side="top", fill="x", pady=10)
        deployment_button.pack()
        network_button.pack()
        subnet_button.pack()
        neutronports_button.pack()
        script_button.pack()

class Networks(tk.Frame):
    def __init__(self, master):
        tk.Frame.__init__(self, master)
        self.entries=[]
        self.create_widgets(master)
    def create_widgets(self, master):
        label = tk.Label(self, text="Insert the name of the networks")
        start_button = tk.Button(self, text="Return to start page", command=lambda: master.switch_frame(StartPage))
        new_network_button = tk.Button(self, text="Add network", command=self.add_network)
        new_network_button.bind("<Return>", self.add_network)
        new_network_button.grid(row=len(self.master.networks), column=3, padx=4, pady=6, sticky="W")
        next_button=tk.Button(self, text="Submit", command=self.networks)    
        next_button.grid(row=1500, column=5,padx=4, pady=6, sticky="W")
        label.pack(side="top", fill="x", pady=10)
        start_button.pack()
        new_network_button.pack()
        next_button.pack()
        for index, network in enumerate(self.master.networks):
            self.render_network_field(network, index)

    def add_network(self):
        requirements={'variable': tk.StringVar(self.master), 'cloudvariable': tk.StringVar(self.master)}
        if requirements: 
           self.master.networks.append(requirements)
           self.master.switch_frame(Networks)
        else: 
           tkMessageBox.showerror("tk", "No networks defined!")
           self.master.switch_frame(Networks)

    def render_network_field(self, network, index):
        labelText=tk.StringVar()
        labelText.set("Tenant name")
        labelDir=tk.Label(self,textvariable=labelText, height=4)
        labelDir.pack(side="top")
        nw_entry_field = tk.Entry(self, textvariable=network['variable'])
        nw_entry_field.grid(row=index, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
        nw_entry_field.pack(side="right")
        labelText=tk.StringVar()
        labelText.set("Network name")
        labelDir=tk.Label(self,textvariable=labelText, height=4)
        labelDir.pack(side="top")
        cloud_entry_field = tk.Entry(self, textvariable=network['cloudvariable'])
        cloud_entry_field.grid(row=index, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
        cloud_entry_field.pack(side="right")
        self.entries.append((network['cloudvariable'],network['variable']))

    def networks(self):
        with open("/home/dante/networks.yml", "w") as f:
             f.write("--- #" + "\n")
             for ent, cloudent in self.entries:
                    network_value=ent.get()
                    cloud_value=cloudent.get()
                    if network_value:
                      if cloud_value:
                        f.write("- { cloud: "+cloud_value+", network: "+network_value+ " }"+ "\n")

if __name__ == "__main__":
    app = SampleApp()
    app.mainloop()
1
The error is telling you that you are trying to set the controller option on a Button, but that widget does not have a controller option. What do you think Button(..., controller=self) is going to do? - Bryan Oakley
You use controller= in the creation of one of your buttons, I guess you meant to use command=: button1 = tk.Button(self, text="Next", controller=self.networks - fhdrsdg
@fhdrsdg: Yes, you're right. I have corrected that part, but I do not see the fields now. I have updated the question - Albert
s is a local variable inside render_network_field(). It ceases to exist the moment that function ends. - jasonharper
@jasonharper: how can I make it available for both functions? - Albert

1 Answers

0
votes

Following is a simple code that I just made to solve your problem. You just have to put the function register() in your class, that is executed when you press the button register (put it in the same class).

import tkinter as tk
from tkinter import *

def register():
    username = x1.get()
    password = y1.get()
    if username!="" and password=="":
    file = open("accountfile.txt","a")
    file.write(username)
    file.write(" ")
    file.write(password)
    file.write("\n")
    file.close()

root=Tk()  

# String variables
x1=StringVar()
y1=StringVar()
Us=Entry(root,textvariable=x1)
Us.grid()
Ps=Entry(root, textvariable=y1)
Ps.grid() 

Reg=Button(root,text="Register",command=lambda:register())
Reg.grid()

root.mainloop()

Edit:

To solve your error, make s a global variable. This will define s for all blocks of code in the file. Also, you can set a new value to it and then, use the new value, anywhere else

global s
s=""

def networks(self):
    with open("/home/dante/networks.yml", "w") as f:
         f.write("--- #" + "\n")
         f.write("networks:" + "\n")
         for ent in s:
             if ent:
                f.write("- { cloud: cloud1, network: "+str(ent)+ " }"+ "\n")

def render_network_field(self, network, index):
    entry_field = tk.Entry(self, textvariable=network['variable'])
    entry_field.grid(row=index, column=0, columnspan=2, padx=4, pady=6, sticky="NEWS")
    entry_field.pack()

    global s
    s=entry_field.get()

Hope this helps