How do I refer to the widget values in the following code.Here I have added widgets by calling methods in the app class for different frames.Next,I want to access the values in all the Widgets(which the user enters) of all the frames at the same time.But I am not able to figure out how should I refer to them and access their values!
class myapp():
def __init__(self,parent):
self.parent=parent
self.container=Frame(self.parent)
self.container.pack()
self.tab1=Button(self.container,text='tab1',command=self.tab1Click)
self.tab2=Button(self.container,text='tab*emphasized text*2',command=self.tab2Click)
self.tab1.pack()
self.tab2.pack()
def tab1Click(self):
top=Toplevel()
self.container1=Frame(top)
self.add_widget1(self.container1)#self.add_widgeti(parent) is a method in myapp() class to add a widget to a frame
self.add_widget2(self.container1)
self.add_widget3(self.container1)
self.container1.pack()
def tab2Click(self):
top=Toplevel()
self.container2=Frame(top)
self.add_widget2(self.container2)
self.add_widget4(self.container2)
self.add_widget5(self.container2)
self.container2.pack()
def write(self):
#here I want to write the values contained in the widgets in both frames in a file,but I am not able to figure out how do I refer to them and access their values.
Any help will be highly appreciated.Thanks in advance.
The widgets in which the user can write have a get method that returns their content. But in order to do this, you need to store your widget in a class variable for example.
Edit: I had misunderstood the problem and I hadn't realized that the add_widget function would be called for different containers for the same instance. One way to keep track of all created widgets is to create a widget list:
add self.widgets = [] in __init__
define theadd_widget method like that:
def add_widget(self, container):
self.widgets.append(Entry(container, text="enter text here"))
self.widgets[-1].pack()
Then to get the text entered by the user in all widgets (inside the write function):
texts = []
for widget in self.widgets:
texts.append(widget.get())
Related
I've written a program and I'm learning about classes and thus, rewriting the code to take advantage of classes and objects.
My problem is if I create a tkinter widget "dropdown menu" from a class, I can not retrieve the get.state variable.
class ...:
def make_drop_menu(self,parent,drop_opts,drop='empty',state=''):
self.parent = parent
self.drop = drop
self.drop_opts = drop_opts
self.state = tk.StringVar()
self.state.set(self.drop_opts[0]) # sets default value on drop (drop down menu)
self.drop = OptionMenu(self.parent, self.state, *self.drop_opts) # completed drop
return self.drop
----------------
class main:
self.widget = self.var.make_drop_menu(self.obj_mainwindow.btm_frame, self.col_opts)
Added for clearity:
window = windowclass() #windowclass is the style for tkinter. Makes a tkwindow.
self.widget = self.windowclass.var.make_drop_Menu() #
I've left out some code to simplify. But my main problem is that I create a widget called self.widget which builds my drop down menu. However, I have NO idea how to get the state of the drop down.
Hopefully the code makes sense.
If your class is named MyClass, then to access the state variable you would use the instance of the class. In your case it appears that self.var is the instance of your class, so it would look something like this:
self.var = MyClass()
self.var.make_drop_menu(...)
...
print(self.var.state.get())
Made the make_drop_menu class independent of any other class object. That way I could make a drop menu, assign the parent tk window, and create a method for getting the state variable when called.
Thanks to Bryan Oakley for the help!
I'm having a simple tkinter two frame application with a Label, Entry and Button widget and I want to access a StringVar() of FrameOne with a Entry and Button of FrameTwo.
If have seen a lots of examples of code, but do not get how this is been done in my example below. Many programmers are using a controller. If I would use a controller, I end up from an error to another.
For example:
FirstFrame = FrameOne(mainWindow)`
TypeError: __init__() missing 1 required positional argument: 'controller'
Which I completely understand, because I do not pass anything into the new 'controller' class argument when calling the Frame class. But I do not know what I should pass into this to solve it. Perhaps it is also caused by the lack of knowledge of using class variables (any literature tips are welcome).
The same counts for the solution to inherit FrameOne into FrameTwo. I bump into the same amount of errors applying to my code.
Another thing is that many programmers have examples of two frames that are not visible at the same time, while in my example I have two frames underneath each other at the same time.
An different related issue that I have is, what if the label widget of FrameOne was a Text widget? How do I access the widget from FrameTwo.
I could make it work with globals, but I do not want to use such writing and I will keep the access widget problem anyhow.
Please find my code below:
import tkinter as tk
class AppWindow():
def __init__(self, master):
self.master = master
master.title("Test Application")
master.geometry("1060x680")
master.grid_propagate(False)
class FrameOne(tk.Frame):
def __init__(self, parent):
super().__init__()
self["borderwidth"]=5
self["relief"]="ridge"
self.LabelText = tk.StringVar()
self.LabelText.set("It is not working yet")
self.testlabel = tk.Label(self, textvariable=self.LabelText)
self.testlabel.grid(row=1, column=1)
class FrameTwo(tk.Frame):
def __init__(self, parent):
super().__init__()
self["borderwidth"]=5
self["relief"]="ridge"
self.testentry = tk.Entry(self)
self.testentry.insert("end", "This should be working")
self.testentry.grid(row=1,column=1)
self.testbutton = tk.Button(self, text="Test the label", command=self.updatelabel)
self.testbutton.grid(row=1,column=2)
def updatelabel(self):
FrameOne.LabelText.set(self.testentry.get()) #HOW TO FIX THIS CODE THE RIGHT WAY?
#Create a window as defined in the AppWindow class
mainWindow = AppWindow(tk.Tk())
#Create a Frame as defined in class FrameOne
FirstFrame = FrameOne(mainWindow)
FirstFrame.grid(row=0, column=0) #Positioning Frame on Window
#Create a Frame as defined in class FrameOne
SecondFrame = FrameTwo(mainWindow)
SecondFrame.grid(row=1, column=0) #Positioning Frame on Window
Like with any python object, you access an attribute of an object using a reference to the object.
In your case, updatelabel should look like this:
def updatelabel(self):
FirstFrame.LabelText.set(self.testentry.get())
Note: your use of uppercase characters for instance variables makes your code much harder to comprehend. I recommend following the naming guidelines in PEP8.
How would i pass a varible from another class without instanting the class? the reason i do not want to instantiate the class is because i would have to pass self.master which would mess up the classes window i am passing the variable to.
class MainPageGUI:
def __init__(self, master):
self.master = master
self.master.title("Jans Corp")
self.master.configure(background='lightgrey')
self.master.geometry("1200x800")
listbox = tk.Listbox(self.master,width=150, height=35) # varibable i would like to use in the other class
listbox.place(x=150, y = 130)
Class i would like to pass the variable in:
class NewEmployee:
def __init__(self, master): #Creating basic GUI to add employees
self.master = master
self.master.title("Jans Corp")
self.master.configure(background="lightgrey")
self.master.geometry("300x500")
aa = MainPageGUI(self.master) ## my attempt at it, its wrong as the class get
self.listbox = self.aa.listbox
In general terms, the answer to "How to get variable from another class without instantiation?" is "you can't".
Your code example doesn't provide enough information to give a more concrete example. We don't know, for example, how, when, or where you create the instance of MainPageGUI, or how, when, and where you create an instance of NewEmployee.
I'm going to assume you've already created an instance of MainPageGUI before creating a NewEmployee.
In your case, you're trying to access something in MainPageGUI from another class. You don't want to create another MainPageGUI. Instead, what you need is a reference to the original MainPageGUI. Since that class must be instantiated somewhere, you simply need to pass that instance down when creating a new NewEmployee.
That means that you need to define NewEmployee something like this:
class NewEmployee:
def __init__(self, master, main_gui):
self.main_gui = main_gui
...
Then, anywhere in NewEmployee where you need to reference the listbox, you would use self.main_gui.listbox.
Of course, this also requires that MainGUI actually defines self.listbox. Right now your code does listbox = tk.Listbox(...) when it needs to be self.listbox = tk.Listbox(...).
Im making a QTableWidget in Pyqt and ran into a bit of an annoying hiccup.
I need to use widgets in my table for its functionality, so im using setCellWidget to add them to the table. However, widgets dont have the same methods available as QTableWidgetItem's do (especially regarding selection in the table).
Im wondering if its possible to do something subclassing both items, so i can have the methods of both, and how i woulda dd that to the table.
Something like:
class TableItem(QtGui.QTableWidgetItem, QtGui.QWidget):
def __init__(self, parent=None):
super(TableItem, self).__init__(parent)
self.check = QtGui.QCheckBox()
self.label = QtGui.QLabel('Some Text')
self.h_box = QtGui.QHBoxLayout()
self.h_box.addWidget(self.check)
self.h_box.addWidget(self.label)
and then somehow add that to my table as a TableWidgetItem so it displays widgets and also has selection methods available.
Any ideas here?
For reference:
setCellWidget: http://pyqt.sourceforge.net/Docs/PyQt4/qtablewidget.html#setCellWidget
QWidget: (easy to find, i cant post more than 2 links)
-Which doesnt have the nice methods for a table
QTableWidgetItem: http://pyqt.sourceforge.net/Docs/PyQt4/qtablewidgetitem.html#type
with isSelected and setSelected (Methods not avialble from a widget used in setCellWidget.
To return the widget in a cell you can use table.cellWidget(row, column) and then use your widgets methods on that. But beacuse setSelected and isSelected arent methods of a widget, you cant check for selection. I was hoping to subclass the two together to allow for both
--Basically I need to know how to get my class to 'return' the proper type when i call it to add to the table with setItem
I am not sure what you want to do but you could "inject" a method like:
class TableWidgetItem(QtGui.QTableWidgetItem):
def __init__(self, parent=None):
QtGui.QTableWidgetItem.__init__(self)
def doSomething(self):
print "doing something in TableWidgetItem"
class Widget(QtGui.QWidget):
def __init__(self, parent=None):
QtGui.QWidget.__init__(self)
tableWidgetItem = TableWidgetItem()
widget = Widget()
def widgetFunction(self):
tableWidgetItem.doSomething()
# as an instance method
settatr(widget, "widgetFunction", MethodType(widgetFunction, widget, type(widget)))
# or as a class method
settatr(widget, "widgetFunction", widgetFunction)
Then you can:
>>>widget.widgetFunction()
doing something in TableWidgetItem
(not tested)
I have a small program that batch handles files. These files use a map file to load certain settings. The map file has a line at the top that specifies for what directory it is for.
Currently I am able to read the line and assign it to the source path variable (sPath). I want to update the TextCtrl for the Source Directory, however it is in the MainFrame class and I load the map file in a different class.
class Process(wx.Panel):
def loadMap(self, event):
MainFrame.sPath = str(mapFile.readline()).strip("\n")
MainFrame.loadSource(MainFrame())
class MainFrame(wx.Frame):
def __init__(self):
wx.Frame.__init__(self, None, title="DICOM Toolkit", size=(800,705))
self.srcTc = wx.TextCtrl(self.panel, 131, '', size=(600,25), style=wx.TE_READONLY)
def loadSource(self):
self.srcTc.SetValue(MainFrame.sPath)
I eliminated most of the code and what's above is where it is giving me trouble. How do I change self.srcTc in the MainFrame class from either the Process class or a function in the MainFrame class? I am having trouble actually pointing to self.srcTc without a handler that stems from the MainFrame class.
There are several ways to accomplish this sort of thing. You can pass a handle to your panel class that can call whatever it needs in the parent to set the value (i.e. parent.myTxtCtrl.SetValue(val) ) or you can use pubsub. I personally recommend the latter as it's much more flexible and less prone to breakage as you change your program. I wrote the following tutorial that should get you up to speed: http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/
I think what you want has to look like something like that (without a working example):
class Process(wx.Panel):
def loadMap(self, event):
frame = MainFrame()
frame.sPath = str(mapFile.readline()).strip("\n")
frame.loadSource()
when using MainFrame.sPath = ... you're not actually changing sPath to a MainFrame you created, but to the class itself, then you create it, in MainFrame() without storing a reference to it (assign it to a variable for example). So, you can't access it from somewhere other than "inside" the class itself as self.
The solution is to create an instance of a MainFrame and operate on it. Once you create it and assign it to a variable, you can manipulate the .sPath attribute and call loadSource().
UPDATE: From you code snippet, it seems you create the MainFrame instance in the end of the file: MainFrame().Show(), and then in the loadMap method, you create a new one.
What you should do is this, in the end of your file:
app = wx.App(0)
#MainFrame().Show()
mainFrame = MainFrame() # or, insteadof making it a global variable, pass it as an argument to the objects you create, or store a reference to it anywhere else.
mainFrame.Show()
app.MainLoop()
and in the loadMap method:
def loadMap(self, event):
global mainFrame # or wherever you stored the reference to it
# ...
# remove this:
# mainFrame = MainFrame()
# set the sPath to the OBJECT mainFrame not the CLASS MainFrame
mainFrame.sPath = str(mapFile.readline()).strip("\n")
mainFrame.srcTc.SetValue(MainFrame.sPath)
Now this way, it should work.
The problem was that you are creating another frame, changing its path and updating its text, but you are not showing it. The correction is to store the actual window that is being shown, and update this one.