Introspection (JavaFx) - java

after having made quite a lot of searches, I leave it up to you.
Here is in my application JavaFx, I use the introspection to generate a gridPane automatically (that I insert then into Dialog). Thus I have TableView, when the user doubles click above, it generates Dialog containing the columns of this TableView.
In this Dialog, thus there is TextFields which allow to modify the values of fields in TableView.
But well, I cannot get back the value of my attributes by means of the introspection, and how make get back the value of the textFields which were created thanks to the introspection?
There is my introspection method :
public static GridPane analyserChamp(Etudiant etu) {
List<String> list = new ArrayList<>();
Class<? extends Etudiant> classPixel = etu.getClass();
Field attribut[] = classPixel.getDeclaredFields();
GridPane gp = new GridPane();
int i=0;
for(Field p : attribut) {
list.add(p.getName());
Label lab = new Label();
if(!p.getName().equals("classe")) {
TextField l = new TextField();
lab.setText(p.getName());
gp.add(l, 1, i);
}else {
ComboBox<String> cb = new ComboBox<String>();
cb.getItems().addAll("1Bi","2Bi","3Bi");
gp.add(cb, 1, i);
}
gp.add(lab, 0, i);
i++;
}
return gp;
}
Here is the code where I call on to the method of introspection :
if(e.getClickCount() == 2) {
Dialog<Etudiant> dialog = new Dialog<>();
Etudiant test = tableViewEtudiant.getSelectionModel().getSelectedItems().get(0);
if(test!=null) {
dialog.setTitle("Editor");
dialog.setHeaderText("You can update your question");
dialog.getDialogPane().setContent(Analysateur.analyserChamp(test));
ButtonType buttonCancel = new ButtonType("Cancel", ButtonData.CANCEL_CLOSE);
ButtonType buttonOk = new ButtonType("Ok", ButtonData.OK_DONE);
dialog.getDialogPane().getButtonTypes().addAll(buttonOk,buttonCancel);
//Confirmation of the edition
Optional<Etudiant> result = dialog.showAndWait();
//Edition of the question in the gson file
GridPane tmp = Analysateur.analyserChamp(test);
if(result.isPresent()) {
// Here ?????
}
}
Thank in advance ;)

There are many ways of solving this, for example, you can use the userData property to store the key of the attributes, so you can iterate later over the GridPane children and obtain each value in the Dialog result converter.
When you introspect the class Etudiant:
if(!p.getName().equals("classe")) {
TextField l = new TextField();
l.setUserData(p.getName()); //Store the attribute name in the TextField
lab.setText(p.getName());
gp.add(l, 1, i);
}else {
ComboBox<String> cb = new ComboBox<String>();
cb.setUserData(p.getName()); //Store the attribute name in the ComboBox
cb.getItems().addAll("1Bi","2Bi","3Bi");
gp.add(cb, 1, i);
}
When you creat the Dialog:
Dialog<Etudiant> dialog = new Dialog<>();
...
GridPane content = Analysateur.analyserChamp(test); //Keep the content accesible
...
dialog.getDialogPane().setContent(content);
...
dialog.setResultConverter(button -> { //Convert the result
Etudiant result = new Etudiant();
for (Node child : content.getChildren()) { //Iterate over the GridPane children
if (child instanceof TextField) {
String attribute = ((TextField)child).getUserData();
String value = ((TextField)child).getTest();
//Set the value in the result attribute via instrospection
}
if (child instanceof ComboBox) {
//Do the same with combos
}
}
});

Store a Supplier for getting the value of the input for a field in a Map<Field, Supplier<?>>. This way you could go through the entries of the map and retrieve the values for the assignments:
public class ReflectionDialog<T> extends Dialog<T> {
public ReflectionDialog(Class<T> type, Supplier<T> factory) throws IllegalAccessException {
GridPane gp = new GridPane();
Field[] fields = type.getDeclaredFields();
// stores getters for result value
final Map<Field, Supplier<?>> results = new HashMap<>();
int i = 0;
for (Field field : fields) {
if (String.class.equals(field.getType())) {
String name = field.getName();
Node input;
Supplier<?> getter;
if ("classe".equals(name)) {
ComboBox<String> cb = new ComboBox<>();
cb.getItems().addAll("1Bi", "2Bi", "3Bi");
getter = cb::getValue;
input = cb;
} else {
TextField l = new TextField();
getter = l::getText;
input = l;
}
results.put(field, getter);
gp.addRow(i, new Label(name), input);
i++;
}
}
getDialogPane().setContent(gp);
getDialogPane().getButtonTypes().addAll(ButtonType.OK, ButtonType.CANCEL);
setResultConverter(buttonType -> {
if (buttonType == ButtonType.OK) {
// create & initialize new object
final T object = factory.get();
results.forEach((k, v) -> {
try {
k.set(object, v.get());
} catch (IllegalAccessException ex) {
throw new IllegalStateException(ex);
}
});
return object;
} else {
return null;
}
});
}
}
public class A {
String classe;
String value;
#Override
public String toString() {
return "A{" + "classe=" + classe + ", value=" + value + '}';
}
}
ReflectionDialog<A> dialog = new ReflectionDialog<>(A.class, A::new);
A result = dialog.showAndWait().orElse(null);
System.out.println(result);

Related

How to get a value from an EventHandler

I'm trying to get the value from the Textfield named getText. However, it doesn't let me get the value since it's inside the handler. Is there a way I can return or save this value?
Here's the code:
EventHandler<ActionEvent> handler2 = k -> {
if (!getText.getText().isEmpty()) {
String NameOfFile = getText.getText();
finallyname[0]=NameOfFile;
StringBuilder sb1 = new StringBuilder(NameOfFile);
sb1.append(".txt");
String newStr=sb1.toString();
System.out.println(newStr);
name.setText(newStr);
stage.show();
stage1.close();
theWindow.getChildren().addAll(v1);
r1.setOnMouseClicked(ME -> {
if (ME.getButton().equals(MouseButton.PRIMARY) && ME.getClickCount() == 2) {
try {
Parent newtxtFile = FXMLLoader.load(getClass().getResource("txtFile.fxml"));
Stage stagenew = new Stage();
Scene scenenew = new Scene(newtxtFile);
stagenew.setTitle(getText.getText());
stagenew.setScene(scene);
stagenew.show();
} catch (IOException ex) {
}
}
});
} else {
l2.setTextFill(Color.RED);
l2.setText("Please enter a value first.");
}
};

How to access values from automatically generated Labels?

Here I receive an ObservableList of Products. Then for each Product in the List I create a Label for the name, price and quantity. I also create two Buttons, to add and remove quantity, altering the value in the label. My problem is in the ´escolherProdutos()´ method, where I want to access the value of each Label respective to de quantity so I can know what quantities of each product are being requested, and I cant seem to access these values from outside the populateFlowPane() method. This is probably not the best solution to my problem, and I am a beginner, so if you can help me solve my problem or even have a better way of doing this I would be really grateful.
public class EscolherProdutosController
{
#FXML private VBox nomesVBox;
#FXML private VBox precoVBox;
#FXML private VBox qtdsVBox;
#FXML private Button escolherBtn;
private static ArrayList<Label> quantidades = new ArrayList<>();
#FXML
public void initialize()
{
populateFlowPane();
}
public void populateFlowPane()
{
ObservableList<Produto> produtos = Logic.getProdutos();
produtos.forEach(prod -> {
HBox hbox = new HBox(5);
Label nome = new Label(prod.getNome());
Label preco = new Label(String.valueOf(prod.getPreco()));
Button minus = new Button("-");
minus.setMinSize(20, 20);
Label qtd = new Label("0");
Button plus = new Button("+");
nomesVBox.getChildren().add(nome);
precoVBox.getChildren().add(preco);
hbox.getChildren().addAll(minus, qtd, plus);
qtdsVBox.getChildren().add(hbox);
//remover unidades do produto
minus.setOnAction((ActionEvent e) -> {
int quantidade = Integer.parseInt(qtd.getText());
if(quantidade >= 1)
{
quantidade--;
qtd.setText(String.valueOf(quantidade));
}
});
//adicionar unidades do produto
plus.setOnAction((ActionEvent e) -> {
int quantidade = Integer.parseInt(qtd.getText());
if(quantidade >= 0)
{
quantidade++;
qtd.setText(String.valueOf(quantidade));
}
});
quantidades.add(qtd);
});
}
public void escolherProdutos()
{
ObservableList<Produto> produtos = Logic.getProdutos();
produtos.forEach(prod -> {
quantidades.forEach(qtd -> {
Logic.escolherProdutos(prod.getIdProduto(),
Integer.parseInt(qtd.getText()));
});
});
}
}
I would probably add them to a list and access them accordingly im not sure what you need from them because you are being vague but take a look at the code sample below
public class MySceneController {
#FXML private ListView listView;
private ArrayList<Label> labelList = new ArrayList<>();
#FXML
public void initialize()
{
populateListView();
}
public void populateListView()
{
ObservableList<Products> products = Logic.getProducts();
products.forEach(prod -> {
Label label = new Label(prod.getName());
//Add them to a list here
labelList.add(label);
listView.getItems().addAll(results);
});
}
public void doSomething()
{
for (Label label : labelList) {//Maybe iterate through the list depending on what you need
//do something
}
//Here is where I need to access the label values
}
}
I solved the problem. Maybe it's not the best solution, but it works for me. What I did was create a HashMap where the product ID is the key and the quantity is the value.
Then for the add and remove buttons, I simply replace the value for the corresponding key in the HashMap. Doing this, I can then use it as input for the escolherProdutos() method from the Logic class, to select the products.
public class EscolherProdutosController
{
#FXML private VBox nomesVBox;
#FXML private VBox precoVBox;
#FXML private VBox qtdsVBox;
private HashMap<BigDecimal, Integer> quantidades = new HashMap<>();
#FXML
public void initialize()
{
populateFlowPane();
}
public void populateFlowPane()
{
ObservableList<Produto> produtos = Logic.getProdutos();
produtos.forEach(prod -> {
HBox hbox = new HBox(5);
Label nome = new Label(prod.getNome());
Label preco = new Label(String.valueOf(prod.getPreco()));
Button minus = new Button("-");
minus.setMinSize(20, 20);
Label qtd = new Label("0");
Button plus = new Button("+");
nomesVBox.getChildren().add(nome);
precoVBox.getChildren().add(preco);
hbox.getChildren().addAll(minus, qtd, plus);
qtdsVBox.getChildren().add(hbox);
//remover unidades do produto
minus.setOnAction((ActionEvent e) -> {
Integer quantidade = Integer.parseInt(qtd.getText());
if(quantidade >= 1)
{
quantidade--;
qtd.setText(String.valueOf(quantidade));
if(quantidades.containsKey(prod.getIdProduto()))
quantidades.replace(prod.getIdProduto(), quantidade);
else
quantidades.put(prod.getIdProduto(), quantidade);
}
});
//adicionar unidades do produto
plus.setOnAction((ActionEvent e) -> {
Integer quantidade = Integer.parseInt(qtd.getText());
if(quantidade >= 0)
{
quantidade++;
qtd.setText(String.valueOf(quantidade));
if(quantidades.containsKey(prod.getIdProduto()))
quantidades.replace(prod.getIdProduto(), quantidade);
else
quantidades.put(prod.getIdProduto(), quantidade);
}
});
});
}
public void escolherProdutos()
{
Logic.escolherProdutos(quantidades);
}

RadioGroupButton deselect value when button is clicked in Vaadin 14

I've been working on an online exam project and currently adding some multiple choice feature. My problem is, each time I moved to the next question the value from the previous radiogroupbutton is removed/deselect. But still the assigned value of the object is present.
I tried removing/adding the component as well, still the selected value for the RadioGroupButton is missing.
public class TestQuestionaire extends Dialog {
TQCoverageService tqcs = new TQCoverageServiceImpl();
CellItemService cis = new CellItemServiceImpl();
ItemKeyService iks = new ItemKeyServiceImpl();
VerticalLayout mainLayout;
TQCoverage tqCoverage;
List<CellItem> ciList = new ArrayList();
Map<CellItem, CellItemOption> cellItemAnswerMap = new HashMap();
CellItem cellItem;
Binder<CellItem> binder;
private int tqCoverageId;
private int cellItemIndex = 0;
private int cellItemIndexSize = 0;
private int score = 0;
Button next;
Button prev;
String stem;
Paragraph stemHolder;
RadioButtonGroup<CellItemOption> cioGroup;
public TestQuestionaire(int tqCoverageId) {
this.tqCoverageId = tqCoverageId;
tqCoverage = tqcs.findTQCoverage(tqCoverageId);
cellItemIndexSize = tqCoverage.getTotalItems();
for(TQItems tqi : tqcs.findAllTQItems(tqCoverageId)){
cellItem = cis.findCellItem(tqi.getCellItemId());
List<CellItemOption> cioList = cis.findAllItemOptions(tqi.getCellItemId());
cellItem.setCellItemOptionList(cioList);
ItemKey ik = iks.findItemKey(tqi.getItemKeyId());
cellItem.setItemKey(ik);
TQAnswerKey tqak = tqcs.findTQAnswerKeyByTQItem(tqi.getTqItemId());
cellItem.setTQAnswerKey(tqak);
cellItemAnswerMap.put(cellItem, new CellItemOption());
ciList.add(cellItem);
}
stemHolder = new Paragraph();
stemHolder.setWidthFull();
stemHolder.getStyle().set("font-weight", "500");
Hr hr = new Hr();
hr.setWidthFull();
cioGroup = new RadioButtonGroup<>();
cioGroup.setRenderer(new TextRenderer<>(CellItemOption::getCellItemOption));
cioGroup.addThemeVariants(RadioGroupVariant.LUMO_VERTICAL);
cioGroup.addValueChangeListener(event -> {
if(event.getValue() == null){
return;
}
if(!event.getValue().equals(event.getOldValue())){
cellItemAnswerMap.replace(getCellItem(), event.getValue());
}
});
mainLayout = new VerticalLayout(stemHolder, hr, cioGroup);
mainLayout.setWidth("600px");
hr = new Hr();
hr.setWidthFull();
mainLayout.add(hr);
binder = new Binder();
binder.forField(cioGroup)
.bind(CellItem::getCellItemOption, CellItem::setCellItemOption);
changeCellItem();
prev = new Button(VaadinIcon.BACKWARDS.create());
prev.addClickListener(event -> {
cellItemIndex--;
if(cellItemIndex == 0){
prev.setEnabled(false);
next.setEnabled(true);
} else {
prev.setEnabled(true);
next.setEnabled(true);
}
changeCellItem();
});
prev.setEnabled(false);
next = new Button(VaadinIcon.FORWARD.create());
next.getStyle().set("margin-left", "490px");
next.addClickListener(event -> {
cellItemIndex++;
if((cellItemIndex + 1) == cellItemIndexSize){
next.setEnabled(false);
prev.setEnabled(true);
} else {
next.setEnabled(true);
prev.setEnabled(true);
}
changeCellItem();
});
//this button is only to test if the current value for radiobuttongroup is removed/deselect when clicked!!
mainLayout.add(new Button("TEST", event -> {
changeCellItem();
}));
HorizontalLayout buttons = new HorizontalLayout(prev, next);
buttons.setWidthFull();
buttons.setJustifyContentMode(FlexComponent.JustifyContentMode.START);
mainLayout.add(buttons);
add(mainLayout);
open();
}
//refresh components for new/previous set if item
private void changeCellItem(){
stemHolder.removeAll();
cellItem = ciList.get(getCellItemIndex());
stem = cellItem.getItem().replace("{key}", cellItem.getItemKey().getItemKey());
stemHolder.add(stem);
cioGroup.clear();
cioGroup.setItems(cellItem.getCellItemOptionList());
cellItem.setCellItemOption(cellItemAnswerMap.get(cellItem));
binder.readBean(cellItem);
//binder.setBean(cellItem);
}
public TQCoverage getTQCoverage() {
return tqCoverage;
}
public CellItem getCellItem() {
return cellItem;
}
public int getCellItemIndex() {
return cellItemIndex;
}
public int getCellItemIndexSize() {
return cellItemIndexSize;
}
}

Gwt Button dropdown in celltable event handling on children

I have too many buttons in a table and I'd like to replace them by a button that open a dropdown list of actions. However I don't really know how to handle the events from the dropdown items. I manage to do it using a javascript function but it's not very practical because I can only pass primitive values.
I also want to make it as a custom cell in the future to use it in different pages in my project so returning some html isn't very practical.
Here's my code :
final ButtonCell buttonInfoCell = new ButtonCell();
Column<GwtStockProduct, String> buttonCell = new Column<GwtStockProduct, String>(buttonInfoCell) {
#Override
public void render(final Context context, final GwtStockProduct value, final SafeHtmlBuilder sb) {
Div div = new Div();
Div bG = new Div();
div.add(bG);
bG.addStyleName("btn-group");
Button button = new Button();
DropDownMenu dropDown = new DropDownMenu();
Span span = new Span();
span.addStyleName("caret");
span.setVisible(false);
button.add(span);
button.getElement().setAttribute("style", "background-image: none !important; background-color: #234C78 !important;");
// button.removeStyleName("");
button.addStyleName("btn-hide-icon btn-blue");
button.setDataToggle(Toggle.DROPDOWN);
button.setText("Change stock");
for (int i = 1; i < 5; ++i) {
AnchorListItem item = new AnchorListItem();
item.getElement().getFirstChildElement().removeAttribute("href");
item.getElement().getFirstChildElement().setAttribute("onclick", "triggerClick('" + i + "')");
item.setText("Item " + i);
dropDown.add(item);
}
// dropDown.getElement().setAttribute("style", "position: relative !important;");
bG.add(button);
bG.add(dropDown);
// sb.append(SafeHtmlUtils.fromTrustedString(buttonGroup));
sb.appendHtmlConstant(div.getElement().getInnerHTML());
}
#Override
public String getValue(final GwtStockProduct object) {
// TODO Auto-generated method stub
return null;
}
};
stockTable.addColumn(buttonCell, "Actions");
stockTable.setColumnWidth(buttonCell, 5, Unit.PCT);
I use SelectionCell to render a drop-down list of options. Maybe that will help you:
ArrayList<String> options = new ArrayList<String>();
options.add("choose an option..."); // the prompt text
options.add("option 1");
options.add("option 2");
// ...
final SelectionCell optionsCell = new SelectionCell(options);
Column<TableType, String> optionsColumn = new Column<TableType, String>(optionsCell) {
#Override
public String getValue(TableType object) {
return null;
}
};
optionsColumn.setFieldUpdater(new FieldUpdater<TableType, String>() {
#Override
public void update(int index, TableType object, String value) {
if(value == "option 1")
// process option 1
else if(value == "option 2")
// process option 2
// ...
// reset drop-down to show the prompt text
optionsCell.clearViewData(object);
redrawRow(index);
}
});
table.addColumn(optionsColumn, "options");
The first option is just a prompt text and after each selection change the drop-down list is reset to show the prompt.
The disadvantage is that you can not have different sets of options for different rows as the list is generated once for the whole column.

Tree View JavaFX Memory out of Space

I have created javaFX tree with custom Objects (SystemNode).
Tree Items has graphics: check-box and image icon which I have set through updateItems() method.
Whenever I expand or collapse Item in tree ,twice or thrice I get JAVA HEAP MEMORY OUT OF SPACE and whole UI hangs UP.
PS: updateItems() method is invoked every time I expand or collapse tree node
I have tried adding event handlers but they didn't work.
Can anyone give some solutions.
Here is how I set cellFactory :
treeView_technicalAreas.setCellFactory(Util.getTreeCellFactory());
Here is code for cell factory:
public static Callback<TreeView<SystemNode>, TreeCell<SystemNode>> getTreeCellFactory() {
Callback<TreeView<SystemNode>, TreeCell<SystemNode>> callback = new Callback<TreeView<SystemNode>, TreeCell<SystemNode>>() {
#Override
public TreeCell<SystemNode> call(TreeView<SystemNode> p) {
TreeCell<SystemNode> cell = new TreeCell<SystemNode>() {
#Override
protected void updateItem(SystemNode t, boolean isEmpty) {
super.updateItem(t, isEmpty); //To change body of generated methods, choose Tools | Templates.
if (!isEmpty) {
System.out.println("util call back : " + t.getSystem().getName());
setText(t.getSystem().getName());
HBox hBox = new HBox();
CheckBox checkBox = new CheckBox();
checkBox.setSelected(t.getSelected());
checkBox.selectedProperty().bindBidirectional(t.getSelectedProperty());
hBox.setSpacing(SPACING_BETWEEN_ICON_AND_CHECKBOX);
ImageView imageView_icon = null;
if (t.getSystem().getType() == TYPE.BAREA) {
imageView_icon = new ImageView(Constant.Image_AREAS);
} else if (t.getSystem().getType() == TYPE.AREA) {
imageView_icon = new ImageView(Constant.Image_AREAS);
} else if (t.getSystem().getType() == TYPE.DOCUMENT) {
imageView_icon = new ImageView(Constant.Image_DOCUMENTS);
} else if (t.getSystem().getType() == TYPE.NOUN_NAME) {
imageView_icon = new ImageView(Constant.Image_NOUN_NAME);
} else if (t.getSystem().getType() == TYPE.CHANGE) {
imageView_icon = new ImageView(Constant.Image_DCC);
} else if (t.getSystem().getType() == TYPE.TASK) {
imageView_icon = new ImageView(Constant.Image_TASK);
}
hBox.getChildren().addAll(checkBox, imageView_icon);
setGraphic(hBox);
}
}
};
return cell;
}
};
return callback;
}

Categories