how to get a button name as a value in python - python-3.x

using tkinter i created buttons from a list and what I want to have is when I click on the button to have a lable that say HDD (the button name ) is added
for examble if I clicked on the button /dev/sda
I should have HDD /dev/sda is added
but the problem is that I always get the last list value in my list
if I click on the button that have this name /dev/sda I get HDD /dev/sdb is
added
thanx in advanced
HDD=[/dev/sda,/dev/sdb,/dev/sdc]
top = tkinter.Tk()
top.geometry("500x500")
def hdd():
hdd = tkinter.Tk()
hdd.geometry("500x500")
len(HDD)
for i in range(0 , len(HDD)):
i = HDD[i]
def addtolist():
hlist =[]
hlist.append(i)
lable = Label(hdd, text="HDD {} is added to the
zpool".format(i))
lable.pack()
print(i)
bb = Button(hdd, text=str(i), command=addtolist)
bb.grid(row=1, column=1)
bb.pack()
e = Button(top, text = "HDD", command = hdd)
e.grid(row=0, column=5)

I'm not sure what you mean with "i created buttons from a list"
from tkinter import *
top = Tk()
top.geometry("500x500")
button_names = ["dev/sda", "dev/sdb"]
button_list = [] # for later needs
#my understanding of creating buttons from a list!?
for i in button_names:
button = Button(top, text=i, command=lambda x=i:lable_name(x))
button.pack()
button_list.append(button)
#Labels are packed bellow because I don't know where you want to pack it
def lable_name(name):
label = Label(top, text="HDD {} is added to the zpool".format(name))
label.pack()
top.mainloop()
Also weird is that line *hdd = tkinter.Tk()" and then you're trying to use len() on it.

Related

Tkinter dialog's elements position

I am building custom Tkinter dialog window with Entry and Combobox. I am stuck with placing text and enter frames. Currently I am placing them manually. I am looking for the way to let tkinter do it automatically (maybe with pack() method). And also configure TopLevel size automatically.
My code:
def ask_unit_len():
values = ['millimeters', 'micrometers', 'nanometers']
top = Toplevel()
top.geometry('170x100')
top.resizable(False, False)
top.focus_set()
top.grab_set()
top.title('Enter length and units')
label_length = Label(top, text='Length:')
label_length.place(x=0, y=0)
units_type = StringVar()
length = StringVar()
answer_entry = Entry(top, textvariable=length, width=10)
answer_entry.place(x=55, y=0)
label_units = Label(top, text='Units:')
label_units.place(x=0, y=30)
combo = Combobox(top, width=10, textvariable=units_type,
values=values)
combo.place(x=50, y=30)
button = Button(top, text='Enter',
command=lambda:
mb.showwarning("Warning",
"Enter all parameters correctly")
if (units_type.get() == "" or not length.get().isdigit()
or int(length.get()) <= 0)
else top.destroy())
button.place(x=65, y=70)
top.wait_window(top)
return int(length.get()), units_type.get()
So, is there any way to perform this?

How to reproduce class within tkinter

I built a little Synchronizer GUI program, using tkinter. I recently tried adding a +-Button, which reproduces the filebrowsing buttons and entry fields, so I can sync more than 2 directories. (I.e. personally, I have my Documents as well as Pictures backed up on a USB drive that I want to keep updated, but I dont want to copy my whole /home directory.)
I have run into two issues. The first issue is with the positioning of the plus Button: I have initialized the rowcount to zero, so everytime I click the +-Button, the new line of Buttons/fields is actually on a new line. sadly, this does not work for the plus button, that is defined outside the fuction, but shouldn't self.rowcount += 1 adjust rowcount for the whole class?
Secondly, I am not sure how to handle self.sourcefile and self.targetfile: When I select a new folder, it replaces the previous input, which is not the idea.
I would really appreciate any help!
from tkinter import *
from tkinter import filedialog
class Application():
def __init__(self):
self.root = Tk()
self.rowcount = 0
self.sourcefile = ""
self.targetfile = ""
self.sourceDirectory = Entry(self.root, width=10)
self.targetDirectory = Entry(self.root, width=10)
self.sourceDirectory.insert(0, "Source")
self.targetDirectory.insert(1, "Target")
selectSource = Button(self.root, text = "browse source", command=self.select_source, height=15, width=15)
selectTarget = Button(self.root, text = "browse target", command=self.select_target, height=15, width=15)
plusButton = Button(self.root, text = "+", command=self.create_new)
self.sourceDirectory.grid(row=0, column=0)
self.targetDirectory.grid(row=0, column=5)
selectSource.grid(row=0, column=1)
selectTarget.grid(row=0, column=10)
plusButton.grid(row=self.rowcount + 1, column=10)
self.root.mainloop()
def create_new(self):
self.rowcount += 1
print(self.rowcount)
self.sourceDirectory = Entry(self.root, width=10)
self.targetDirectory = Entry(self.root, width=10)
self.sourceDirectory.insert(0, "Source")
self.targetDirectory.insert(1, "Target")
selectSource = Button(self.root, image=self.browsericon, command=self.select_source, height=15, width=15)
selectTarget = Button(self.root, image=self.browsericon, command=self.select_target, height=15, width=15)
self.sourceDirectory.grid(row=self.rowcount, column=0)
self.targetDirectory.grid(row=self.rowcount, column=5)
selectSource.grid(row=self.rowcount, column=1)
selectTarget.grid(row=self.rowcount, column=10)
def select_source(self):
source = filedialog.askdirectory(title="Select Source")
self.sourceDirectory.delete(0, END)
self.sourceDirectory.insert(0, source)
self.sourcefile = source
def select_target(self):
target = filedialog.askdirectory(title="Select Target")
self.targetDirectory.delete(0, END)
self.targetDirectory.insert(1, target)
self.targetfile = target
Application()
shouldn't self.rowcount += 1 adjust rowcount for the whole class?
Yes, and it does in your code. However, changing the variable won't change the location of a widget that used that variable in a grid command.
My advice is to put the rows in one frame and the buttons in another. That way you don't have to keep adjusting the location of the buttons. For example:
self.row_frame = Frame(self.root)
self.button_frame = Frame(self.root)
self.button_frame.pack(side="bottom", fill="x")
self.row_frame.pack(side="top", fill="both", expand=True
Also, if the "+" button creates a new row, it shouldn't be duplicating code. You need to have a single function for adding a row. Since you already have a function to do that, you can call that function in __init__.
Putting it all together it looks something like this:
class Application():
def __init__(self):
self.root = Tk()
self.root.title("File Synchronizer")
self.rowcount = 0
self.sourcefile = ""
self.targetfile = ""
self.row_frame = Frame(self.root)
self.button_frame = Frame(self.root)
self.button_frame.pack(side="bottom", fill="x")
self.row_frame.pack(side="top", fill="both", expand=True)
startSync = Button(self.button_frame, text="Start", command=self.synchronize)
plusButton = Button(self.button_frame, text = "+", command=self.create_new)
startSync.grid(row=1, column=2)
plusButton.grid(row=0, column=10)
self.create_new()
self.root.mainloop()
def create_new(self):
self.rowcount += 1
self.sourceDirectory = Entry(self.row_frame, width=10)
self.targetDirectory = Entry(self.row_frame, width=10)
self.sourceDirectory.insert(0, "Source")
self.targetDirectory.insert(1, "Target")
selectSource = Button(self.row_frame, text = "browse source", command=self.select_source)
selectTarget = Button(self.row_frame, text = "browse source", command=self.select_target)
self.sourceDirectory.grid(row=self.rowcount, column=0)
self.targetDirectory.grid(row=self.rowcount, column=5)
selectSource.grid(row=self.rowcount, column=1)
selectTarget.grid(row=self.rowcount, column=10)
This doesn't put the "plus" and "Start" button in exactly the same place, but that's just because it's somewhat irrelevant to the answer. You can use whatever options you want to place it in the button frame. Since the two frames are independent, you can adjust rows, columns, and weights in one without affecting the other. Or, you can use pack in one frame and grid in another.
The other problem with your code is that self.sourceDirectory and self.targetDirectory can only hold one value so it will always refer to the last widgets that were created.
Since you are creating multiple source and target widgets, you need to save them in a list.
For example, start by adding an empty list to your application in the __init__ method:
self.sources = []
self.targets = []
Then, when you add a new row, append it to the list:
source_entry = Entry(self.row_frame, width=10)
target_entry = Entry(self.row_frame, width=10)
self.sources.append(source_entry)
self.targets.append(target_entry)
You can then iterate over these two lists to process all source and target values.
You will also have to modify the callback for the browse functions to accept an index so that the button knows which entry to update.

How to use a single button to take input from multiple Tkinter entries?

This program is being written in Tkinter. I am writing a program that will have multiple entry boxes where the user will input certain parameters. I want there to be a single button that saves all the entries from all the entry boxes to be used later by another part of my program. At this moment, the entry boxes and the button are done but the button does not do anything. How could I go about making the button read and save all the entries? Thanks!
You just need to get the data in the Entries and store them as variables, inside functions and globalize those variables. After that just call all the functions in a separate function. And then give this function as a command to the button.
import tkinter as tk
root = tk.Tk()
e_1 = tk.Entry(root)
e_1.pack()
e_2 = tk.Entry(root)
e_2.pack()
e_3 = tk.Entry(root)
e_3.pack()
var_1 = 0
var_2 = 0
var_3 = 0
def func_1():
global var_1
var_1 = e_1.get()
def func_2():
global var_2
var_2 = e_2.get()
def func_3():
global var_3
var_3 = e_3.get()
def store_all():
func_1()
func_2()
func_3()
print(var_1)
print(var_2)
print(var_3)
b = tk.Button(root, text="get", width=10, command=store_all)
b.pack()
root.mainloop()
I have used print() inside the function to confirm to you that the values are stored successfully. You can just remove those.
Here is an example of a program that reads contents of one Entry and prints it:
https://effbot.org/tkinterbook/entry.htm#patterns
Below you can find code in python 3:
from tkinter import *
master = Tk()
e = Entry(master)
e.pack()
e.focus_set()
def callback():
print(e.get())
b = Button(master, text="get", width=10, command=callback)
b.pack()
mainloop()
Just add more Entry widgets and read them all in the callback method.

A reset button for tkinter entries, looped inside a list

I've successfully looped the textvariable for all the entries created to point to DoubleVar(), and its working properly. The problem arose when i tried creating reset button for all the entries. from my code as shown, the program runs, doesn't raise any error, and the values in the entries are not cleared. thanks in advance :)
from tkinter import*
root = Tk()
img = PhotoImage(file = 'background.png')
cc = DoubleVar()
cc.set('##')
dr =Label(root, text='helo world')
sd = []
y = -1
dr.pack()
Entry(root, textvariable =cc).pack()
def clear():
cc.set('')
for i in sd:
i['textvariable'] = DoubleVar().set('')
def create():
global y
y +=1
sd.append(Entry(root, width =5))
for i in sd:
i["textvariable"] = DoubleVar()
sd[y].pack()
Button(root, text = 'push', command = clear).pack()
Button(root, text = 'create', command = create).pack()
root.mainloop()
`
Your reset code is creating new DoubleVars, and setting them to the empty string. You're doing nothing to the original variables.
You don't need to use the variables for this, you can simply call the delete method on each entry widget:
for entry in sd:
entry.delete(0, "end")

Python 3 Radio button controlling label text

I am in the process of learning Python3 and more of a necessity, the TkInter GUI side. I was working my way through a book by James Kelly, when I encountered this problem. All his examples made a new window with just label/canvas/check box etc which seemed to work OK.
But as I wanted to experiment in a more real world scenario I put most things on one window. This where I encountered my problem. I can not get the radio button in the frame to alter the wording of a label in the parent window.
Complete code is:-
#! /usr/bin/python3
from tkinter import *
def win_pos(WL,WH,xo=0,yo=0) :
# Screen size & position procedure
# Screen size
SW = home.winfo_screenwidth()
SH = home.winfo_screenheight()
# 1/2 screen size
sw=SW/2
sh=SH/2
# 1/2 window size
wl=WL/2
wh=WH/2
# Window position
WPx=sw-wl+xo
WPy=sh-wh+yo
# Resulting string
screen_geometry=str(WL) + "x" + str(WH) + "+" + str(int(WPx)) + "+" \ + str(int(WPy))
return screen_geometry
# Create a window
home=Tk()
home.title("Radio buttons test")
# Set the main window
home.geometry(win_pos(600,150))
lab1=Label(home)
lab1.grid(row=1,column=1)
fraym1=LabelFrame(home, bd=5, bg="red",relief=SUNKEN, text="Label frame text")
fraym1.grid(row=2,column=2)
laybl1=Label(fraym1, text="This is laybl1")
laybl1.grid(row=0, column=3)
var1=IntVar()
R1=Radiobutton(fraym1, text="Apple", variable=var1, value=1)
R1.grid(row=1, column=1)
R2=Radiobutton(fraym1, text="Asus", variable=var1, value=2)
R2.grid(row=1, column=2)
R3=Radiobutton(fraym1, text="HP", variable=var1, value=3)
R3.grid(row=1, column=3)
R4=Radiobutton(fraym1, text="Lenovo", variable=var1, value=4)
R4.grid(row=1, column=4)
R5=Radiobutton(fraym1, text="Toshiba", variable=var1, value=5)
R5.grid(row=1, column=5)
# Create function used later
def sel(var) :
selection="Manufacturer: "
if var.get() > 0 :
selection=selection + str(var.get())
lab1.config(text=selection)
R1.config(command=sel(var1))
R2.config(command=sel(var1))
R3.config(command=sel(var1))
R4.config(command=sel(var1))
R5.config(command=sel(var1))
R1.select()
mainloop()
I realise that there is room for improvement using classes/functions but I need to get this resolved in my head before I move on. As it can be hopefully seen, I'm not a complete novice to programming, but this is doing my head in.
Can a solution, and reasoning behind the solution, be given?
You can modify your label's text by assigning the same variable class object, var1 as its textvariable option as well but since lab1's text is slightly different, try removing:
R1.config(command=sel(var1))
R2.config(command=sel(var1))
R3.config(command=sel(var1))
R4.config(command=sel(var1))
R5.config(command=sel(var1))
R1.select()
and modify sel to:
def sel(*args) :
selection="Manufacturer: "
selection=selection + str(var1.get())
lab1.config(text=selection)
and then call var1.trace("w", sel) somewhere before mainloop as in:
...
var1.trace("w", sel)
mainloop()
Also for a simple example:
import tkinter as tk
root = tk.Tk()
manufacturers = ["man1", "man2", "man3", "man4", "man5"]
lbl = tk.Label(root, text="Please select a manufacturer.")
lbl.pack()
# create an empty dictionary to fill with Radiobutton widgets
man_select = dict()
# create a variable class to be manipulated by radiobuttons
man_var = tk.StringVar(value="type_default_value_here_if_wanted")
# fill radiobutton dictionary with keys from manufacturers list with Radiobutton
# values assigned to corresponding manufacturer name
for man in manufacturers:
man_select[man] = tk.Radiobutton(root, text=man, variable=man_var, value=man)
#display
man_select[man].pack()
def lbl_update(*args):
selection="Manufacturer: "
selection=selection + man_var.get()
lbl['text'] = selection
#run lbl_update function every time man_var's value changes
man_var.trace('w', lbl_update)
root.mainloop()
Example with label's identical to that of radiobutton's value:
import tkinter as tk
root = tk.Tk()
# radiobutton group will the button selected with the value=1
num = tk.IntVar(value=1)
lbl = tk.Label(root, textvariable=num)
zero = tk.Radiobutton(root, text="Zero", variable=num, value=0)
one = tk.Radiobutton(root, text="One", variable=num, value=1)
#display
lbl.pack()
zero.pack()
one.pack()
root.mainloop()

Resources