Select JTree node from JComboBox and vice versa - java

I have JTree and JComboBox in my application. When I select a node, JComboBox content also changes, but I need to do same thing in case of selecting JComboBox item.
As you see, if I select "Default Session Start" , the same node should be selected in the JTree. Could someone tell me, what will be a good approach for it. enter image description here

This is just a part of a skeleton of an application. Swing is rather verbose, and much you'll need to work out. You provide data models for the JComponents, and need to add listeners, or
JComboBox<Thing> comboBox = new JComboBox<>(controller.getComboBoxModel());
JTree tree = new JComboBox<>();
... tree.setSelectionModel(controller.getTreeSelectionModel());
publi class Controller { // or Application
public static void main(String[] args) { ... }
// Model:
private ComboBoxModel<Thing> comboBoxModel;
private TreeSelectionModel treeSelectionModel;
public Controller() {
comboBoxModel = new DefaultComboBoxModel() {
#Override
pubic void setSelectedItem​(Thing item) {
if (!item.equals(getSelectedItem())) {
super.setSelectedItem(itenm);
treeSelectionModel.setSelectionPath(...);
}
}
};
treeSelectionModel = new DefaultTreeSelectionModel ...
...
}
Important is that there is no back-and-forth setting the selected item, for an unchanged item. Hence the equality test.

Related

Javafx - Hide TreeTableRow based on data content

I created a TableTree that contains object of class Component that has a boolean property "selected".
I want to hide the rows from the table where the rows component is not selected.
I tried this:
componentTree.setRowFactory(new Callback<TreeTableView<Component>, TreeTableRow<Component>>() {
#Override
public TreeTableRow<Component> call(TreeTableView<Component> param) {
TreeTableRow<Component> row = new TreeTableRow<Component>() {
#Override
protected void updateItem(Component component, boolean empty) {
if(!empty) {
if (!component.isSelected()) {
setVisible(false);
setManaged(false);
System.out.println("hide");
} else {
setVisible(true);
setManaged(true);
System.out.println("show");
}
}
}
};
return row;
}
});
On system.out I can see a lot of "show" and "hide" messages, but this doesn't affect the table, all rows are shown as before.
Any idea on this topic?
Thanks!
I used eclipse's fx.ui.controls library for the same achieve the same goal before.
<dependency>
<groupId>at.bestsolution.eclipse</groupId>
<artifactId>org.eclipse.fx.ui.controls</artifactId>
<version>2.2.0</version>
</dependency>
The library provides a class: FilterableTreeItem<T> under the tree package. This class was designed to be used in cases like yours. You can provide a Predicate to the root of the tree and the items will get hidden when the value given changes:
// Children
final FilterableTreeItem<Component> childNode1 = new FilterableTreeItem<>(component1);
final FilterableTreeItem<Component> childNode2 = new FilterableTreeItem<>(component2);
final FilterableTreeItem<Component> childNode3 = new FilterableTreeItem<>(component3);
// Root
final FilterableTreeItem<Component> root = new FilterableTreeItem<>(rootComponent);
root.getInternalChildren().setAll(childNode1, childNode2, childNode3);
root.setPredicate((parent, value) -> value.isSelected());
// TreeTableView
final TreeTableView<Component> treeTableView = new TreeTableView<>(root);
Note that you have to use getInternalChildren() to add children and the default getChildren().
FilterableTreeItem<T> also provides a predicateProperty() that you can bind to another property in case you need to update the how items are shown or hidden.
Another advatage of this class is that it shows the whole path up to the root of the items matching that predicate.

JComboBox to display multiple lines of text

I'm currently writing a small tool for sending sql queries to a database and recieving the according data.
Now to my problem:
I want to allow the user to enter a new search query or select from a "latest" list, where the last few queries are saved.
For that, I planned on using an editable JComboBox, but I'm having trouble diplaying multiple lines of text in the box itself.
The reason I want to do that, is because sql queries can get quite long and since I want make the box editable and at the same time keep the frame clean.
I've found ways to display multiple lines in the dropdown menu, but nothing for the box itself.
Thank you in advance and please forgive me if I overlooked something simple ;)
Greetings
Zeus
Extended editing functionality is supplied by the ComboBoxEditor, this allows you to define the actual component which is used as the combobox's editor
Based on your requirements, you're going to need (at the very least) a JTextArea, to provide (optionally) word wrapping and multiple lines
A rough and ready example might look something like this...
public class TextAreaComboBoxEditor implements ComboBoxEditor {
private JTextArea ta = new JTextArea(4, 20);
private JScrollPane sp = new JScrollPane(ta);
public TextAreaComboBoxEditor() {
ta.setWrapStyleWord(true);
ta.setLineWrap(true);
}
#Override
public Component getEditorComponent() {
return sp;
}
#Override
public void setItem(Object anObject) {
if (anObject instanceof String) {
ta.setText((String) anObject);
} else {
ta.setText(null);
}
}
#Override
public Object getItem() {
return ta.getText();
}
#Override
public void selectAll() {
ta.selectAll();
}
#Override
public void addActionListener(ActionListener l) {
}
#Override
public void removeActionListener(ActionListener l) {
}
}
This doesn't support ActionListener, as JTextArea uses the Enter key for it's own purposes. If you wanted to, you could use the key bindings API to add your own Action that can trigger the ActionListeners, for that, you'd need to supply a List or other means for managing them so you can call them back

Cannot link text field to RowItem from SQLContainer with Vaadin

I'm building a simple CRUD application with a MySql database as back end. So far I managed to link a grid to the contents of a SQLContainer with the FreeformQuery (so the read is fine).
String query = "select a.id, a.name name, b.name type from asset a join " +
" assettype b on a.assettype_id = b.id";
grid.setContainerDataSource(container);
For the container the SQLContainer. I created a form and I did the binding between its contents and a selected row
grid.addSelectionListener(event -> {
if (event.getSelected().isEmpty()) {
form.setVisible(false);
} else {
Item item = container.getItem(event.getSelected().iterator().next());
form.setAsset(item);
}
});
So, as you see, the form is linked to an Item. setAsset is simply a form method that links the row contents to the text fields of the form.
public void setAsset(Item item) {
this.item = item;
FieldGroup binder = new FieldGroup(this.item);
binder.bind(textField1, "name");
binder.bind(textField2, "type");
setVisible(true);
}
Well, I don't know anymore how to add a row, or how to edit an existing one. For editing a row I tried with a save method for the form (that I call with a button) as follows
private void save() throws UnsupportedOperationException, SQLException {
SQLContainer container = db.getContainer();
container.addItem(item);
container.commit();
}
Well, problem one is that, if I select a grid item, I see the contents of name and type in the text fields but, if I modify their values in the text field before entering the save method, this.item still has the original values (when I thought it would take the new value in the text field because the textfields are bound to the RowItem). Does anybody know what's going on?
In addition, if I want to create a new row, I would like to have something like this
Button createAsset = new Button("Add asset");
createAsset.addClickListener(e ->
{
grid.select(null);
form.setAsset(new Item());
});
and fill the contents of the blank Item() in the form, before pushing it to the table. Of course I can't because Item and RowItem are interfaces. So how can I instantiate an empty row of a container before filling its contents?
Thanks very much in advance.
In the end, I would say that either I din't use the FieldGroup.bind method properly, or that there is a bug in it. This is my original entry
public void setAsset(Item item) {
this.item = item;
FieldGroup binder = new FieldGroup(this.item);
binder.bind(textField1, "name");
binder.bind(textField2, "type");
setVisible(true);
}
which did not work, and this is what works (which to me, is the same)
public void setAsset(Item item) {
this.item = item;
textField1.setPropertyDataSource(item.getItemProperty("name"));
textField2.setPropertyDataSource(item.getItemProperty("type"));
setVisible(true);
}

Updating JList by pressing button

first of all I will introduce what I am trying to do. This is an assignment in university we are making Hotel booking system with JAVA. To go straight to the point, all I need to know is how to update JList when I press button.
listModel = new DefaultListModel<Hotel>();
bookingList = new JList(listModel);
class MouseAdapterMod extends MouseAdapter {
public void mousePressed(MouseEvent e) {
if(e.getSource() == searchButton){
for(lists.getRoomsList() p : lists.getRoomsList())
{
listModel.addElement(p);
}
bookingList.setModel(listModel);
}
In this GUI class I have instance variable (lists) of Hotel class, in Hotel class there are methods
public ArrayList<Rooms> getRoomsList()
{
return roomsList.getListRooms();
}
public ArrayList<Suite> getSuitesList()
{
return roomsList.getListSuites();
}
this returns whole ArrayList of Room class objects and also ArrayList of Suite class.
QUESTION would be is how to show whole ArrayList of Rooms when I press button, in other words how to update JList which consists of objects, by pressing button?
I hope I explained alright.
Your for-each loop is wrong. Try this and see:
public void mousePressed(MouseEvent e) {
if(e.getSource().equals(searchButton)){
ArrayList<Rooms> rooms = lists.getRoomsList();
for(Rooms r : rooms) {
listModel.addElement(r);
}
bookingList.setModel(listModel);
}
}
This still looks sorta messy to me though. A more appropriate approach would be to set an event handler on the searchButton, to populate the JList when searchButton is clicked.
Also, are Rooms and Suites sub classes of Hotel? If not, you'll have to create listModel like this (for rooms):
listModel = new DefaultListModel<Rooms>();

How to do a JList MVC style?

I've been trying to implement a simple JList using MVC. Basicaly, show the JList and under it add a button to delete an item. I want to use AbstractListModel for the model because later on I want more than just a simple ArrayList as data.
I'm having trouble using the JList in a proper MVC way. For example in the View I create the list. But this list need the model (addModel(method), and is added in the View.
It seems weird because I thought in MVC the View had no knowledge of the model.
I also don't really know what I should put in the controller.
Anyway if someone could give me guidelines to implement this it would be nice.
Here's the code I started:
public class SimpleJlist extends JFrame
{
public static void main(String[] args)
{
Controller controller = new Controller();
View view = new View(controller);
Model model = new Model();
SimpleJlist jl = new SimpleJlist();
jl.setLayout(new FlowLayout());
jl.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jl.add(view);
jl.setVisible(true);
jl.pack();
}
}
public class View extends JPanel implements ListDataListener, ActionListener
{
Controller controller;
JButton button;
JList list;
public View(Controller controller)
{
this.controller = controller;
button = new JButton("Delete");
/* Creation of the Jlist, but need the model. */
}
/* For the button */
public void actionPerformed(ActionEvent event) { }
/* For the list */
public void contentsChanged(ListDataEvent event) { }
public void intervalAdded(ListDataEvent event) { }
public void intervalRemoved(ListDataEvent event) { }
}
public class Model extends AbstractListModel
{
private ArrayList<String> names;
public Model()
{
names = new ArrayList<String>();
/* add names... */
}
public void deleteElement(int index) { names.remove(index); }
public String getElementAt(int index) { return names.get(index); }
public int getSize() { return names.size(); }
}
The code is far from complete obviously, but this is about where I got to before wondering what to do next...
The controller is not there, because I'm simply not sure what to put in it.
I've been trying to implement a simple JList using MVC.
Swing components are already designed in an MVC like style. You just need to use the components. The LIstModel is the model and the JList is a combined view-controller. You don't create additional classes called Model-View-Controller.
Basicaly, show the JList and under it add a button to delete an item.
Read the section from the Swing tutorial on How to Use Lists for an example of how to add/remove items from the DefaultListModel
I want to use AbstractListModel for the model because later on I want more than just a simple ArrayList as data.
That's fine, all you are doing is replacing the model. You don't need to make any changes to the JList when you do this, assuming that your model invokes the proper fireXXX() methods when the data is changed.
You should also check out the section from the Swing tutorial on How to Use Models which shows how you might use the MVC approach for your own custom component.

Categories