I have a code (swing):
javax.swing.JButton loginbutton = new javax.swing.JButton("Login");
loginbutton.setName("LoginButton126");
and test for it:
ComponentFinder finder = BasicComponentFinder.finderWithCurrentAwtHierarchy();
javax.swing.JButton loginbutton = (javax.swing.JButton) finder.findByName("LoginButton126");
but unfortunatelly I have:
Exception in thread "main" java.lang.NoClassDefFoundError: org/fest/util/Strings
What should I change ?
Best regards
I think this should work fine
By creating a new ComponentFinder that only has access to the GUI components created after it. In the following example, finder has access to MainFrame but not to LoginFrame.
// new LoginFrame();
ComponentFinder finder = BasicComponentFinder.finderWithNewAwtHierarchy();
finder.findByName("login", true); // will fail finding component of login frame
// new MainFrame();
finder.findByName("pw", true); // will work finding label of main frame
The easiest solution is to make all of the component variables be class variables so that you can access them anywhere. However, not everyone wants to do that, and some (like myself) are using GUI Editors that don't generate the components as class variables.
My solution is simple, I'd like to think, and doesn't really violate any programming standards, as far as I know (referencing what fortran was getting at). It allows for an easy and straightforward way to access components by name.
Create a Map class variable. You'll need to import HashMap at the very least. I named mine componentMap for simplicity.
private HashMap componentMap;
Add all of your components to the frame as normal.
initialize() {
//add your components and be sure
//to name them.
...
//after adding all the components,
//call this method we're about to create.
createComponentMap();
}
Define the following two methods in your class. You'll need to import
Component if you haven't already:
private void createComponentMap() {
componentMap = new HashMap<String,Component>();
Component[] components = yourForm.getContentPane().getComponents();
for (int i=0; i < components.length; i++) {
componentMap.put(components[i].getName(), components[i]);
}
}
public Component getComponentByName(String name) {
if (componentMap.containsKey(name)) {
return (Component) componentMap.get(name);
}
else return null;
}
Now you've got a HashMap that maps all the currently existing components in your frame/content pane/panel/etc to their respective names.
To now access these components, it is as simple as a call to getComponentByName(String name). If a component with that name exists, it will return that component. If not, it returns null. It is your responsibility to cast the component to the proper type. I suggest using instanceof to be sure.
If you plan on adding, removing, or renaming components at any point during runtime, I would consider adding methods that modify the HashMap according to your changes.
Related
I have in a JFrame some components that I want
to refer into another JFrame and I want
to get them by name and not
do public get/set methods for each.
Is there a way from Swing to get a component reference by its name like do
c#?
e.g. form.Controls["text"]
Thanks
I know this is an old question, but I found myself asking it just now. I wanted an easy way to get components by name so I didn't have to write some convoluted code each time to access different components. For example, having a JButton access the text in a text field or a selection in a List.
The easiest solution is to make all of the component variables be class variables so that you can access them anywhere. However, not everyone wants to do that, and some (like myself) are using GUI Editors that don't generate the components as class variables.
My solution is simple, I'd like to think, and doesn't really violate any programming standards, as far as I know (referencing what fortran was getting at). It allows for an easy and straightforward way to access components by name.
Create a Map class variable. You'll need to import HashMap at the
very least. I named mine componentMap for simplicity.
private HashMap componentMap;
Add all of your components to the frame as normal.
initialize() {
//add your components and be sure
//to name them.
...
//after adding all the components,
//call this method we're about to create.
createComponentMap();
}
Define the following two methods in your class. You'll need to import Component if you haven't already:
private void createComponentMap() {
componentMap = new HashMap<String,Component>();
Component[] components = yourForm.getContentPane().getComponents();
for (int i=0; i < components.length; i++) {
componentMap.put(components[i].getName(), components[i]);
}
}
public Component getComponentByName(String name) {
if (componentMap.containsKey(name)) {
return (Component) componentMap.get(name);
}
else return null;
}
Now you've got a HashMap that maps all the currently existing components in your frame/content pane/panel/etc to their respective names.
To now access these components, it is as simple as a call to getComponentByName(String name). If a component with that name exists, it will return that component. If not, it returns null. It is your responsibility to cast the component to the proper type. I suggest using instanceof to be sure.
If you plan on adding, removing, or renaming components at any point during runtime, I would consider adding methods that modify the HashMap according to your changes.
Each Component can have a name, accessed via getName() and setName(), but you'll have to write your own lookup function.
getComponentByName(frame, name)
IF you're using NetBeans or another IDE that by default creates private variables (fields) to hold all of your AWT/Swing components, then the following code may work for you. Use as follows:
// get a button (or other component) by name
JButton button = Awt1.getComponentByName(someOtherFrame, "jButton1");
// do something useful with it (like toggle it's enabled state)
button.setEnabled(!button.isEnabled());
Here's the code to make the above possible...
import java.awt.Component;
import java.awt.Window;
import java.lang.reflect.Field;
/**
* additional utilities for working with AWT/Swing.
* this is a single method for demo purposes.
* recommended to be combined into a single class
* module with other similar methods,
* e.g. MySwingUtilities
*
* #author http://javajon.blogspot.com/2013/07/java-awtswing-getcomponentbynamewindow.html
*/
public class Awt1 {
/**
* attempts to retrieve a component from a JFrame or JDialog using the name
* of the private variable that NetBeans (or other IDE) created to refer to
* it in code.
* #param <T> Generics allow easier casting from the calling side.
* #param window JFrame or JDialog containing component
* #param name name of the private field variable, case sensitive
* #return null if no match, otherwise a component.
*/
#SuppressWarnings("unchecked")
static public <T extends Component> T getComponentByName(Window window, String name) {
// loop through all of the class fields on that form
for (Field field : window.getClass().getDeclaredFields()) {
try {
// let us look at private fields, please
field.setAccessible(true);
// compare the variable name to the name passed in
if (name.equals(field.getName())) {
// get a potential match (assuming correct <T>ype)
final Object potentialMatch = field.get(window);
// cast and return the component
return (T) potentialMatch;
}
} catch (SecurityException | IllegalArgumentException
| IllegalAccessException ex) {
// ignore exceptions
}
}
// no match found
return null;
}
}
It uses reflection to look through the class fields to see if it can find a component that is referred to by a variable of the same name.
NOTE: The code above uses generics to cast the results to whatever type you are expecting, so in some cases you may have to be explicit about type casting. For example if myOverloadedMethod accepts both JButton and JTextField, you may need to explicitly define the overload you wish to call ...
myOverloadedMethod((JButton) Awt1.getComponentByName(someOtherFrame, "jButton1"));
And if you're not sure, you can get an Component and check it with instanceof...
// get a component and make sure it's a JButton before using it
Component component = Awt1.getComponentByName(someOtherFrame, "jButton1");
if (component instanceof JButton) {
JButton button = (JButton) component;
// do more stuff here with button
}
Hope this helps!
you could hold a reference to the first JFrame in the second JFrame and just loop through JFrame.getComponents(), checking the name of each element.
You can declare a variable as a public one then get the text or whatever operation you want and then you can access it in the other frame(if its in the same package) because it's public.
I needed to access elements inside several JPanels which were inside a single JFrame.
#Jesse Strickland posted a great answer, but the provided code is not able to access any nested elements (like in my case, inside JPanel).
After additional Googling I found this recursive method provided by #aioobe here.
By combining and slightly modifying the code of #Jesse Strickland and #aioobe I got a working code that can access all the nested elements, no matter how deep they are:
private void createComponentMap() {
componentMap = new HashMap<String,Component>();
List<Component> components = getAllComponents(this);
for (Component comp : components) {
componentMap.put(comp.getName(), comp);
}
}
private List<Component> getAllComponents(final Container c) {
Component[] comps = c.getComponents();
List<Component> compList = new ArrayList<Component>();
for (Component comp : comps) {
compList.add(comp);
if (comp instanceof Container)
compList.addAll(getAllComponents((Container) comp));
}
return compList;
}
public Component getComponentByName(String name) {
if (componentMap.containsKey(name)) {
return (Component) componentMap.get(name);
}
else return null;
}
Usage of the code is exactly the same as in #Jesse Strickland code.
If your components are declared inside the same class you're manipulating them from, you simply access these components as attributes of the class name.
public class TheDigitalClock {
private static ClockLabel timeLable = new ClockLabel("timeH");
private static ClockLabel timeLable2 = new ClockLabel("timeM");
private static ClockLabel timeLable3 = new ClockLabel("timeAP");
...
...
...
public void actionPerformed(ActionEvent e)
{
...
...
...
//set all components transparent
TheDigitalClock.timeLable.setBorder(null);
TheDigitalClock.timeLable.setOpaque(false);
TheDigitalClock.timeLable.repaint();
...
...
...
}
...
...
...
}
And, you may be able to access class components as attributes of the class name from other classes in the same namespace too. I can access protected attributes(class member variables), maybe you can access public components, too. Try it!
Swing does provide other ways to implement this, for the sake as exercising here is my version that implements a find in Component hierarchy context.
/**
* Description : Find a component having the given name in container desccendants hierarchy
* Assumptions : First component with the given name is returned
* #return java.awt.Component
* #param component java.awt.Component
* #param componentName java.lang.String
*/
public static Component findComponentByName(Component component, String componentName) {
if (component == null ) {
return null;
}
if (component.getName() != null && component.getName().equalsIgnoreCase(componentName)) {
return component;
}
if ( (component instanceof Container ) ) {
Component[] children = ((Container) component).getComponents();
for ( int i=0; i<children.length; i++ ) {
Component child = children[i];
Component found = findComponentByName( child, componentName );
if (found != null ) {
return found;
}
}
}
return null;
}
I have a quick question. I don't get it...
I've got a JFrame where I add a JComboBox:
JComboBox<String> Team_ComboBox = new JComboBox<>();
Team_ComboBox_Handler ComboBox_Listener = new Team_ComboBox_Handler();
Team_ComboBox.addActionListener(ComboBox_Listener);
Team_ComboBox.addItem("Test 1");
Team_ComboBox.addItem("Test 2");
On this Frame I have a button which opens another JFrame.
Play = new JButton();
Play.setText("Play");
Play.setPreferredSize(dimension);
Play.addActionListener(menuhandler);
private class main_menuhandler implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource()==Play){
teams Team = new teams();
Team.teams();
disposeMainMenue();
}
if(e.getSource()==Close) {
System.exit(DO_NOTHING_ON_CLOSE);
}
}
}
Anyway, I would like to transfer the Selected value of the Combobox to a method of the other class. I know how I can get the itemvalue of the combobox in the method itself (with getselecteditem) But how can I do that in the ActionPerformed Method as I can't access the combobox in the ActionPerformed method.... I created another ActionListener (comboBox_Listener) but I haven't put any code into it...
Any idea? Thanks a lot in advance
Several issues appear to me:
Your main question:
But how can I do that in the ActionPerformed Method as I can't access the combobox in the ActionPerformed method
Your likely best solution is to change your code and variable declaration placement so that you can access the JComboBox fromt he actionPerformed method. If you're declaring the combobox from within a method or constructor, change this so that it is a proper instance field of the class.
Other problems:
You should not be creating multiple JFrames. If you need a dependent window, then one should be a JDialog. If not, then consider swapping views with a CardLayout.
Learn and follow Java naming conventnions so others can better understand your code. Class names begin with capital letters and methods and variable names don't for instance.
I am not sure why you're doing this: System.exit(DO_NOTHING_ON_CLOSE);. Why pass that constant into the exit method?
Use a constructor for your action listener class:
private class main_menuhandler implements ActionListener {
private JComboBox<String> Team_ComboBox;
public main_menuhandler(JComboBox<String> Team_ComboBox){
this.Team_ComboBox = Team_ComboBox;
}
}
Now you can create the class main_menuhandlervia the constructor and add the combobox to it.
In your Overriden action you have access to it.
Try playing around with this as your code snippet isn't broad enough to actually provide proper code. But this should answer your question
I have many .java files within my project. From FTall.java i want to access {text field} t1 ('main' jFrame -> jPanel2) of the FormTTS.java
I am right now getting errors due to that only, because it cannot find symbol t1.
It is private and i cant change it to public
Edit:
I am using this code already to open up FTall from the FormTTS.java:
In a button in FormTTS
FTall forma = new FTall();
JFrame frame = forma.getFrame();
forma.setVisible(true);
and this in FTall
public JFrame getFrame() {
return jFrame1;
}
Because of the way your code is structure, you need to supply some way for FormTTS.t1
In FormTTS, provide a method to exposes t1, something like getMainTextField for example...
public JTextField getMainTextField() {
return t1;
}
You're next problem is FTall is going to need a reference to an instance of FormTTS. Probably the easiest way would be to pass a reference to the constructor of FTall
private FormTTS mainForm;
public FTall(FormTTS mainForm) {
this.mainForm= mainForm;
}
This will allow you to access t1 by simply using the mainForm reference...
JTextField field = mainForm.getMainTextField();
Personally, I would prefer not to expose the text field as it gives too much access to callers, instead I'd prefer to return the text and if required provide a means to change it...
So in FormTTS, I might do something like...
public String getMainText() {
return t1.getText();
}
// Do this only if you need to have write access
public void setMainText(String text) {
t1.setText(text);
}
But that's just me...
To obtain the value, you would use a similar approach as above (to getting the text field)
String text = mainForm.getMainText();
if i am understanding your question its simple first ensure that your text field come in to scope before access and once it come in, then use a setter to set its refrence in required class then you can access it.
I have in a JFrame some components that I want
to refer into another JFrame and I want
to get them by name and not
do public get/set methods for each.
Is there a way from Swing to get a component reference by its name like do
c#?
e.g. form.Controls["text"]
Thanks
I know this is an old question, but I found myself asking it just now. I wanted an easy way to get components by name so I didn't have to write some convoluted code each time to access different components. For example, having a JButton access the text in a text field or a selection in a List.
The easiest solution is to make all of the component variables be class variables so that you can access them anywhere. However, not everyone wants to do that, and some (like myself) are using GUI Editors that don't generate the components as class variables.
My solution is simple, I'd like to think, and doesn't really violate any programming standards, as far as I know (referencing what fortran was getting at). It allows for an easy and straightforward way to access components by name.
Create a Map class variable. You'll need to import HashMap at the
very least. I named mine componentMap for simplicity.
private HashMap componentMap;
Add all of your components to the frame as normal.
initialize() {
//add your components and be sure
//to name them.
...
//after adding all the components,
//call this method we're about to create.
createComponentMap();
}
Define the following two methods in your class. You'll need to import Component if you haven't already:
private void createComponentMap() {
componentMap = new HashMap<String,Component>();
Component[] components = yourForm.getContentPane().getComponents();
for (int i=0; i < components.length; i++) {
componentMap.put(components[i].getName(), components[i]);
}
}
public Component getComponentByName(String name) {
if (componentMap.containsKey(name)) {
return (Component) componentMap.get(name);
}
else return null;
}
Now you've got a HashMap that maps all the currently existing components in your frame/content pane/panel/etc to their respective names.
To now access these components, it is as simple as a call to getComponentByName(String name). If a component with that name exists, it will return that component. If not, it returns null. It is your responsibility to cast the component to the proper type. I suggest using instanceof to be sure.
If you plan on adding, removing, or renaming components at any point during runtime, I would consider adding methods that modify the HashMap according to your changes.
Each Component can have a name, accessed via getName() and setName(), but you'll have to write your own lookup function.
getComponentByName(frame, name)
IF you're using NetBeans or another IDE that by default creates private variables (fields) to hold all of your AWT/Swing components, then the following code may work for you. Use as follows:
// get a button (or other component) by name
JButton button = Awt1.getComponentByName(someOtherFrame, "jButton1");
// do something useful with it (like toggle it's enabled state)
button.setEnabled(!button.isEnabled());
Here's the code to make the above possible...
import java.awt.Component;
import java.awt.Window;
import java.lang.reflect.Field;
/**
* additional utilities for working with AWT/Swing.
* this is a single method for demo purposes.
* recommended to be combined into a single class
* module with other similar methods,
* e.g. MySwingUtilities
*
* #author http://javajon.blogspot.com/2013/07/java-awtswing-getcomponentbynamewindow.html
*/
public class Awt1 {
/**
* attempts to retrieve a component from a JFrame or JDialog using the name
* of the private variable that NetBeans (or other IDE) created to refer to
* it in code.
* #param <T> Generics allow easier casting from the calling side.
* #param window JFrame or JDialog containing component
* #param name name of the private field variable, case sensitive
* #return null if no match, otherwise a component.
*/
#SuppressWarnings("unchecked")
static public <T extends Component> T getComponentByName(Window window, String name) {
// loop through all of the class fields on that form
for (Field field : window.getClass().getDeclaredFields()) {
try {
// let us look at private fields, please
field.setAccessible(true);
// compare the variable name to the name passed in
if (name.equals(field.getName())) {
// get a potential match (assuming correct <T>ype)
final Object potentialMatch = field.get(window);
// cast and return the component
return (T) potentialMatch;
}
} catch (SecurityException | IllegalArgumentException
| IllegalAccessException ex) {
// ignore exceptions
}
}
// no match found
return null;
}
}
It uses reflection to look through the class fields to see if it can find a component that is referred to by a variable of the same name.
NOTE: The code above uses generics to cast the results to whatever type you are expecting, so in some cases you may have to be explicit about type casting. For example if myOverloadedMethod accepts both JButton and JTextField, you may need to explicitly define the overload you wish to call ...
myOverloadedMethod((JButton) Awt1.getComponentByName(someOtherFrame, "jButton1"));
And if you're not sure, you can get an Component and check it with instanceof...
// get a component and make sure it's a JButton before using it
Component component = Awt1.getComponentByName(someOtherFrame, "jButton1");
if (component instanceof JButton) {
JButton button = (JButton) component;
// do more stuff here with button
}
Hope this helps!
you could hold a reference to the first JFrame in the second JFrame and just loop through JFrame.getComponents(), checking the name of each element.
You can declare a variable as a public one then get the text or whatever operation you want and then you can access it in the other frame(if its in the same package) because it's public.
I needed to access elements inside several JPanels which were inside a single JFrame.
#Jesse Strickland posted a great answer, but the provided code is not able to access any nested elements (like in my case, inside JPanel).
After additional Googling I found this recursive method provided by #aioobe here.
By combining and slightly modifying the code of #Jesse Strickland and #aioobe I got a working code that can access all the nested elements, no matter how deep they are:
private void createComponentMap() {
componentMap = new HashMap<String,Component>();
List<Component> components = getAllComponents(this);
for (Component comp : components) {
componentMap.put(comp.getName(), comp);
}
}
private List<Component> getAllComponents(final Container c) {
Component[] comps = c.getComponents();
List<Component> compList = new ArrayList<Component>();
for (Component comp : comps) {
compList.add(comp);
if (comp instanceof Container)
compList.addAll(getAllComponents((Container) comp));
}
return compList;
}
public Component getComponentByName(String name) {
if (componentMap.containsKey(name)) {
return (Component) componentMap.get(name);
}
else return null;
}
Usage of the code is exactly the same as in #Jesse Strickland code.
If your components are declared inside the same class you're manipulating them from, you simply access these components as attributes of the class name.
public class TheDigitalClock {
private static ClockLabel timeLable = new ClockLabel("timeH");
private static ClockLabel timeLable2 = new ClockLabel("timeM");
private static ClockLabel timeLable3 = new ClockLabel("timeAP");
...
...
...
public void actionPerformed(ActionEvent e)
{
...
...
...
//set all components transparent
TheDigitalClock.timeLable.setBorder(null);
TheDigitalClock.timeLable.setOpaque(false);
TheDigitalClock.timeLable.repaint();
...
...
...
}
...
...
...
}
And, you may be able to access class components as attributes of the class name from other classes in the same namespace too. I can access protected attributes(class member variables), maybe you can access public components, too. Try it!
Swing does provide other ways to implement this, for the sake as exercising here is my version that implements a find in Component hierarchy context.
/**
* Description : Find a component having the given name in container desccendants hierarchy
* Assumptions : First component with the given name is returned
* #return java.awt.Component
* #param component java.awt.Component
* #param componentName java.lang.String
*/
public static Component findComponentByName(Component component, String componentName) {
if (component == null ) {
return null;
}
if (component.getName() != null && component.getName().equalsIgnoreCase(componentName)) {
return component;
}
if ( (component instanceof Container ) ) {
Component[] children = ((Container) component).getComponents();
for ( int i=0; i<children.length; i++ ) {
Component child = children[i];
Component found = findComponentByName( child, componentName );
if (found != null ) {
return found;
}
}
}
return null;
}
I have a JFrame that contains a "display" JPanel with JTextField and a "control" JPanel with buttons that should access the contents of the display JPanel. I think my problem is related on how to use the observer pattern, which in principle I understand. You need to place listeners and update messages, but I don't have a clue where to put these, how to get access from one panel to the other and maybe if necessary to introduce a "datamodel" class. For example, I want to access the contents of the JTextField from the control panel and I use an anonymous action listener as follows:
JButton openfile = new JButton("Convert file");
openfile.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
openButtonPressed();
}
});
You need to reduce the coupling between these objects.
You can have a master object, that owns all the text fields and the button ( the panels are irrelevant )
Then a separete actionlistener within that master object ( I call it mediator see mediator pattern )
That action listener performs a method on the mediator which in turn take the values from the textfields and create perhaps a transfer object.
This way you reduce the coupling between the panels, textfields etc. and let the control in one place ( the mediator ) that is, you don't let them know each other.
You can take a look at the code in this question:
https://stackoverflow.com/questions/324554/#324559
It shows these concepts in running code.
BTW the observer pattern is already implemented in the JTextField, JButton, ActionListener etc. You just need to add the hooks.
I hope this helps.
EDIT Joined two answers into one.
This is the code.
class App { // this is the mediator
// GUI components.
private JFrame frame;
private JTextField name;
private JTextField count;
private JTextField date;
// Result is displayed here.
private JTextArea textArea;
// Fired by this button.
private JButton go;
private ActionListener actionListener;
public App(){
actionListener = new ActionListener(){
public void actionPerformed( ActionEvent e ){
okButtonPressed();
}
};
}
private void okButtonPressed(){
// template is an object irrelevant to this code.
template.setData( getData() );
textArea.setText( template.getTransformedData() );
}
public void initialize(){
frame = new JFrame("Code challenge v0.1");
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
name = new JTextField();
count = new JTextField();
date = new JTextField();
textArea = new JTextArea();
go = new JButton("Go");
go.addActionListener( actionListener ); // prepare the button.
layoutComponents(); // a lot of panels are created here. Irrelevant.
}
}
Complete and running code can be retrieved here:
It is important to favor composition over inheritance when possible.
It does make the code cleaner if you create the models in one layer and add a layer or two above to create the components and layout. Certainly do not extend the likes of JFrame and JPanel.
Do not feel the need to make the composition hierarchy in the model layer exactly match the display. Then it's just a matter of taking the text from the Document and performing the relevant operation.
Okay, perhpas not that simple. Swing models are a little bit messy. In particular ButtonModel is brain damaged, and the controller area of code might not be entirely pure.
We have so called builders, which will build the parent panel out of the children. In this builder you will have access to all the subcomponents you need to listen to and can thus can implement any logic there.
Finally the builder will then return the parent panel with the complete logic.
Once you've got the parent panel it's really a mess getting to the child components and have them do anything.
thanks. I added a datamodel layer which handles somehow the communication between the panels.
I also found this link on Listeners on JTextField usefull:
link text