How to mass produce entry box widgets in Tkinter? - python-2.7

I would like to turn the following 4 lines of code into 1 line by calling a function or class. This way, i can just call the function for each entry box widget i want to create:
self.systest = StringVar()
self.systest.set("N/A")
self.e = Entry(self.frame1, textvariable=self.systest)
self.e.grid(row=6, column=1)
here is the function i am trying to create (doesn't actually work):
def entry_boxes(self, row, col, default, var, frame):
setattr(self, var, StringVar)
setattr(self, var, default)
e = Entry(frame, textvariable=var)
e.grid(row=row, column=col)
calling it:
entry_boxes(self,6,1,'N/A','self.systest',self.frame1)
This will be part of a class, so i need the variables to be callable from anywhere in it.

Are you trying something like this?
from Tkinter import StringVar,Entry,Tk
class UIclass():
def __init__(self,root):
#define self.frame1
self.myfunc()
def myfunc(self):
self.entry_boxes(6,1,'N/A','self.systest',self.frame1)
self.entry_boxes(6,2,'N/A','self.systest',self.frame1)
...
...
...
def entry_boxes(self, row, col, default, var, frame):
setattr(self, var, StringVar)
setattr(self, var, default)
e = Entry(frame, textvariable=var)
e.grid(row=row, column=col)
if __name__ == '__main__':
root = Tk()
UIclass(root)
root.mainloop()
If not,kindly do tell me so that I can delete this answer

Related

Tkinter assign buttons to entries in dynamically created widgets

How can I access an Entry content with pressing the corresponding Button in dynamically created widgets?
Below is the best I come up with so far. Thank you for any help.
from Tkinter import *
class App(object):
def __init__(self, master):
self.master = master
self.mf = Frame(self.master)
self.l = ["white", "red", "blue", "brown"]
self.font = ("Arial", 30)
self.c, self.r = 1, 0
self.cc, self.rr = 0, 0
self.bel = []
for c in self.l:
action = self.print_entry
self.e = Entry(self.mf, bg=c, width=10, font=self.font)
self.e.grid(row=self.r, column=self.c)
self.b = Button(self.mf, bg=c, text=c, font=self.font)
self.b.grid(row=self.rr, column=self.cc)
self.b.config(command=action)
self.bel.append((self.b, self.e))
self.rr += 1
self.r += 1
self.mf.pack()
def print_entry(self): # this function prints the content of the entry
pass
def main():
root = Tk()
display = App(root)
root.mainloop()
if __name__=="__main__":
main()
You can pass a reference to the entry widget into the command, using lambda or functools.partial. For example:
self.b.config(command= lambda entry=self.e: action(entry))
...
def print_entry(self, entry):
print("the entry is '%s'" % entry.get())
By the way, using self.b and self.e is pointless, since those variables will only ever hold references to the last button and last entry. You should either use a local variable, and/or append the values to a list.

Update class instance StringVar() from abstract method

I am trying to update 4 StringVar() with values read only after a file is opened. I'm trying to use an abstract method set_values() on the class TestPage to update the 4 StringVar().
...
class TestPage(Tk.Frame):
def __init__(self, parent, *controller):
Tk.Frame.__init__(self, parent)
self.x = Tk.StringVar()
self.y = Tk.StringVar()
self.z = Tk.StringVar()
self.w = Tk.StringVar()
...
x_label = ttk.Label(self, textvariable=self.x)
y_label = ttk.Label(self, textvariable=self.x)
z_label = ttk.Label(self, textvariable=self.x)
w_label = ttk.Label(self, textvariable=self.x)
...
def set_values(self):
self.x.set(some.list[0])
self.y.set(some.other_list.last_index)
self.z.set(some.list_total_entries)
self.w.set('herro worr')
...
TestPage inherets from Tk.Frame. I believe I 'instantiate' the TestPage object when I call show_frame() in the main Application class, which inherets from Tk:
# ***** Tkinter Gui classes *****
# Main container, called by app.gui.Application() in main.py
class Application(Tk.Tk):
def __init__(self, *args, **kwargs):
Tk.Tk.__init__(self, *args, **kwargs)
container = Tk.Frame(self, name='container')
container.pack(side="top", fill="both", expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (EntryPage, TestPage):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(EntryPage)
# ***** Change view/frame *****
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
# ***** Open file *****
def open_file(self):
functions.load_file()
...
I would like to call set_values() from my existing load_file function which is in a seperate functions module. I call load_file() to do some populating of graphs, and to parse the file selected for openening.
...
def load_file():
...
if file_name:
gui.TestPage.set_values()
...
...
When I try I get the error:
TypeError: unbound method set_values() must be called with TestPage instance as first argument (got nothing instead)
I need to call the method on the instantiated instance of TestPage, but I do not understand what parameter to supply to set_values() to indicate self or the current instance of TestPage. In the Application class I thought I was instantiating TestPage as frame in the line frame = F(container, self). But I have not been able to reference set_values() using frame either.
I am not even sure this is the best way to do it. I tried to replace the method with binds, events, and also #classmethod and #staticmethod, but with no real succes. Should I be using an abstract method for this?
The values you are changing are attributes of an object, so you need to change them via the instance. In other words, don't pass something to the "self" parameter of a class or abstract function, simply call the function on the object itself.
For example:
...
testfile = TestPage(...)
...
load_file(testpage)
...
def load_file(page):
...
page.set_values()

How to correctly create a second window in pyqt4

I'm trying to open a second window beside my mainwindow on a button click and display a tablewidget on it with some data. When I open the window it raises
AttributeError: 'Ui_MainWindow' object has no attribute 'openTable'
The mainwindow was created with Qt Designer and converted the ui file with pyuic4. How do I do this correctly correct so that the error is not raised?
The button calls function:
def showCliplist(self):
data = self.metadata_list
luts = self.lutlist
selected_lut = self.LUTBox.currentIndex()
openTable = ClipListViewer(data,luts,selected_lut)
self.openTable.show()
New window class:
class ClipListViewer(QtGui.QWidget):
def __init__(self, data, luts, selected_lut, parent = None):
super(ClipListViewer,self).__init__()
self.setWindowTitle('Cliplist')
self.resize(900,600)
self.metadata = data
self.curentluts = luts
self.choosenlut = selected_lut
y_count = len(self.metadata)
self.table = QtGui.QTableWidget(y_count,6)
self.table.setHorizontalHeaderLabels(['Clip', 'Videocodec', 'FPS', 'Audiocodec', 'Start Timecode', 'LUT'])
x = y = 0
for items in self.metadata:
for entry in items:
#print entry
self.table.setItem(y, x, QtGui.QTableWidgetItem(entry))
self.table.resizeColumnToContents(x)
x += 1
self.comb = QtGui.QComboBox()
for lutname in self.curentluts:
self.comb.addItem(lutname)
self.comb.setCurrentIndex(self.choosenlut)
self.table.setCellWidget(y, 5, self.comb)
self.table.setColumnWidth(5, 230)
y += 1
x = 0
self.table.resizeRowsToContents()
layout = QtGui.QHBoxLayout()
layout.addWidget(self.table)
self.setLayout(layout)
self.show()
def closeEvent(self, event): #check if window was closed
print "Cliplist Window was closed! "
I reviews your code completed, OK, let's me explain.
AttributeError: 'Ui_MainWindow' object has no attribute 'openTable'
This error says, "I not have self.openTable in class Ui_MainWindow (That true because your have create own method)".
Why ? : Because a problem is in line this;
def showCliplist(self):
data = self.metadata_list
luts = self.lutlist
selected_lut = self.LUTBox.currentIndex()
openTable = ClipListViewer(data,luts,selected_lut) # <- (1) THIS LINE
self.openTable.show() # <- (2) THIS LINE
In (1), your create your second widget in to openTable (Not self.openTable).
This line we have this object in openTable (Not self.openTable).
Then (2), your call QtGui.QWidget.show(self) to show widget of self.openTable (Not openTable). It's should be error because we don't have variable self.openTable. To fix it your should use same name variable, Like this;
def showCliplist(self):
data = self.metadata_list
luts = self.lutlist
selected_lut = self.LUTBox.currentIndex()
self.openTable = ClipListViewer(data,luts,selected_lut) # <- FIX THIS LINE !
self.openTable.show() # <- (2) THIS LINE
Why second widget is show before I call self.openTable.show()?
Answer : Your can see in second widget initiate in last line of code your see QtGui.QWidget.show(self) has be call before end of initiate;
class ClipListViewer(QtGui.QWidget):
def __init__(self, data, luts, selected_lut, parent = None):
super(ClipListViewer,self).__init__()
.
.
.
self.show() # <- THIS LINE
Regards,

How to invoke a method from combo box event

I am trying to invoke a method from combo box selected change event
with lambda expression but I am stuck with following error
TypeError: () takes no arguments (1 given)
I think I have passed 1 argument as per the method definition, could somebody please help me where I am wrong
or any other combobox selected change event code will be great help!
please note my code
self.boxWidget[boxName].bind("<<ComboboxSelected>>", lambda:invoke_Setting_Group(self))
def invoke_My_method1(self):
print "expand another window"
I am trying to pass the first class object to the second python script file for variable value assigning easeness.I tried to use this combox event change code without lambda then I noticed that this method is getting called automatically so I used lambda to prevent this automatic method calling
Sorry I am not having the knowledge on lambda expression usage; here I used only to prevent the automatic method execution. Without lambda expression I noticed my combo box function starts automatically, I did not understand why it happens so?
I am using TKinter python 2.6
More Detailed Code of above:
#Main_GUI_Class.py
##----------------------
import sys
class App():
def __init__ (self,master,geometry=None,root=None):
try:
self.master=master
if not root:
self.root=Tkinter.Toplevel(master)
def initUI(self):
try:
self.master.title("GUI")
menubar = Menu(self.master)
self.root.config(menu=menubar)
fileMenu.add_command(label='Open')
submenu_ncss.add_command(label='Model Setting',command=lambda:Combo_Expand_Script.Call_Model_Setting(self))
##----------------------
def main():
r = Tkinter.Tk()
r.withdraw()
r.title("GUI Sample")
r.wm_iconbitmap(Pic1)
v = App(r)
r.mainloop()
if __name__ == "__main__":
main()
##Combo_Expand_Script.py
##-----------------------
import sys
import Tkinter
import Main_GUI_Class
def Call_Model_Setting(self):
try:
self.PopUpWin = Toplevel(bg='#54596d',height=500, width=365)
self.PopUpWin.title("POP UP SETTING")
#Combo Boxs in Pop Up
boxNameGroup="boxSetting"
boxPlaceY=0
for Y in range(4):
boxName=boxNameGroup+str(Y)
if Y == 0:
boxPlaceY=50
else:
boxPlaceY=boxPlaceY+40
self.box_value = StringVar()
self.boxWidget[boxName] = ttk.Combobox(self.PopUpWin, height=1, width=20)
if Y== 0:
self.boxWidget[boxName]['values'] = ('A', 'B')
self.boxWidget[boxName].current(1)
if Y== 1:
self.boxWidget[boxName]['values'] = ('X', 'Y')
self.boxWidget[boxName].bind("<<ComboboxSelected>>",lambda:invoke_Setting_Group(self))
self.boxWidget[boxName].place(x=180, y = boxPlaceY)
#Buttons in Pop Up
self.btnApply = tk.Button(self.PopUpWin,width=10, height=1,text="Apply",relief=FLAT,bg=btn_Bg_Color,command=lambda: treeDataTransfer(self,0))
self.btnApply.pack()
self.btnApply.place(x=75, y = 460)
self.btnCancel = tk.Button(self.PopUpWin,width=10, height=1,text="Cancel",relief=FLAT,command=lambda: deleteTreeNodes(self))
self.btnCancel.pack()
self.btnCancel.place(x=170, y = 460)
except IOError:
print "Error: data error"
def invoke_Setting_Group(self):#, event=None
try:
#self.boxName.current(0)
self.boxWidget["boxSetting3"].current(0)
self.PopUpWin['width']=1050
self.PopUpWin['height']=700
self.btnApply.place(x=500, y = 550)
self.btnCancel.place(x=600, y = 550)
self.txtWidget={}
lsttxtSetting = ['1', '2','3 ','4','5 ','6','7','8','9','10']
for t in range(10):
txtName=txtNameGroupTS+str(t)
if t == 0:
txtPlaceY=120
else:
txtPlaceY=txtPlaceY+30
self.txtWidget[txtName] = Text(self.groupSettingFrame,height=1, width=10,borderwidth = 2)
self.txtWidget[txtName].insert(INSERT, lsttxtSetting[t])
self.txtWidget[txtName].pack()
self.txtWidget[txtName].place(x=200, y = txtPlaceY)
except IOError:
print "Error: Group Settings Popup error"
def turbDataTransferBind(self):
for P in range(0,3):
boxName="boxSetting"+str(X)
dataSettingbox=self.lstTurb[X]+" "+self.boxWidget[boxName].get()
self.root_node_Setting = self.tree.insert( self.root_node_ChildSetting["ChildSettingNode"], 'end', text=dataSettingbox, open=True)
def treeDataTransfer(self,dlgTurbFlag):
self.treeDataTransferBind()
print "data tranfer sucess"
def deleteTreeNodes(self):
print "delete nodes"
command= and bind expect function name - without () and arguments - so in place of
If you use
.bind("<<ComboboxSelected>>", invoke_Setting_Group(self) )
then you use result from invoke_Setting_Group(self) as second argument in .bind(). This way you could dynamicly generate function used as argument in bind
TypeError: () takes no arguments (1 given)
This means you have function function() but python run it as function(arg1)
You run lambda:invoke_Setting_Group(self) but python expects lambda arg1:self.invoke_Setting_Group(self)
You could create function with extra argument
def invoke_My_method1(self, event):
print "expand another window"
print "event:", event, event.widget, event.x, event.y
And then you could use it
.bind("<<ComboboxSelected>>", lambda event:invoke_Setting_Group(self, event))
BTW: it looks strange - you have class App() but in second file you use only functions instead of some class too.

How to pass id of a Tkinter Scale through command

I am using Tkinter to create a GUI for a program I am writing that will adjust some Zigbee controlled LED lights that I have. I am using a loop to create multiple copies of a Scale that I'm going to use as a brightness slider. I manage to create the sliders properly, but I am having difficulties actually adjust the sliders correctly. Here's my code:
import simplejson as json
import requests # submits http requests
from Tkinter import *
from ttk import Frame, Button, Label, Style, Notebook
# MD5 hash from http://www.miraclesalad.com/webtools/md5.php
myhash = "d9ffaca46d5990ec39501bcdf22ee7a1"
appname = "dddd" # name content isnt relevant
num_lights = int(3)
class hueApp(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.parent = parent
self.initUI()
def initUI(self, *args, **kwds):
# title the app window
self.parent.title("Hue controller")
self.style = Style()
# create grid layout
self.columnconfigure(0, pad=3)
self.columnconfigure(1, pad=3)
self.columnconfigure(2, pad=3)
self.rowconfigure(0, pad=3)
self.scale=[]
self.val=[]
for i in range(num_lights):
print 'i=', i, type(i)
self.val.append(i+1)
print 'val=', self.val, type(self.val)
self.scale.append(Scale(self, from_=255, to_=0, command=lambda i=self.val: self.brightness_adj(i,light_id=i)))
print self.scale[i]
print 'i = ', i, type(i), '\n\n'
self.scale[i].set(150)
self.scale[i].grid(row=1, column=i)
if i == 2:
print '\n', self.scale, '\n'
print self.val, '\n'
self.scale[i].set(200)
self.centerWindow
self.pack()
def brightness_adj(self,light_val, light_id):
#global bri_val
print 'light_id:', light_id, type(light_id)
print 'light_val:', light_val, type(light_val)
print self.val[int(light_id)]
#print int(light_id)
bri_val = self.scale[light_id-1].get()
print bri_val
light = light_id
global huehub
huehub = "http://192.168.0.100/api/"+ myhash + "/lights/" + str(light)
#brightness_logic()
reply = requests.get(huehub)
a=json.loads(reply.text)
#print bri_val
payload = json.dumps({"bri":bri_val})
sethuehub = huehub + "/state"
reply = requests.put(sethuehub, data=payload)
def centerWindow(self):
w = 250
h = 150
sw = self.parent.winfo_screenwidth()
sh = self.parent.winfo_screenheight()
x = (sw-w)/2
y = (sh-h)/2
self.parent.geometry('%dx%d+%d+%d' % (w, h, x, y))
def main():
root=Tk() #the root window is created
app=hueApp(root) #create an instance of the application class
root.mainloop()
if __name__ == '__main__':
main()
I realize that this code probably gives an error when you try to run it. Basically my problem is that the command for each scale is only send brightness_adj the value of the scale, but I can't get it to pass through the id of the light. I was trying to do this by sending through the index of the self.scale list that it is appended into when it is created. I need to know which light is being adjusted so that I can send a new brightness to the corresponding light bulb. I hope I was clear enough. Thanks in advance!
I'm a little confused about what you're trying to do with the line that assigns callback functions to the scale widgets:
self.scale.append(Scale(self, from_=255, to_=0, command=lambda i=self.val: self.brightness_adj(i,light_id=i)))
since self.val is a list, and you're sending it as both the light_val and the light_id arguments, which I would think should be integers.
Possible fix:
I'm guessing that you want each callback to send a different ID to the brightness_adj function depending on which scale it's assigned to. Here's how I would fix this up:
Add this function to your hueApp class namespace:
def brightnessCallbackFactory(self, id):
return lambda light_val:self.brightness_adj(light_val, id)
Then change the callback assignment line from the above to this:
self.scale.append(Scale(self, from_=255, to_=0, command=self.brightnessCallbackFactory(i)))
That should create callback functions that retain the ID value in their internal namespace and assign them to the corresponding scale widget.