Jython classes and variable scope - swing

What I want to know is, how can I create GUI elements using swing inside a Jython class so that they can be referenced from outside the class, and I can use statements like button.setText("Hello") on an object that was created inside another class. For example:
foo.py:
from javax.swing import *
class Test():
def __init__(self):
frame = JFrame("TEST")
button = JButton("Hey")
frame.add(button)
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
frame.setSize(300,200)
frame.show()
and then I have another file called somethingelse.py:
from foo import *
run = Test()
If I were to want to change the button text by using run.button.setText("Message"), how could I organise the Test() class such that I could change the text from the second file, somethingelse.py.

Your code is throwing away the references it has to the controls, so you can't access them from anywhere - frame and button are local variables, and disappear once __init__ returns.
You should (minimally) make them object members:
class Test():
def __init__(self):
self.frame = JFrame("TEST")
self.button = JButton("Hey")
self.frame.add(button)
# ...
You can then say:
from foo import *
run = Test()
run.button.setText("Message")

Related

Variable not recognized in the listener - Jython Swing

I'm developing a simple window that performs some operations at closure. This is my code extract:
from javax.swing import *
from java.awt import *
from java.awt.event import *
from java.io import *
import javax.swing.table.DefaultTableModel as DefaultTableModel
class registro(JFrame):
def __init__(self):
super(registro, self).__init__()
self.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
self.setExtendedState(JFrame.MAXIMIZED_BOTH)
#[...]
headers = ('Data e orario',
'Personale UO Q&A',
'Tipologia di attività'.decode('utf-8'),
'Personale incontrato con strutture di appartenenza',
'Note')
self.model = DefaultTableModel([["","","","",""]], headers)
self.table = JTable(self.model)
#[...]
self.addWindowListener(self.onClose())
#[...]
def onClose(self):
class saver(WindowAdapter):
tableModel = self.model
def windowClosing(self, event):
print tableModel #HERE IS THE ERROR!!!!!!!!!
return saver()
The error reported on the highlighted line is the following:
NameError: global name 'tableModel' is not defined
Although I have declared the variable inside the listener (to avoid misunderstanding between the two self), I don't understand why it has never been recognized. I'm almost a novice with object-oriented programming and Swing windows on Jython, and I hope this is not my (very) serious shortcoming!
Many thanks in advance.
There's a fairly subtle scope issue here, which is mostly about Python syntax, but also about what code you want to have access to the tableModel. The tableModel variable is not visible by default because you are inside the onClose() function. A defensive solution to this is to explicitly pass the needed variable into the new saver object. I personally prefer this as it more explicitly declares the inputs for saver objects.
class WindowAdapter:
None
class App:
def __init__(self):
self.model = 'DUMMYMODEL'
def onClose(self):
class Saver(WindowAdapter):
def __init__(self,tableModel):
WindowAdapter.__init__(self)
self.tableModel = tableModel
def windowClosing(self,event):
print (self.tableModel)
return Saver(self.model)
if __name__ == '__main__':
app = App()
sv = app.onClose()
sv.windowClosing(event=None)
(This code is cut down and in pure Python to show it is largely scoping related.)
An alternative would be using the Python global keyword to expose the tableModel variable to all lower scopes.
class WindowAdapter:
None
class App:
def __init__(self):
self.model = 'DUMMYMODEL'
def onClose(self):
global tableModel
tableModel = self.model
class Saver(WindowAdapter):
def windowClosing(self,event):
print (tableModel)
return Saver()
if __name__ == '__main__':
app = App()
sv = app.onClose()
sv.windowClosing(event=None)

NameError: global name not defined when calling method inside class

I'm trying to call a different function inside the same class from my main function and I can seem to figure where the error is.
I keep getting this error relating to functions not being defined and I'm not sure how to resolve it:
NameError: global name 'results' is not defined
class Darts:
def main() :
print results()
def results() :
round_result_totals = "Stuff"
return round_result_totals
#RUNNING CODE
main()
Make sure that you define properly self in your functions and initialize an object first before you do anything else. You can't just call a function from a class without creating an instance of that class and calling a function from that instance (NOT THE CLASS). Usually you want to have an __init__ in your python classes.
class Darts:
def __init__(self):
pass
def main(self):
print(self.results())
def results(self):
round_result_totals = "Stuff"
return round_result_totals
Dart1 = Darts()
Dart1.main()
If you want to use variables, self is critical too for encapsulation.
class Darts:
def __init__(self):
self.a = 500
def main(self):
self.a += 1
print(self.a)
Dart1 = Darts()
Dart1.main()
You need to pass self (the instance of your object) into your object's methods.
class Darts:
def main(self) :
print self.results()
def results(self) :
round_result_totals = "Stuff"
return round_result_totals
You're missing all of the required references to self inside your class. It should look like this:
class Darts:
def main(self) :
print self.results()
def results(self) :
round_result_totals = "Stuff"
return round_result_totals
Here is the Python documentation on classes. And the fifth paragraph of this section makes reference to the convention of self.
Briefly: the first argument to a method of a Python class is automatically passed in a reference to the instance of that class from which the method is being called (provided it is being called as an instance method). This is done automatically by Python's interpreter. This parameter still needs to be explicitly stated in the method definition, however, and the convention is to call it self.

Call up a function from another module

I am making a project where I need several modules which are imported into one main module. I have decided to move the interaction to a single Tkinter window. Instead of using input() I use tkinter.Entry(), for example. I have functions for each step of the interaction.
When I get past the last function of the first module, the configured button has a command to go to a function in the second module. I get an error saying that the command is not defined.
I seem unable to import the configured button variable into the next module, and anything else I tried gave no result. It simply doesn't go to the next module after the first module is done.
I have made the main Tkinter window in the main module and have it that it will mainloop after importing the other modules. Shouldn't the function I want to call upon be defined? How can I get from one function to the next if the latter is in a separate module?
Here is a minimal example:
main_script.py
import tkinter
mainwindow = tkinter.Tk()
# here i set the window to a certain size etc.
import mod1
import mod2
mainwindow.mainloop()
mod1.py
import tkinter
def button1():
label.destroy()
button1.destroy()
button2.config(text = "continue", command = func2)
def button2():
label.destroy()
button1.destroy()
button2.config(text = "continue", command = func2)
label = tkinter.Label(text = "example label")
button1 = tkinter.Button(text = "button1", command = button1)
button2 = tkinter.Button(text = "button2", command = button2)
label.pack()
button1.pack()
button2.pack()
mod2.py
def func2():
button2.destroy()
print ("haha it works...")
Importing a module has no effect on what the module you import can see. If you want to use mod1 contents in mod2 and mod2 contents in mod1, you need to have them import each other and refer to each other's contents with the appropriate module:
# mod1
import mod2
...
button2.config(text = "continue", command = mod2.func2)
# mod2
import mod1
def func2():
mod1.button2.destroy()
Circular imports cause nasty initialization order issues, though, so imports like this are a bad idea. When dividing your code into modules, try to do so in such a way that import loops like this aren't necessary.

Import and classes confusion

If I have a file called init.py:
class main:
import foo
import bar
and another file called foo.py, how can I import init's "main" class? Because I've seen this working instead of classes with functions, and it is a bit confusing, how classes and functions rank.
e.g.: if i import bar, what I am importing, the class or the file? if I want to import the class? and what about calling a function inside the class?
In the case:
# foo.py
import string
class Bar(object):
...
def baz(...):
...
You have two choices:
Using import foo would bring foo into your namespace, giving access to foo.Bar and foo.baz; or
You could e.g. from foo import baz to bring baz directly into the namespace, so you can access it without needing foo..
Note that you can have both classes and functions at the top level, which is also where imports should be done.
Suppose you have a file called Foo.py, and inside that file you defined a class called Foo, like this.
class Foo:
def __init__(self, args):
# perform initialization
Now you want to use this class in a different file called main.py, which we will assume for simplicity is in the same directory. You have two options.
The first option is to use import Foo, and then refer to the class by Foo.Foo.
import Foo
myFoo = Foo.Foo(args)
The second option is to write from Foo import Foo, and refer to the class by Foo.
from Foo import Foo
myFoo = Foo(args)

Jython swing supercall to class "extending" JTextField

I am trying to make a custom TextField similar to the panel here. However if I try calling super for certain methods it goes into infinite recursion leading to the recursion limit (never had a more suiting question for stackoverflow ;) ), the methods are for example paint and add (those two I tried, I guess it is everything inherited).
Here is the important code excerpt:
class inputWithButtons(JLayeredPane):
def __init__(self):
self.setLayout(_textFieldWithButtons())
self._fileField = JTextField()
self.add(self._fileField, Integer(1))
self.preferredSize = (0, 40) #TODO: why does minimumSize not work?
def add(self, component, layer): #recurses indefinitly
super(inputWithButtons, self).add(component, layer)
self.revalidate()
If the method is protected in their respective java class, you have to use the following syntax (Honestly hate this method)
self.super__
ex:
from javax.swing import JPanel
class panel(JPanel):
def paintComponent(self, graphic):
self.super__paintComponent(graphic)
# Do something
Source
To call any other super class methods, you use this syntax:
SuperClassName.method(self, *args)
With new-style classes:
super(panel, self).method(*args)