Сводка. При создании JComponent вы часто объявляете переменные свойств (шрифты, цвета, размеры и т. Д.). Многие компоненты в графическом интерфейсе используют один и тот же формат (например, наборы кнопок, текстовые поля). Таким образом, вы определяете подкласс шрифта Font. Если вы хотите реализовать изменение для всей группы для каждого компонента, который использует только шрифт, как вы поступите с этим? Мое текущее решение состоит в том, чтобы создать ArrayList для каждого свойства, а затем добавить компонент, который его использует. Это утомительно.
Другими словами, я хочу иметь возможность динамически идентифицировать мои именованные переменные, используемые при построении компонента (то есть свойства), чтобы я мог вносить изменения во всей программе.
Я пытался использовать утилиту отражения Java, но возникли проблемы с этим методом, и они будут описаны позже.
обо всем по порядку: давайте определим пример, чтобы показать вам, что я делаю. Создайте класс, определите несколько компонентов, определите переменные свойств, добавьте свойства к компонентам.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class CLASSNAME{
//First define all variables to be accessed within the class //so they can be accessed within the whole class.
JPanel panel;
JButton button;
JLabel label;
String stringButton;
String stringLabel;
int[] setCol={125,125,125};
Font font;
Color color;
Dimension dimension;
Dimension dimension2;
FlowLayout flowlayout;
//Then build the UI class
classUI extends JFrame{
panel =new JPanel();
button =new JButton();
label =new JLabel();
//Then define spec variables to pass into these components.
stringButton="Button";
stringLabel="Label";
font =new Font("Arial",font.PLAIN,18);
color =new Color(setCol[1],setCol[2],setCol[3]);
dimension =new Dimension(150,150);
dimension2=new Dimension(100,100);
flowlayout =new FlowLayout();
//Pass these spec variables into the components as required.
panel.setLayout(flowlayout);
panel.setPreferredSize(dimension);
panel.setBackground(color);
label.setFont(font);
label.setText(stringLabel);
label.setBackground(color);
label.setPreferredSize(dimension2);
button.setText(stringButton);
button.setFont(font);
button.setPreferredSize(dimension2);
Необходимо заранее определить каждую переменную в качестве первого входа в класс, чтобы получить доступ ко всем компонентам и переменным свойств компонента из любого места в классе, в том числе в функциях или вне класса. (но см. ответ ниже fd , если вы не хотите предварительно определять каждый компонент.)
Конкретный пример: чтобы изменить свойство JComponent, вам нужен новый экземпляр переменной свойства, а затем нужно перекрасить этот компонент и панель, если она видна.
font=new Font("Arial",font.PLAIN,12);
//Camickr correctly commented I had left these two lines out.
label.setFont(font);
button.setFont(font);
// I think this is redundant - namely when setting a property
// the component is repainted automatically.
label.repaint();
button.repaint();
/* does the panel the component is displayed on need a repaint()?
* from what I can tell usually not.
*/
Это хорошо, если у вас есть 5 компонентов, и вам не нужны изменения.
Однако, если вы начинаете иметь около 30-50 компонентов в графическом интерфейсе и хотите внести изменения ... например, просто измените шрифты компонентов, которые используют шрифт, у вас есть список из 50 компонентов, поэтому я хочу получить к ним динамический доступ.
Таким образом:
1) Я хочу динамически найти все компоненты по имени и типу компонента.
У меня есть частичное решение с использованием java.reflect.util
2) Я хочу динамически найти, какая переменная свойства (спецификации) использовалась при определении компонента. java.reflect.util не хранит записи о том, какие компоненты передают какой переменной.
Существует решение проблемы, которое не является динамическим : объявляйте ArrayList для каждой спецификации и добавляйте его вручную при каждом его использовании.
Пример:
// для каждого свойства, используемого в JComponent, создаем массив.
// поэтому для примера вы должны определить ArrayLists следующим образом
ArrayList<Object> spec_stringButton=new ArrayList();
ArrayList<Object> spec_arraystringLabel=new ArrayList();
ArrayList<Object> spec_arrayfont =new ArrayList();
ArrayList<Object> spec_color =new ArrayList();
ArrayList<Object> spec_dimension =new ArrayList();
ArrayList<Object> spec_dimension2=new ArrayList();
ArrayList<Object> spec_flowlayout =new ArrayList();
и затем:
// вручную добавляем, какие компоненты использовали каждую переменную. Это отстой.
spec_stringButton.add (кнопка);
spec_arraystringLabel.add(label);
spec_arrayfont.add(button);
spec_arrayfont.add(label);
spec_color.add(label);
spec_color.add(panel);
spec_dimension.add(panel);
spec_dimension2.add(button);
spec_dimension2.add(label);
spec_flowlayout.add(panel);
Это решение работает. Но это не элегантное решение. Это очень трудоемко, вы должны помнить, чтобы добавить каждый компонент, который использует свойство.
Всякий раз, когда вам нужно внести изменения в группе, вы можете сделать это достаточно легко:
//spec=new spec;
dimension2=new Dimension(80,40);
int i=0;
for (i=0;i<spec_dimension2.size();i++){
JComponent a=(JComponent)spec_dimension2.get(i);
//component.setSpec(new spec);
a.setPreferredSize(dimension2);
//component.repaint();
a.repaint();
//proof we have made the change.
System.out.println(a.getPreferredSize());
}
Нет ли способа динамического доступа к тому, какая переменная свойства использовалась компонентом?
Какие инструменты доступны? После долгих поисков Java.lang. отражать полезность приходит на ум.
Из учебника:
//Field comes from java.lang.reflect.field
try {
int i=0;
Class cls = Class.forName("CLASSNAME");
Field fieldlist[] = cls.getDeclaredFields();
for ( i= 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
System.out.println(" name = " + fld.getName());
System.out.println(" decl class = " +fld.getDeclaringClass());
System.out.println(" type= " + fld.getType());
System.out.println(" declaredannotations="+fld.getDeclaredAnnotations());
System.out.println(" generic type="+fld.getGenericType());
System.out.println(" get type ="+fld.getType());
System.out.println(" hashcode="+fld.hashCode());
System.out.println(" to generic string="+fld.toGenericString());
int mod = fld.getModifiers();
System.out.println(" modifiers = " +Modifier.toString(mod));
System.out.println(" -----");
}
Я пошел, чтобы отразить полезность и попробовал все методы выше. Строки println выводят следующее и показывают, что вы можете динамически получать доступ к объявленным переменным в классе, включая тип класса (например, тип компонента):
name = panel
decl class = class CLASSNAME
type= class javax.swing.JPanel
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class javax.swing.JPanel
get type =class javax.swing.JPanel
hashcode=-1546142233
to generic string=javax.swing.JPanel CLASSNAME.panel
modifiers =
-----
name = button
decl class = class CLASSNAME
type= class javax.swing.JButton
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class javax.swing.JButton
get type =class javax.swing.JButton
hashcode=141398225
to generic string=javax.swing.JButton CLASSNAME.button
modifiers =
-----
name = label
decl class = class CLASSNAME
type= class javax.swing.JLabel
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class javax.swing.JLabel
get type =class javax.swing.JLabel
hashcode=-1550792425
to generic string=javax.swing.JLabel CLASSNAME.label
modifiers =
-----
name = stringButton
decl class = class CLASSNAME
type= class java.lang.String
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.lang.String
get type =class java.lang.String
hashcode=1112659264
to generic string=java.lang.String CLASSNAME.stringButton
modifiers =
-----
name = stringLabel
decl class = class CLASSNAME
type= class java.lang.String
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.lang.String
get type =class java.lang.String
hashcode=23733888
to generic string=java.lang.String CLASSNAME.stringLabel
modifiers =
-----
name = font
decl class = class CLASSNAME
type= class java.awt.Font
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.awt.Font
get type =class java.awt.Font
hashcode=-1514161236
to generic string=java.awt.Font CLASSNAME.font
modifiers =
-----
name = color
decl class = class CLASSNAME
type= class java.awt.Color
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.awt.Color
get type =class java.awt.Color
hashcode=-1607952256
to generic string=java.awt.Color CLASSNAME.color
modifiers =
-----
name = dimension
decl class = class CLASSNAME
type= class java.awt.Dimension
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.awt.Dimension
get type =class java.awt.Dimension
hashcode=456448645
to generic string=java.awt.Dimension CLASSNAME.dimension
modifiers =
-----
name = dimension2
decl class = class CLASSNAME
type= class java.awt.Dimension
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.awt.Dimension
get type =class java.awt.Dimension
hashcode=-1120040849
to generic string=java.awt.Dimension CLASSNAME.dimension2
modifiers =
-----
name = flowlayout
decl class = class CLASSNAME
type= class java.awt.FlowLayout
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class java.awt.FlowLayout
get type =class java.awt.FlowLayout
hashcode=-466921925
to generic string=java.awt.FlowLayout CLASSNAME.flowlayout
modifiers =
-----
name = setCol
decl class = class CLASSNAME
type= class [I
declaredannotations=[Ljava.lang.annotation.Annotation;@15dfd77
generic type=class [I
get type =class [I
hashcode=1871572573
to generic string=int[] CLASSNAME.setCol
modifiers =
-----
Итак, у нас есть динамический метод для доступа к каждой объявленной переменной, будь то компонент или спецификация. (Эта функция не существует в C ++!)
fld.getName () выведет список всех объявленных имен переменных в классе.
fld.getType () предоставит типы Компонентов и даже свойства (шрифт, цвет и т. Д.), Которые мы хотим, но они должны быть извлечены.
Таким образом, должна быть возможность динамически извлекать / создавать список всех Компонентов и всех переменных свойств.
Отлично. Но до сих пор нет способа показать, какая переменная передана какому компоненту. Кажется, что нет прямого способа доступа к используемому имени свойства переменной. Беспокоить.
Итак ... одно решение: возможно пройти через все компоненты, и если он соответствует текущему (например, если размерность 100,100, то это должен быть размер переменной). Но если вы определите две переменные с одинаковыми текущими параметрами? Было бы гораздо эффективнее иметь доступ к имени переменной. Так что это не хорошо.
Может ли Java показать, какое свойство (которое я назвал спецификационной переменной) использовалось при определении компонента? простым английским языком = если я определил шрифт Font, могу ли я найти компоненты, которые используют шрифт.
если нет ... может кто-нибудь придумает способ динамически добавить переменную в ArrayList без ручного вызова "spec_stringButton.add (button)";
Вторая проблема - это утилита Reflect в Java. Строка println показывает, что вы можете получить доступ к каждому компоненту и к какому типу он относится, например, JPanel, JLabel, JButton и т. Д. Но с какой стати вы используете строковое имя и передаете его в объект?
ВОПРОС 2, на который нужно ответить: как изменить поле доступа и передать его в то, что я могу использовать? Мне удалось передать Поле в Струну. Но получение имени объекта из строки в компонент создает проблемы.
// this String objectname works.
String type= fld.getType().getName();
Вывод этой строки должен позволить вам получить доступ и ограничить поиск типами JComponent.
Однако получить доступ к объекту и затем привести его к объекту JComponent из String name было бесполезно.
первый:
String name=fld.getName();
name дает имена ваших компонентов.
Использование метода Arraylist
ArrayList<Object> a=new ArrayList();
a.add(name);
JComponent b=(JComponent)a.get(0);
Это приводит к следующей красивой ошибке:
java.lang.ClassCastException: java.lang.String не может быть приведен к
javax.swing.JComponent
Я пытаюсь преобразовать вывод имени переменной String и преобразовать его в объект. Совет пожалуйста.
Итак, решение Ideally Elegant могло бы сказать что-то вроде:
переменная спецификация = новая спецификация.
1) для каждого использования свойства переменной получите имя и тип компонента.
(Я знаю, что это логика обратного типа).
2) используя тип компонента, соответственно сбросьте спецификацию переменной
например component.setSpec (новая спецификация);
(e.g. for a font TitledBorder would have to be setTitleFont(),
otherwise setFont();)
3) component.repaint ();
Другими потенциальными решениями может быть попытка динамически добавить спецификацию в качестве массива. Кто-нибудь написал класс, который может отслеживать имена переменных, используемых для добавления свойств ко всем компонентам? Если бы не кто-то мог работать над решением.
В настоящее время я пытаюсь добавить addPropertyListener для каждого компонента. Это вызывает событие при изменении свойства (но не макета). Возможно, можно было бы определить используемую переменную (спецификацию) и использовать тот факт, что изменение свойства было зарегистрировано для динамического добавления в решение ArrayList.
Для удобства: код, который я здесь написал, завершен в одном разделе.
Пожалуйста, используйте, чтобы внести изменения для реализации вашего решения. Или поиграться с примером.
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
class CLASSNAME extends JFrame{
JPanel panel;
JButton button;
JLabel label;
String stringButton;
String stringLabel;
Font font;
Color color;
Color color2;
Dimension dimension;
Dimension dimension2;
FlowLayout flowlayout;
int[] setCol={125,125,125};
int[] setCol2={100,100,100};
public CLASSNAME(){
panel =new JPanel();
button =new JButton();
label =new JLabel();
stringButton="Button";
stringLabel="Label";
font =new Font("Arial",font.PLAIN,18);
color =new Color(setCol[0],setCol[1],setCol[2]);
color2=new Color(setCol2[0],setCol2[1],setCol2[2]);
dimension =new Dimension(150,150);
dimension2=new Dimension(150,150);
flowlayout =new FlowLayout();
panel.setLayout(flowlayout);
panel.setPreferredSize(dimension);
panel.setBackground(color);
label.setFont(font);
label.setText(stringLabel);
label.setBackground(color2);
button.setText(stringButton);
button.setFont(font);
/* This is the reflect utility. Allows you dynamic access to the list of
* components in a class.
*/
try {
int i=0;
Class cls = Class.forName("CLASSNAME");
Field fieldlist[] = cls.getDeclaredFields();
for ( i= 0; i < fieldlist.length; i++) {
Field fld = fieldlist[i];
try{
String objectname= fld.getType().getName();
Object a=objectname;
System.out.println("preferredsize="+((JComponent) a).getPreferredSize());
}catch(Exception e){}
System.out.println(" name = " + fld.getName());
System.out.println(" decl class = " +fld.getDeclaringClass());
System.out.println(" type= " + fld.getType());
System.out.println(" declaredannotations="+fld.getDeclaredAnnotations());
System.out.println(" generic type="+fld.getGenericType());
System.out.println(" get type ="+fld.getType());
System.out.println(" hashcode="+fld.hashCode());
System.out.println(" to generic string="+fld.toGenericString());
int mod = fld.getModifiers();
System.out.println(" modifiers = " +Modifier.toString(mod));
System.out.println(" -----");
}
}catch (Throwable a) {System.err.println(a);}
//This is my current solution. Create an array list for each property,
// and add to it every time you add a property to a Component.
ArrayList<Object> spec_stringButton=new ArrayList();
ArrayList<Object> spec_arraystringLabel=new ArrayList();
ArrayList<Object> spec_arrayfont =new ArrayList();
ArrayList<Object> spec_color =new ArrayList();
ArrayList<Object> spec_dimension =new ArrayList();
ArrayList<Object> spec_dimension2=new ArrayList();
ArrayList<Object> spec_flowlayout =new ArrayList();
//and then:
spec_stringButton.add(button);
spec_arraystringLabel.add(label);
spec_arrayfont.add(button);
spec_arrayfont.add(label);
spec_color.add(label);
spec_color.add(panel);
spec_dimension.add(panel);
spec_dimension2.add(button);
spec_dimension2.add(label);
spec_flowlayout.add(panel);
//so then whenever you need to make a groupwide change you can do
//this with just 7 lines:
dimension2=new Dimension(80,40);
int i=0;
for (i=0;i<spec_dimension2.size();i++){
JComponent a=(JComponent)spec_dimension2.get(i);
a.setPreferredSize(dimension2);
a.repaint();
//shows that the change has been implemented.
System.out.println(a.getPreferredSize());
}
}
}