I have some ObjectProperty in my class and I don't know how can I bind it to Node's children.
My code:
public class Base extends Parent {
private ObjectProperty<Panel> panel;
private final HBox foundation;
public Base() {
panel = new SimpleObjectProperty<>();
foundation = new HBox(20);
// ???
getChildren().add(foundation);
}
//------Properties below
public final ObjectProperty<Panel> panelProperty() {
return panel;
}
public final void setPanel(Panel value) {
panelProperty().setValue(value);
}
public final Panel getPanel() {
return panelProperty().getValue();
}
}
I want to have an automatic system working like that:
Setting panel property value -> adding the value (node) to foundation's children
EDIT:
I'm talking about adding the node via FXML, like that;
<?xml version="1.0" encoding="UTF-8"?>
<Base xmlns:fx="gui">
<panel>
<Panel/>
</panel>
</Base>
Assuming you just want foundation to contain a single element, which is the current value of panel, just add a listener to panel:
public Base() {
panel = new SimpleObjectProperty<>();
foundation = new HBox(20);
panel.addListener((obs, oldPanel, newPanel) -> {
if (newPanel == null) {
foundation.getChildren().clear();
} else {
// Assumes Panel is a subclass of Node:
foundation.getChildren().setAll(newPanel);
}
});
getChildren().add(foundation);
}
Note that there's no real reason to expose an observable property for panel here, unless you have some other pressing need to actually observe it and respond to changes externally to the class (which seems unlikely). You could simplify the whole thing to:
public class Base extends Parent {
private final HBox foundation;
public Base() {
foundation = new HBox(20);
getChildren().add(foundation);
}
public final void setPanel(Panel value) {
if (value == null) {
foundation.getChildren().clear();
} else {
foundation.getChildren().setAll(value);
}
}
public final Panel getPanel() {
if (foundation.getChildren().isEmpty()) {
return null ;
}
return (Panel) foundation.getChildren().get(0);
}
}
Related
I have a TreeView which is empty at the start and I want to set a placeholder until it is empty. Like the one available for ListView (setPlaceholder())
My first thought was to wrap the TreeView into a BorderPane and just change the center based on the number of elements in the TreeView. The problem is though that I add elements to the TreeView through drag and drop and if I set a label to the center for substituting a placeholder, I won't be able to drag n drop my items in the TreeView anymore. Any suggestions would be much appreciated.
TreeView has no placeholder support - not entirely certain, why not, but could be that an empty tree (whatever that means: null root? root without children? root not showing?) is a rare species.
It's rather simple to implement, though, by following the implementation for a virtualized control that supports it, f.i. TableView. All we need is a custom TreeViewSkin that
manages (creates and adds to the tree's hierarchy, layouts as needed) the placeholder
listens to relevant state of the tree and updates the placeholder's visibilty as appropriate
An example, toggling the emptyness by toggling the tree's root between null/not null via a button:
public class TreeViewWithPlaceholder extends Application {
private static class TreeViewPlaceholderSkin<T> extends TreeViewSkin<T> {
private StackPane placeholderRegion;
private Label placeholderLabel;
public TreeViewPlaceholderSkin(TreeView<T> control) {
super(control);
installPlaceholderSupport();
}
private void installPlaceholderSupport() {
registerChangeListener(getSkinnable().rootProperty(), e -> updatePlaceholderSupport());
updatePlaceholderSupport();
}
/**
* Updating placeholder/flow visibilty depending on whether or not the tree
* is considered empty.
*
* Basically copied from TableViewSkinBase.
*/
private void updatePlaceholderSupport() {
if (isTreeEmpty()) {
if (placeholderRegion == null) {
placeholderRegion = new StackPane();
placeholderRegion.getStyleClass().setAll("placeholder");
getChildren().add(placeholderRegion);
placeholderLabel = new Label("No treeItems");
placeholderRegion.getChildren().setAll(placeholderLabel);
}
}
getVirtualFlow().setVisible(!isTreeEmpty());
if (placeholderRegion != null)
placeholderRegion.setVisible(isTreeEmpty());
}
#Override
protected void layoutChildren(double x, double y, double w, double h) {
super.layoutChildren(x, y, w, h);
if (placeholderRegion != null && placeholderRegion.isVisible()) {
placeholderRegion.resizeRelocate(x, y, w, h);
}
}
private boolean isTreeEmpty() {
return getSkinnable().getRoot() == null;
}
}
private Parent createContent() {
TreeView<String> tree = new TreeView<>() {
#Override
protected Skin<?> createDefaultSkin() {
return new TreeViewPlaceholderSkin<>(this);
}
};
Button toggle = new Button("toggleRoot");
toggle.setOnAction(e -> {
TreeItem<String> root = tree.getRoot();
tree.setRoot(root == null ? new TreeItem<>("root") : null);
});
BorderPane content = new BorderPane(tree);
content.setBottom(toggle);
return content;
}
#Override
public void start(Stage stage) throws Exception {
stage.setScene(new Scene(createContent()));
//stage.setTitle(FXUtils.version());
stage.show();
}
public static void main(String[] args) {
launch(args);
}
#SuppressWarnings("unused")
private static final Logger LOG = Logger
.getLogger(TreeViewWithPlaceholder.class.getName());
}
I am working on a project. In this project, I must have a shop that has a huge list of cards. I am also very new to JavaFX.
I made a custom class that inherits pane. It has an image view and some labels to show the name and description of card.
Know my problem is that how should I add them to scene to have an scrollable list of this items? What Components should my Scene have. (I omitted imports in the code below)
CardView.java ---- Custom component that loads an fxml
public class CardView extends Pane {
CardController cardController;
Node view;
public CardView() {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("../FXMLFiles/Card.fxml"));
fxmlLoader.setControllerFactory(new Callback<Class<?>, Object>() {
#Override
public Object call(Class<?> param) {
return cardController = new CardController();
}
});
try {
view = (Node) fxmlLoader.load();
} catch (IOException ex) {
}
getChildren().add(view);
cardController.setNameAndDsc("Card", "This is A card", heroImg);
}
}
CardController.java
public class CardController {
#FXML
private Label name_lbl;
#FXML
private Label dsc_lbl;
#FXML
private ImageView card_img;
public void setNameAndDsc(String name, String dsc, Image img) {
name_lbl.setText(name);
dsc_lbl.setText(dsc);
card_img.setImage(img);
}
public void setName_lbl(Label name_lbl) {
this.name_lbl = name_lbl;
}
public void setDsc_lbl(Label dsc_lbl) {
this.dsc_lbl = dsc_lbl;
}
public void setCard_img(ImageView card_img) {
this.card_img = card_img;
}
}
Card.fxml
Overall View of Card.fxml:
Actually I want to have a huge list of this card that can be scrolled. How should I do that? What Components should I use. I must also note that I have access to JFoenix.
Use a listview. It's a virtual control so it only creates nodes that are in the visual bounds.
You can apply css to make background transparent.
Im facing overlaps problem with my project when trying to resize browser.
I was trying so many different variations to make it work, but still result is not acceptable.
Before resizing:
A, B and C are contained in VerticalLayout - I will call it root.
Root is inside HorizontalLayout - content of UI.
A is simple component.
B is extending VerticalLayout that contains 2 HorizontalLayouts inside.
C is only one component - Grid.
Now, when Im trying to resize my browser (like arrow shows) C is starting to steal other components place.
After resizing:
The effect I would like to achieve is that my Grid (C) is not trying to fit my browser. It should not move, and just hide - like below (green is showing actually visible part):
/*ROOT class that extends VerticalLayout*/
private void init()
{
super.setSizeFull();
addA();
addB();
addC();
}
private void addA()
{
Label header = new Label();
super.addComponent(header);
super.setComponentAlignment(header, Alignment.MIDDLE_CENTER);
}
private void addB()
{
layoutB.setSizeFull();
layoutB.setWidth("92%");
super.addComponentsAndExpand(layoutB);
super.setExpandRatio(layoutB, 0.3f);
super.setComponentAlignment(layoutB, Alignment.MIDDLE_CENTER);
}
private void addC()
{
grid.setSizeFull();
grid.setColumnReorderingAllowed(true);
grid.setWidth("92%");
super.addComponentsAndExpand(grid);
super.setExpandRatio(grid, 0.6f);
super.setComponentAlignment(grid, Alignment.BOTTOM_CENTER);
}
As you can see C is added in the same way as B, but only C is moving. Thanks in advance for any help!
Im using Vaadin 8.
#Edit:
#SpringUI(path = "/ui")
public class MyUI extends UI {
#Override
protected void init(VaadinRequest request)
{
Workspace workspace = new Workspace();
HorizontalLayout root = new HorizontalLayout();
root.setSizeFull();
root.addComponentsAndExpand(workspace);
setContent(root);
}
public class Workspace extends Panel
{
public Workspace()
{
init();
}
private void init()
{
setSizeFull();
addStyleName(ValoTheme.PANEL_BORDERLESS);
VerticalLayout layout = new VerticalLayout();
// by default width 100% and height undefined in Vaadin 8
setContent(layout);
// component A
Label label = new Label("Test1");
layout.addComponent(label);
// component B
HorizontalLayout bar = new HorizontalLayout();
bar.addComponents(new Label("Label 1"), new Label("Label 2"));
layout.addComponent(bar);
// component C
Grid<MyBean> grid = new Grid<>(MyBean.class);
grid.setCaption("My Grid:");
grid.setHeight("1000px");
//grid.setHeightByRows(50); // same as fixed height
List<MyBean> items = new LinkedList<>();
IntStream.range(1, 100).forEach(i -> items.add(new MyBean("Item " + i)));
grid.setItems(items);
layout.addComponent(grid);
}
}
public static class MyBean {
private String name;
public MyBean(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}
Have a look at this working example:
#SpringUI(path = "/ui")
public class MyUI extends UI {
#Override
protected void init(VaadinRequest request) {
Panel panel = new Panel();
panel.addStyleName(ValoTheme.PANEL_BORDERLESS);
panel.setSizeFull();
VerticalLayout layout = new VerticalLayout();
// by default width 100% and height undefined in Vaadin 8
panel.setContent(layout);
// component A
Label label = new Label("Test1");
layout.addComponent(label);
// component B
HorizontalLayout bar = new HorizontalLayout();
bar.addComponents(new Label("Label 1"), new Label("Label 2"));
layout.addComponent(bar);
// component C
Grid<MyBean> grid = new Grid<>(MyBean.class);
grid.setCaption("My Grid:");
grid.setHeight("1000px");
//grid.setHeightByRows(50); // same as fixed height
List<MyBean> items = new LinkedList<>();
IntStream.range(1, 100).forEach(i -> items.add(new MyBean("Item " + i)));
grid.setItems(items);
layout.addComponent(grid);
setContent(panel);
}
public static class MyBean {
private String name;
public MyBean(String name) { this.name = name; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
}
The Grid has a fixed height (either by pixels or by number of rows). No expand ratios are necessary for the VerticalLayout. The layout within the Panel will grow as needed by its child components. If the height is greater than the space available for the Panel then scroll bars are shown.
My question is this: How can I set the value of a JTextArea from another class? This is the class that contains the JTextArea and extends JFrame:
public class JTreeFiles extends javax.swing.JFrame {
private javax.swing.JTextArea jTextArea1;
public JTreeFiles() {
initComponents();
}
public JTextArea setTextArea(){
return this.jTextArea1;
}
}
This where I am trying to set the value of the JTextArea:
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
TreePath tp = tree.getSelectionPath();
if (tp != null) {
Object filePathToAdd = tp.getLastPathComponent();
//System.out.println(filePathToAdd);
if (filePathToAdd instanceof FileTreeNode) {
FileTreeNode node = (FileTreeNode) filePathToAdd;
File file = node.getFile();
if (file.isFile() && file.getName().endsWith(".java")) {
JTreeFiles jf = new JTreeFiles();
jf.setTextArea().setText("Text Here"); //Nothing happen here
}
}
}
}
}
But nothing happens, the text not displayed in the JTextArea. What am I doing wrong?
It looks like you never init the jTextArea1 (from what I can see). You also don't use jTextArea1 anywhere in the listener. You might want to add these and test it.
You have not changed anything in this method
public JTextArea setTextArea(){
return this.jTextArea1;
}
This method needs to include something like
jTextArea1.setText("sometext");
EDIT
For example
public class JTreeFiles extends JFrame {
private JTextArea jTextArea1;
public void setText(String text){
jTextArea1.setText(text);
}
}
Then you would put this in the listener
tree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent e) {
// All of your other IF statements
JTreeFiles jf = new JTreeFiles();
jf.setText("Text Here");
jf.repaint();
}
}
Try to redraw the textArea after updating it:
jf.getTextArea().update(jf.getTextArea().getGraphics());
BTW, according to the beans' code conventions, the JTreeFiles method should be getTextArea instead of setTextArea.
My use case is that a List<String> is passed to a Jpanel and for each String in the List, the JPanel renders a UI component. This UI component consists of 3 buttons and my current code for my given use case is as follows. -- The code for the 'UI component' follows --
public class MacroEditorEntity implements ActionListener {
private String macro;
private JButton upButton;
private JButton downButton;
private JButton MacroDetailsButton;
public MacroEditorEntity(String macro) {
this.macro = macro;
upButton = new JButton("Up");
downButton = new JButton("Down");
MacroDetailsButton = new JButton(macro);
upButton.addActionListener(this);
downButton.addActionListener(this);
MacroDetailsButton.addActionListener(this);
}
#Override
public void actionPerformed(ActionEvent evt) {
if(evt.getSource().equals(MacroDetailsButton))
{
System.out.println(macro);
}
}
public JButton GetUpButton()
{
return upButton;
}
public JButton GetDownButton()
{
return downButton;
}
public JButton getMacroDetailsButton()
{
return MacroDetailsButton;
}
}
The code for my Panel is as follows --
public class MacroEditor extends JPanel implements PropertyChangeListener {
private static final long serialVersionUID = 1L;
private List<String> stringlist;
public MacroEditor(List<String> list) {
this.stringlist = list;
setupComponents();
validate();
setVisible(true);
}
public void setupComponents()
{
Box allButtons = Box.createVerticalBox();
for(String string : stringlist)
{
MacroEditorEntity entry = new MacroEditorEntity(string);
Box entryBox = Box.createHorizontalBox();
entryBox.add(entry.GetUpButton());
entryBox.add(Box.createHorizontalStrut(15));
entryBox.add(entry.getMacroDetailsButton());
entryBox.add(Box.createHorizontalStrut(15));
entryBox.add(entry.GetDownButton());
allButtons.add(entryBox);
}
add(allButtons);
}
#Override
public void propertyChange(PropertyChangeEvent arg0) {
revalidate();
repaint();
}
}
The code works fine for all Strings in the passed List. I want my Panel to pick up any change that may happen to the List like additions or deletions and add/remove relevant corresponding UI components accordingly. I think this can be done by using PropertyChangeListener but have not been able to account for that in my code.
Any ideas or suggestions on how i can make my Panel render/rerender stuff as soon as there are changes to the List would be of help.
What you need here is an observable collection. This should do it: http://commons.apache.org/dormant/events/apidocs/org/apache/commons/events/observable/ObservableCollection.html
Edit:
Here's the code snippet you requested:
public class ObservableListExample implements StandardPostModificationListener,
StandardPreModificationListener {
public static void main(String[] args) {
new ObservableListExample();
}
public ObservableListExample() {
ObservableList list = ObservableList.decorate(new ArrayList<>(),
new StandardModificationHandler());
list.getHandler().addPostModificationListener(this);
list.getHandler().addPreModificationListener(this);
//....
}
#Override
public void modificationOccurring(StandardPreModificationEvent event) {
// before modification
Collection changeCollection = event.getChangeCollection();
if (event.isTypeAdd()) {
// changeCollection contains added elements
} else if (event.isTypeReduce()) {
// changeCollection contains removed elements
}
}
#Override
public void modificationOccurred(StandardPostModificationEvent event) {
// after modification
Collection changeCollection = event.getChangeCollection();
if (event.isTypeAdd()) {
// changeCollection contains added elements
} else if (event.isTypeReduce()) {
// changeCollection contains removed elements
}
}
}
By the way: Another concept that helps to bind buisness objects to your GUI and react to modifications (bidirectionally) is Data Binding. Have a look at this, a Data Binding Library commonly used with Swing.