Статьи

Почему JavaFX получает чит?

Почему JavaFX делает то, что было бы неодобрительно, если бы оно делалось на простой старой Java? Ярким примером является обработка менеджеров и панелей. В JavaFX менеджер компоновки связан с JPanel для создания единой единицы. Затем API специально адаптируется к потребностям этого сочетания менеджера компоновки и панели. Теперь я смотрю на код и сказать себе: «Эй , что это удобно», и IS, но дело не в этом. Кто-то в какой-то момент существования Java решил, что логика компоновки должна быть отделена от хранения компонентов в контейнере. Я уверен, что есть веские причины для такого разделения. Теперь JavaFX, кажется, делает заявление, что разделение не было хорошей идеей. По сути, говоря, что простой в использовании API превосходит этот конкретный шаблон проектирования и оправдывает тесную связь. Не могу сказать, что не согласен с этим обстоятельством. Я просто хочу рычаг игрового поля. Если JavaFX нарушает правила, я тоже могу

Групповые занятия.

Бросая осторожность на ветер, я использовал все известные мне подвохи, чтобы попытаться создать несколько простых в использовании панелей для простой старой Java. Вот что у меня так далеко.

  • BorderPanel
  • CardPanel
  • GridPanel
  • BoxPanel
  • GBFPanel (заводская панель для сетки)

BorderPanel, CardPanel и GridPanel

Панели бордюров и карточек просто добавляют несколько удобных методов и не так уж увлекательны. У меня есть методы, такие как setNorth () для BorderPanel и next () и previous () для CardPanel. С GridPanel я решил создать конструктор, который принимает двумерный массив компонентов. Таким образом, вы можете указать точное местоположение каждого компонента в сетке таким образом, чтобы он фактически отражал макет конечного продукта. Пример GridPanel:

Component[][] grid = new Component[][] {
{ new JButton("1"), new JButton("A") },
{ GridPanel.spacer(), new JButton("B"), new JButton("Blue") },
{ new JButton("3") } };
GridPanel gp = new GridPanel(grid, 5, 5);

 

В качестве дополнительного бонуса этот конструктор автоматически добавит пустое пространство, когда строка будет меньше размера.

BoxPanel

С BoxPanel я смог немного креативнее. Я добавил перечисление DIRECTION, которое определяет методы spacer (), glue () и build (). Я также добавил версию varags для добавления нескольких компонентов в одну строку. Пример блока 1: — В этом коде показан новый метод addSpacer () и версия add для varargs.

BoxPanel bp = new BoxPanel(X_AXIS);

bp.addSpacer(5);
bp.add(new JLabel("Section 1"), X_AXIS.spacer(5), new JButton("A"), X_AXIS.spacer(5), new JButton("B"));
bp.addSpacer(10);
bp.add(new JComboBox());
bp.addGlue();
bp.add(new JLabel("Section 2"), X_AXIS.spacer(5), new JButton("1"), X_AXIS.spacer(5), new JButton("2"));
bp.addSpacer(5);

Пример блока 2: — В этом коде показан новый метод Direction для build (). Он также вкладывает BoxPanels в сетку.

BoxPanel rowsPanel = new BoxPanel(Y_AXIS);
rowsPanel.add(Y_AXIS.spacer(10));
for(int rows = 0; rows < 10; rows++ ){
if(rows % 2 == 0){
rowsPanel.add(X_AXIS.build(X_AXIS.spacer(5), new JLabel("Row :" + rows), X_AXIS.spacer(5) , new JComboBox(), X_AXIS.spacer(5)));
}else{
BoxPanel oddColumns = new BoxPanel(X_AXIS);
oddColumns.add(X_AXIS.spacer(5), new JLabel("Row :" + rows), X_AXIS.spacer(5) ,new JButton("Button 1"), X_AXIS.glue());
oddColumns.addSpacer(10);
oddColumns.add(new JTextField(), X_AXIS.spacer(5) ,new JButton("Button 2"), X_AXIS.glue(), X_AXIS.spacer(5));
rowsPanel.add(oddColumns);
}
rowsPanel.add(Y_AXIS.spacer(10));
}

GBFPanel — GridBagFactoryPanel

GridBagLayout — безусловно, один из самых сложных менеджеров компоновки в JDK. Я решил, что большинство проблем происходит от объекта GridBagConstraints. Просто кажется, что метод add (Component comp, Object constraint) класса Container просто недостаточно гибок для обработки тех ограничений, которые действительно нужны GridBag. Я хотел иметь дело только с отдельными ограничениями, относящимися к компоненту, с которым я имею дело. Вот что я придумал.

public class DemoPanel extends GBFPanel {

private JButton button1 = new JButton("Button 1");
private JButton button2 = new JButton("Button 2");
private JButton button3 = new JButton("Button 3");
private JButton button4 = new JButton("Button 4");
private JButton button5 = new JButton("Button 5");
private JButton button6 = new JButton("Button 6");
private JButton button7 = new JButton("Button 7");
private JButton button8 = new JButton("Button 8");
private JButton button9 = new JButton("Button 9");
private JButton button10 = new JButton("Button 10");

public DemoPanel(){

addDefaultConstraints(FILL.BOTH);

add(button1, WEIGHT.x(1));
add(button2, WEIGHT.x(1));
add(button3, WEIGHT.x(1));
add(button4, GRID.WIDTH.REMAINDER);

add(button5, GRID.WIDTH.REMAINDER);
add(button6, GRID.WIDTH.RELATIVE);
add(button7, GRID.WIDTH.REMAINDER);
add(button8, GRID.HEIGHT.REMAINDER, WEIGHT.y(1));

add(button9, GRID.WIDTH.REMAINDER);
add(button10, GRID.WIDTH.REMAINDER);

}
}

Распознать этот код? Нет? Это пример GridBagLayout Javadoc .

Увидеть? И всего за 10 строк кода макета, без побочных эффектов, которые нужно отслеживать. Хорошо, позвольте мне объяснить, что происходит. Я начал с создания интерфейса, определяющего работу одного ограничения.

public interface GridBagFactoryConstraint {

public void apply(GridBagConstraints gbc);

}

Затем, используя комбинацию перечислений и статических методов фабрики, я реализовал класс, представляющий каждое ограничение из GridBagConstraints. Вот реализация перечисления FILL в качестве примера.

public enum FILL implements GridBagFactoryConstraint {

HORIZONTAL(GridBagConstraints.HORIZONTAL),
VERTICAL(GridBagConstraints.VERTICAL),
BOTH(GridBagConstraints.BOTH),
NONE(GridBagConstraints.NONE);

private int gbcValue;

private FILL(int val) {
gbcValue = val;
}

public void apply(GridBagConstraints gbc) {
gbc.fill = gbcValue;
}
}

Я знаю, что вы думаете, и да, я действительно сделал
все из них. Следующим шагом было создание метода добавления в GBFPanel, который принимал бы переменное число этих объектов ограничения.

public void add(Component comp, GridBagFactoryConstraint... constraints) {
....
}

Это метод add, используемый в моем примере кода выше. Теперь некоторые из вас, возможно, заметили вызов addDefaultConstraints (). Этот метод позволяет указать ограничения, которые вы хотите применить к каждому компоненту, добавленному на панель. Это удобно для вычленения общих ограничений. Ограничения, переданные в методе add, всегда будут переопределять любые значения по умолчанию. Некоторое время назад на java.net произошла «перестрелка менеджера по макету». Вот как могла бы выглядеть запись GBFPanel.

public class AddressShootout extends GBFPanel {

private JTextField lastNameTF = new JTextField(15);
private JTextField firstNameTF = new JTextField(15);
private JTextField phoneTF = new JTextField(15);
private JTextField addressTF = new JTextField(20);
private JTextField emailTF = new JTextField(15);
private JTextField stateTF = new JTextField(2);
private JTextField cityTF = new JTextField(15);

public AddressShootout() {

addDefaultConstraints(ANCHOR.E, INSETS.top(5), INSETS.left(5), INSETS.right(5));

add(new JLabel("Last Name"));
add(lastNameTF, FILL.HORIZONTAL, WEIGHT.x(1));
add(new JLabel("First Name"));
add(firstNameTF, FILL.HORIZONTAL, WEIGHT.x(1), GRID.WIDTH.REMAINDER);

add(new JLabel("Phone"));
add(phoneTF, FILL.HORIZONTAL, WEIGHT.x(1));
add(new JLabel("Email"));
add(emailTF, FILL.HORIZONTAL, WEIGHT.x(1), GRID.WIDTH.REMAINDER);

add(new JLabel("Address"));
add(addressTF, FILL.HORIZONTAL, WEIGHT.x(1), GRID.WIDTH.REMAINDER);

add(new JLabel("City"), INSETS.bottom(5));
add(cityTF, FILL.HORIZONTAL, WEIGHT.x(1), INSETS.bottom(5));
add(new JLabel("State"), INSETS.bottom(5));
add(stateTF, FILL.HORIZONTAL, WEIGHT.x(1), INSETS.bottom(5));

}
}

Я переопределил примеры учебников по javadoc и Java для GridBagLayout и обнаружил две вещи.

1. Это делает работу намного меньше кода.

2. Примеры почти полностью бесполезны.

Затем я переопределил ряд других «примерных макетов» от некоторых сторонних менеджеров макетов. Я снова обнаружил две вещи.

1. Это делает работу почти одинаковой по объему кода.

2. Их примеры гораздо больше сфокусированы на реальных ситуациях развития.

Выводы

Я думаю, что GridBag больше всего выигрывает от этой злой жесткой связи. Другие макеты стали легче читать, но они не получили реальной силы Можно с уверенностью сказать, что чем сложнее менеджер компоновки, тем больше выиграет от тесной связи. Другие возможности для этой обработки включают SpringPanel, OverlayPanel, FlowPanel, GroupPanel, TablePanel, MigPanel, FormPanel и PagePanel. Так что это зло, верно? JavaFX делает это. Почему мы не должны? Это архитектурный компромисс, который того стоит?