Java Swing modular color scheme - java

I am setting up a large scale GUI (larger than anything I have done before) using Java's Swing toolkit and I would like to set up my own custom color scheme to draw colors from so that all color definitions are in one place. To do this, I have decided to make a pseudo-static top-level class called ColorPalette (applied from https://stackoverflow.com/a/7486111/4547020 post) that contains a SchemeEnum where the programmer sets a color scheme for the entire GUI.
I would like the color selection to be independent to knowledge of color scheme. Does anyone know a design pattern or an efficient way to do this? I'm not entirely confident that my current setup is the best way to implement this, but I would like to set up a modular design where it would not be intrusive to add more ColorEnums or SchemeEnums (at compile time, not runtime).
For clarification sake, I want the programmer to be able to simply select a ColorEnum and get returned a java.awt.Color object based on the ColorEnum and the defined SchemeEnum.
For instance:
// Use the BASIC color scheme
ColorPalette.setCurrentScheme(ColorPalette.SchemeEnum.BASIC);
// Set button backgrounds
testButton.setBackground(ColorPalette.ColorEnum.DARK_RED.getColor());
testButton2.setBackground(ColorPalette.ColorEnum.BLUE.getColor());
should return different Color objects than
// Use the DARK color scheme
ColorPalette.setCurrentScheme(ColorPalette.SchemeEnum.DARK);
// Set button backgrounds
testButton.setBackground(ColorPalette.ColorEnum.DARK_RED.getColor());
testButton2.setBackground(ColorPalette.ColorEnum.BLUE.getColor());
because they have different SchemeEnums even though they are requesting the same color from ColorPalette. This way, changing the SchemeEnum changes every color in the GUI with a one line code change (or Colors could even be changed at runtime).
I've heard of HashTables being used for large data storage such as this, but I don't know how they work. Might that apply here?
Here is my code thus far. Thanks in advance!
package common.lookandfeel;
import java.awt.Color;
/**
* Class which contains the members for the color scheme used throughout the project.
* <p>This class is essentially static (no constructor, class is final, all members static) and
* should not be instantiated.
*/
public final class ColorPalette
{
/**
* The list of color schemes to choose from.
*/
public static enum SchemeEnum
{
BASIC, DARK, METALLIC
}
/**
* The list of color descriptions to choose from.
*/
public static enum ColorEnum
{
LIGHT_RED(256,0,0), RED(192,0,0), DARK_RED(128,0,0),
LIGHT_GREEN(0,256,0), GREEN(0,192,0), DARK_GREEN(0,128,0),
LIGHT_BLUE(0,0,256), BLUE(0,0,192), DARK_BLUE(0,0,128),
LIGHT_ORANGE(256,102,0), ORANGE(256,102,0), DARK_ORANGE(192,88,0),
LIGHT_YELLOW(256,204,0), YELLOW(256,204,0), DARK_YELLOW(192,150,0),
LIGHT_PURPLE(136,0,182), PURPLE(102,0,153), DARK_PURPLE(78,0,124);
private int red;
private int green;
private int blue;
private ColorEnum(int r, int g, int b)
{
this.red = r;
this.green = g;
this.blue = b;
}
/**
* Get the selected color object for this Enum.
* #return The color description as a Color object.
*/
public Color getColor()
{
// WANT TO RETURN A COLOR BASED ON currentScheme
return new Color(red, green, blue);
}
}
private static SchemeEnum currentScheme = SchemeEnum.BASIC;
/**
* Default constructor is private to prevent instantiation of this makeshift 'static' class.
*/
private ColorPalette()
{
}
/**
* Get the color scheme being used on this project.
* #return The current color scheme in use on this project.
*/
public static SchemeEnum getCurrentScheme()
{
return currentScheme;
}
/**
* Set the overall color scheme of this project.
* #param currentPalette The color scheme to set for use on this project.
*/
public static void setCurrentScheme(SchemeEnum cp)
{
currentScheme = cp;
}
/**
* Main method for test purposes only. Unpredictable results.
* #param args Command line arguments. Should not be present.
*/
public static void main(String[] args)
{
// Declare and define swing data members
JFrame frame = new JFrame("Test Environment");
CustomButton testButton = new CustomButton ("Hello World");
CustomButton testButton2 = new CustomButton ("I am a button!");
// Use a particular color scheme
ColorPalette.setCurrentScheme(ColorPalette.SchemeEnum.BASIC);
// Set button backgrounds
testButton.setBackground(ColorPalette.ColorEnum.DARK_RED.getColor());
testButton2.setBackground(ColorPalette.ColorEnum.BLUE.getColor());
// Place swing components in Frame
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(testButton, BorderLayout.NORTH);
frame.getContentPane().add(testButton2, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
// Set allocated memory to null
frame = null;
testButton = null;
testButton2 = null;
// Suggest garbage collecting to deallocate memory
System.gc();
}
}

It looks and sounds like you just need to compose SchemeEnum to be made up of ColorEnums just like how you have the ColorEnum made up of rgb values.
public static enum SchemeEnum
{
// Don't really know what colors you actually want
BASIC(ColorEnum.RED, ColorEnum.GREEN, ColorEnum.ORANGE),
DARK(ColorEnum.DARK_RED, ColorEnum.DARK_GREEN, ColorEnum.DARK_ORANGE),
METALLIC(ColorEnum.LIGHT_RED, ColorEnum.LIGHT_GREEN, ColorEnum.LIGHT_ORANGE);
// nor know how many colors make up a scheme
public ColorEnum mainColor;
public ColorEnum secondaryColor;
public ColorEnum borderColor;
private SchemeEnum(ColorEnum mainColor, ColorEnum secondaryColor,
ColorEnum borderColor)
{
this.mainColor = mainColor;
this.secondaryColor = secondaryColor;
this.borderColor = borderColor;
}
}
Then, use code like the following, where the colors are based on the selected scheme:
testButton.setBackground(ColorPalette.getCurrentScheme().mainColor.getColor());

Before you go reinventing the wheel, Swing is based on a pluggable look and feel API, see Modifying the Look and Feel.
The right way would be to define your own look and feel and load this. Because you want to provide a variable number of changes, it would probably be better to use something like Synth. This allows you to define cascading properties for objects and allows you to inherit from other properties as well (so you could devise a base set of properties and then only change the properties you need in each subsequent look and feel).
The cheat way would be to modify the UIManager directly, changing the various properties used by the current look and feel. This is sometimes easier if you want to perform small tweaks.
Either way, this will effect ALL components created by your application without you needing to do anything more then changing the look and feel at startup

Related

Do properties of properties make sense?

Because this is a question about design I'll start by saying what i have and what i want.
I have a design that uses composition. A Cell object holds a Shape and a Background objects (custom made ones for this example). Each of these 2 have their own data that defines them. here is the example in code:
class Cell {
Shape shape;
Background background;
class Shape {
int size;
Color color;
Point location;
//...
}
class Background {
Color color;
String name;
CoverType type;
//...
}
}
I also have a GUI that needs to represent many cells and i have written how to do it (how to use color, size etc. to create what i want on the screen). It includes classes such as CellRepresentation, ShapeRepresentation and BackgroundRepresentation that have their display properties bound to the the data properties (i think this is called Model and View).
I want to be able to represent changes in the GUI by changing the above data:
a user can (for example) right-click on a shape and set its color. So the data above changes and the change needs to be reflected in the GUI.
a user can also change the whole shape (for example copy-paste it from another cell). Or even the whole cell. These changes also need to reflect in the GUI.
My question is which of the class members need to be JavaFX properties that I bind to.
Here is what I am thinking: the "leaf" properties (size, color, location...) must be properties so I can bind to them the GUI property. But do I need to make the shape and background objects properties too? Only their properties have "Actual" representation on the screen. Ideally i would have liked it that if Shape changes then all of its properties tell their bindings that they could have changed (maybe the color didn't but size did). But it doesn't work this way - even though the Color of a Shape can change when the Shape changes the Color property won't tell whatever is bound to it that it changed.
The same goes for making Cell a property in the lager picture where there are many cells and so on: properties of properties delegating changes.
So I thought of making the Shape and Background also properties and registering an InvalidationListener to them updates their properties. This just doesn't seem right because i would think that with all the support for properties there would be a way to do what i want.
Can someone suggest a way to do this?
Using just the standard JavaFX API you can leverage the Bindings.selectXXX methods to observe a "property of a property".
So for example:
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.scene.paint.Color;
public class Cell {
private final ObjectProperty<Shape> shape = new SimpleObjectProperty<>(new Shape());
public final ObjectProperty<Shape> shapeProperty() {
return this.shape;
}
public final Cell.Shape getShape() {
return this.shapeProperty().get();
}
public final void setShape(final Cell.Shape shape) {
this.shapeProperty().set(shape);
}
public static class Shape {
private final IntegerProperty size = new SimpleIntegerProperty(0);
private final ObjectProperty<Color> color = new SimpleObjectProperty<>(Color.BLACK);
public final IntegerProperty sizeProperty() {
return this.size;
}
public final int getSize() {
return this.sizeProperty().get();
}
public final void setSize(final int size) {
this.sizeProperty().set(size);
}
public final ObjectProperty<Color> colorProperty() {
return this.color;
}
public final javafx.scene.paint.Color getColor() {
return this.colorProperty().get();
}
public final void setColor(final javafx.scene.paint.Color color) {
this.colorProperty().set(color);
}
}
public static void main(String[] args) {
Cell cell = new Cell();
Bindings.selectInteger(cell.shapeProperty(), "size").addListener(
(obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
cell.getShape().setSize(10);
cell.setShape(new Shape());
Shape s = new Shape();
s.setSize(20);
cell.setShape(s);
}
}
Will produce the (desired) output
Size changed from 0 to 10
Size changed from 10 to 0
Size changed from 0 to 20
This API has a bit of a legacy feel to it, in that it relies on passing the property name as a string, and consequently is not typesafe and cannot be checked at compile time. Additionally, if any of the intermediate properties are null (e.g. if cel.getShape() returns null in this example), the bindings generate annoying and verbose warning messages (even though this is supposed to be a supported use case).
Tomas Mikula has a more modern implementation in his ReactFX library, see this post for a description. Using ReactFX, you would do:
public static void main(String[] args) {
Cell cell = new Cell();
Var<Number> size = Val.selectVar(cell.shapeProperty(), Shape::sizeProperty);
size.addListener(
(obs, oldSize, newSize) -> System.out.println("Size changed from "+oldSize+" to "+newSize));
cell.getShape().setSize(10);
cell.setShape(new Shape());
Shape s = new Shape();
s.setSize(20);
cell.setShape(s);
}
Finally, if you are creating a list of cells, you can create an ObservableList specifying an extractor. The extractor is a function mapping each element in the list (each Cell) to an array of Observables. If any of those Observables changes, the list fires an update event. So you could do
ObservableList<Cell> cellList =
FXCollections.observableArrayList(cell -> new Observable[] {Bindings.selectInteger(cell.shapeProperty(), "size")});
using the standard API, or
ObservableList<Cell> cellList =
FXCollections.observableArrayList(cell -> new Observable[] {Val.selectVar(cell.shapeProperty(), Shape::sizeProperty)});
using ReactFX. Then just add a ListChangeListener to the list, and it will be notified if the size changes (or if the shape changes to a new shape with a different size). You can add as many observables that are properties (or properties of properties) of the cell in the returned array as you need.

Get value of JTextField whose name is stored in a String variable in JAVA [duplicate]

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;
}

Creating a hierarchy for shape classes within a level in Java

I'm working on a Java based game where I need to model some basic shapes. The implementation I have at the moment has a lot of duplicated attributes across shapes of the same dimensions.
Example, I have an Interactive Rectangle which is involved in Box2d world and I have a Background Rectangle which is not involved in Box2d world. But both classes need a width and height defined.
Does anyone know a better way to model this data?
Current implementation ..
Mock idea for new implementation, however Interactive and Background can only inherit from one parent.
The reason why I have Interactive and Background classes is so I can loop through my objects like below.
for (Background bgShape : getLevel.getBGShapes()){
bgShape.draw(
gl2,
new Vec3(
bgShape.getPosition().x,
bgShape.getPosition().y,
bgShape.getPosition().z));
}
for (Body body = world.getBodyList(); body != null; body = body.getNext()) {
Interactive iaShape = (Interactive) body.getUserData();
iaShape.draw(
gl2,
new Vec3(
body.getPosition().x,
body.getPosition().y,
0.0f));
}
Also Interactive class defines a number of attributes which are not present in Background,
public abstract class InteractiveShape extends Shape {
private String bodyType;
private float density;
private float friction;
private float restitution;
private boolean fixedRotation;
private Body body;
}
2nd example is much better asRectangle is really a shape, but has additional data (width and height)
I don't think Iteractive and Background are necessary unless they add any additional operations (which from the picture they do not).

Add specific background colors to JDaychooser Dates

I've developed a Java Swing application..
How can I set the background color of specific JDayChooser dates?
Thanks
getDayPanel
public javax.swing.JPanel getDayPanel()
This returns the day panel. After that, you can:
panel.setBackground(color);
Also:
setForeground
public void setForeground(java.awt.Color foreground)
Sets the foregroundColor color.
setDecorationBackgroundColor
public void setDecorationBackgroundColor(java.awt.Color decorationBackgroundColor)
Sets the background of days and weeks of year buttons.
JDayChooser has a protected field that specifies the selectedColor, but it has no public interface. You can,
Alter the default gray, in JDayChooser#init().
Add the required methods; the new bound property will appear in JCalendarDemo.
public Color getSelectedColor() {
return selectedColor;
}
public void setSelectedColor(Color selectedColor) {
this.selectedColor = selectedColor;
}
As discussed here, setBackground() doesn't read well on some Look & Feel implementations. The workaround in DecoratorButton#paint() is an example.
JPanel jPanel = jDayChooser1.getDayPanel();
Component component[] = jPanel.getComponents();
for (int i = 7; i < 49; i++) {
component[i].setBackground(Color.red);
}
Finally got a solution to do :D

Get a Swing component by name

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;
}

Categories