JTree refreshing after setting new jtree model - java

I'm trying to use dynamically JTree component.
Under root node I have four nodes and one of them ("Operations") can have 0 to many children. This is set by user via editable list in separate window opened on users request. After editing this list user hits button 'Save' and then magic should happen. Edited list is sent to server(on the same machine actually, so it doesn't take to long), the window with list is closed but right before that the main window (with jtree) is told to refresh itself, and I can see that it does what is told in log output, but the changes don't show on the screen.
I am using DefaultTreeModel, this method is called to create model at the beginning(when first opening the window) and after the change to update the new model with new structure.
with dmtn.getLeafCount() I can see that newly downloaded structure from server is the right one with the changed number of leaves under 'Operations'
public DefaultTreeModel getDataStructure() {
int dataID = task.getData().getId();
LoggerUtility.logger.info("Data ID: " + dataID);
DefaultMutableTreeNode dmtn = Manager.manager.getDataStructure(task.getId());
LoggerUtility.logger.info("DTMN created "+dmtn.getLeafCount());
return new DefaultTreeModel(dmtn);
}
the method used to refresh the jtree looks like this (it's very messy):
public void updateTree(){
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel)taskDataTree.getModel()).reload();
this.revalidate();
this.repaint();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
}
It's very messy because I have tried to put in there every possible solution to my problem that I have found on forums,
I also tried with my own treemodel implementation which would call fireTreeStructureChanged(...) but it also didn't change.
I should probably also add that I'm using Netbeans GUI Builder to build my gui although I don't know if it has anything to do with that.
I would be very grateful for any help with that
BR
Lucja
EDIT!!!
I also tried puting it in another thread like that:
public void updateTree() {
SwingWorker sw = new SwingWorker() {
#Override
protected Object doInBackground() throws Exception {
taskDataTree.setModel(getDataStructure());
((DefaultTreeModel) taskDataTree.getModel()).reload();
taskDataTree.revalidate();
taskDataTree.repaint();
taskDataTree.updateUI();
taskDataTree.setVisible(false);
taskDataTree.setVisible(true);
jScrollPane2.setViewportView(taskDataTree);
return null;
}
};
sw.execute();
}
but it also didn't help.

tree.setModel( anotherModel );
Is the only line of code that you need.
If it doesn't work then it means that the tree variable does not contain a reference to the tree that was added to the GUI. Maybe you have a class variable and a local variable of the same name.

From my point of view the own TreeModel implementation was a good approach. But I know that creating an TreeModelEvent with the correct data isn't that simple.
I would suggest to update your question with your TreeModel implementation so that we can find the problem with it.

In principle it should work this way (when you set a new Model, the tree reloads itself). (This is not the most efficient way, better let the model send appropriate events when it changes.)
If this does not work, make sure you are calling the setModel method in the AWT Event Dispatch Thread (with EventQueue.invokeLater (or SwingUtilities.invokeLater, which is the same), for example. I think you should not need all your revalidate(), repaint() etc. calls (and updateUI should only be done if you changed the look-and-feel configuration).

Related

How do I find the root component of a given component in zk?

In my viewmodel I have the following code:
#Command
public void onFinish(#BindingParam(value = "myButton") Button myButton) {
Component root = myButton.getParent().getParent().getParent();
...
}
Is there a more elegant way to find the root component of any given component? The expression above has to be altered every time I change the zul.
P.S. I am new to zkoss..:)
It all depends on what the root of your component is.
Your root is normally an IdSpace, and if you didn't have set other IdSpace element's you could use :
#Command
public void onFinish(#ContextParam(ContextType.SPACE_OWNER) IdSpace spaceOwner) {
...
}
This way, you never have to pass anything in the zul.
It will automaticly fetch that component.
Remember that IdSpace is an interface what is implemented in some specific components.
Please take a look of the other, maybe more suitable in your case, options you can do.
But there are also other tricks, this one uses CSS selectors :
#Command
public void onFinish(#SelectorParam(":root") Component root) {
...
}
Like this you will always have the root.
I'm not a great fan of sending components from the view to the viewmodel with bindingparams.
Reason is that today, you call this command from a button, but maybe you add the same command on other component and then this will fail.
Yes, you can use the Component class, but MVVM has so many ways to do it in a better way without polluting your view.
Remember that the whole point of MVVM is a separation between UI and code.
It may not matter what triggers a command, even as it doesn't matter what your collection will fill on the screen.
Assuming your root component has an id, you could do the following:
Component root = myButton.getPage().getFellow("id-of-root-component");

Why use JavaFX properties?

Pardon my question if it may seem stupid but I'm curious. I am making a program in Java of which will have a GUI, and am curious about the whole idea of properties. Why use them when we can just add data to a class? For example:
class myButton extends Button {
private boolean booleanProperty = false;
myButton(args...) {
// Do something with the property
}
public void setProperty(boolean value) {
this.booleanProperty = value;
}
public boolean getProperty() {
return this.booleanProperty;
}
}
Seems to work just fine for storing additional information on the custom implementation of the button. But what about:
class myButton extends Button {
private SimpleBooleanProperty booleanProperty = new SimpleBooleanProperty(false);
myButton(args...) {
// Do something with the property
}
public void setProperty(boolean value) {
this.booleanProperty.set(value);
}
public boolean getProperty() {
return this.booleanProperty.get();
}
}
The only real difference, I am seeing (correct me if I'm wrong) is that that you can attach listeners to the property values, but I feel as if there has to be more than just that. Ideas?
The power of JavaFX's properties is that they can be bound in ways that will automatically update the UI when a change occurs.
As an example consider an element you want to hide if a textField contains no value:
TextField tf = ...
Node container = ...
container.visibleProperty.bind(tf.textProperty.isNotEmpty());
Now as you change the text in tf, you will see container switching whether its visible based on the presence of text.
They really are useful in a lot of ways I even started them using in non UI related stuff. But look at this example: You habe an undomanager class
public class UndoManager {
BooleanProperty canUndo = ...;
BooleanProperty canRedo = ...;
...
}
And you have 3 places from where you can invoke undo/redo.
MenuButton menuUndo;
Button toolbarUndo;
MenuButton contextMenuUndo;
You basically only beed to do this:
menuUndo.disabledProperty().bind(undoManager.undoProperty()):
toolbarUndo.disabledProperty().bind(undoManager.undoProperty());
contextMenuUndo.disabledProperty().bind(undoManager.undoProperty());
and you dont ever have to worry about it again. If you add a new place where an undo can happen you just have to bind it too.
In this case you don't have a benefit, since you do not allow access to the property object itself. Usually this is done.
This allows you to add listeners to the property and be notified, when it changes.
Bindings are using this possibility to keep values the same and properties as well as the Bindings class provide methods for simple conversions of properties.
BooleanProperty booleanProperty = new SimpleBooleanProperty();
booleanProperty.addListener(new ChangeListener<Boolean>() {
#Override
public void changed(ObservableValue<? extends Boolean> observable, Boolean oldValue, Boolean newValue) {
System.out.println("property changed form "+oldValue +" to "+newValue);
}
});
booleanProperty.set(true);
booleanProperty.set(true);
booleanProperty.set(false);
booleanProperty.set(false);
booleanProperty.set(false);
booleanProperty.set(true);
booleanProperty.set(false);
booleanProperty.set(true);
booleanProperty.set(false);
Furthermore it allows you to pass an object representing the property. E.g. code that has to write/read booleanProperty does not need information about the myButton to write/read the property; you can just pass the property.
TableView is an example of a class that makes use of propertys. The columns used with TableView get a property from the items in the TableView and TableView registers a listener to that property. This allows it to change the values displayed in the cells even if the changes are triggered somewhere else in the code. Also for editable cells the properties of the items can be automatically modified.
The use of a javafx property for a pre-made object to hold an arbitrary value for later use. So you can set values to a text field or some other object that doesn't directly effect the shown value
Imagine programming a robot that would take care of resturant customers. How would it respond to customers or any other tasks that would have to be taken care of without using something like property listeners.
The benefit of using property listeners is that you can make your program become Concurrent. If there are no customers coming the next 1 hour your otherwise Sequentially made program would stand and do nothing for the next hour. Maybe switching the word Concurent with flexible in this example would be better, but you should look up Concurent programming and Sequence programming. Those properties allow you to customly make your program concurent.
You should also know that the gui you are using are already use built-in (event listening) features which build on the same principle.
Now what if you made that robot - instead of handing 1 customer at a time - respond depending upon what had to be done instead. Ask customers what the food tasted like (if customers have eaten), take new order(if called upon - by ANYBODY), take dishes(When any customer has paid and there is dish on a table), handle payment(When called upon by anybody). And ofcours handling a new customer arriving at the resturant.
The concurrently made program will handle any task needed by any customer. The sequencly made robot would only handle one customer at a time. Maybe it only then also has to be limited to greeting customers and placing them on seats to be anyhow useful. (You cannot have 1 robot for each customer).
Some people think it is easier to program sequencially can also be said. This is beacuse it can be difficult to keep track of subtasks that has to be done in a particular order. For instance that robot should not look for dishes when there haven´t arrived any customers. And what happens if it receives a payment call - while carrying dish? So it´s hard to prioritize and sort out the different tasks. However when succesfully doing it you program becomes so much more effective. It will be able to mutli task vs just solo-tasking.
And yes the sole purpose of properties is indeed that you can add listeners to them.

java customized JTree insertnodeinto

there is a lot of similar topics that I've seen here but couldn't really find solution to my little problem.
My application is searching through a file and showing the results inside a jtree. and I have a problem with that. When I add new nodes to a tree using insertNodeInto(...); i can search through found items while still searching but there is a problem with visualization. I mean there is a problem with rendering the nodes - I really can't explain that properly so I'm including this image.
When I use reload on jtree at the end of searching everything is back to normal - rendering is ok, unfortunately this closes all tabs that user opened.
I'm a student - sorry for my poor english. I hope someone know why this problem appears.
The way that your GUI is displayed, it certainly looks as if you are adding components to your Model outside of the painting thread (the Event Dispatch Thread (EDT)). This in turn will trigger painting outside of this thread, which will result in erratic painting.
Please take a look at this tutorial on threads in Swing
Looking at DefaultTreeModel, it is clear that the insertNodeInto(..) method will trigger the GUI updates, so if not done on the EDT, you are prone the painting issues depicted in your example.
A quick fix would be to add a method similar to the (uncompiled) code below:
public void safeInsertNodeInto(final MutableTreeNode newChild,
final MutableTreeNode parent, final int index) {
SwingUtilities.invokeLater(
new Runnable(){
public void run(){
model.insertNodeInto(newChild,parent,index);
}
}
);
}
then call that method instead of directly calling on you model.
That said, I heavily recommend reading the tutorial cited above. There are more advanced ways of dealing with the EDT constraints.

Java Swing Threading Problem

so here's the problem. I have a JDialog box that consists of 3 combo boxes, a text field, a few buttons and a JTable. The JTable information is filtered based on the text field and combo boxes, so for instance it starts with all of the data and gets shrunk down to only the data that starts with any string value the user decides.
What's happening though is that while the values filter correctly, if I click in the JTable (in the white space, where there are no rows) then the rows that were deleted show up, like they were invisible until I clicked on them. I've tried almost everything:
I've tried re-creating the table every time filter is clicked (bad hack that didn't even work), I've called all of the repaint, revalidate, firechanged methods, I rewrote the dialog from scratch to make sure I didn't do any stupid mistakes (if I made one I didn't find it at least), and I've tried putting them on separate threads. The only fix I haven't tried is using a swing worker, but that's because my filtering was a little too complicated for me to figure out what goes where and how to extend the swing worker correctly. The GUI is generated by netbeans (bleh), and has worked in my other dozen or so JDialogs just fine (perfectly in fact). Here's the method that doest the filtering, if any of you can help it would be greatly appreciated.
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {
nameFilter = "task1";
javax.swing.table.DefaultTableModel dm = (javax.swing.table.DefaultTableModel)jTable1.getModel();
tempParameters = parameters;
String currentString;
int rowNumber = 0;
while (dm.getRowCount()>rowNumber){
currentString = (String)(jTable1.getValueAt(rowNumber,1));
if(!nameFilter.equalsIgnoreCase(currentString.substring(0,nameFilter.length()))){
dm.removeRow(rowNumber);
parameters--;
}
else rowNumber++;
}
parameters = numOfRows;
}
Update, I also implemented the filter from the comment below, and while it filtered out the correct data, it had the exact same problem. In the future I will probably use this filter feature though, so thanks.
Another update, the code is still failing even after removing everything but this chunk, and all (at least I believe..) I am doing here is doing a simple remove row call. Hope this helps a bit.
Have you tried creating a new Model every time you want to filter, instead of clearing it by deleting rows? Create new model, copy relevant rows to new Model, set new Model in table. Really shouldn't be necessary, but it might be a quick fix.
Also, I really have to wonder why you're calling toLowerCase on two strings when you're using equalsIgnoreCase to compare them.
So long as this method is called from the EDT I don't think there would be a threading problem. Try using
SwingUtilties.isEventDispatchThread()
to make sure.
If you look at the API for DefaultTableModel, updates are being sent to your JTable which will repaint itself, so I don't think that is the problem.
I would guess that it is a logic problem. If you can extract the logic into separate methods it will be easier to test and verify whether it is updating the model as you expect.
Couple of observations:
If the filter happens to be larger than the string content of the row, it'll throw in the substring call
Calling the dm.removerow is generating a bunch of tablerowsdeleted events.
You're asking for a rowcount from the model, yet are getting the value through the table (a little inconsistent, if the model gets wrapped around another model you might be acting upon different rows), so instead of jtable1.getvalueat, use the dm.getvalueat.
I think what might be happening is that as the events get fired I see there are repaint and revalidate events fired in the JTable, these can be trampling over each other as they get enqueued in the EDT.
What I would suggest is to create a new datamodel, add the rows that you want to keep, and then reassign it to your jTable1.setModel(newDm);
Also to watch for is if someone else is modifying the model while you're in your eventlistener.
Hope this helps

Java- updating JTree

I've got a JTree which I'm using to display some (unsurprisingly) hierarchical data. Part of the spec is that the user can change the data source (atm it's just between files). Now, when this happens, I can rebuild the data and the tree nodes with no problem. But, I'm having substantial difficulties getting the tree to update the changes. I tried removing it from it's scrollpane and replacing with a new JTree, but I didn't see any such. I've tried removing all from the JTree and didn't see any effect.
How can I make the JTree display changes after it's been constructed?
Ninjedit: Yes, I did call updateUI().
Another edit:
I also wanted to replace the tree's current data with my new data. However, I don't see any methods that will take the DefaultMutableTreeNode that I constructed with. Even if I just remove the JTree and call updateUI on it's containing ScrollPane, nothing happens. Or if I use repaint instead.
It could be that the proper events (the JTree internal events) are not being fired. For example, you can add nodes either by using node.add(...) or even better, model.insertNodeInto(...) (assuming you're using the DefaultTreeModel). In this case, the latter method is preferred as it will fire appropriate events that will cause the view (the JTree) to update correctly. It's possible that your problem isn't with redrawing the UI, but in fact notifying the view that the model has changed.
So, I would suggest looking in to how you're dynamically modifying your JTree, and if possible I'd suggest using the DefaultTreeModel as your model to drive the view.
And just to make sure, you've read through the Sun JTree tutorials, right?

Categories