java customized JTree insertnodeinto - java

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.

Related

How to force repaint in Swing while debugging? [duplicate]

I cannot seem to force a layout in Swing. I have a JComponent added to a JLayeredPane and I set a border on the JComponent. Then, I want to immediately re-draw everything - not in the sense of "please do this asap" like invalidate(), but synchronously and immediately. Any help? I cannot seem to find the right method of doing this, and all my reading about invalidate(), validate(), repaint(), doLayout(), etc is just confusing me more!
According to this (see the section titled "Synchronous Painting") the paintImmediately() method should work.
The most reliable way to get Swing to update a display is to use SwingUtilities.invokeLater. In your case, it would look something like
SwingUtilities.invokeLater(new Runnable {
public void run() {
somecomponent.repaint();
}
});
I realize the 'invokelater' does not exactly sound like it does anything immediate, but in practice, events posted in this way tend execute pretty quickly compared to just calling e.g. somecomponent.repaint() directly. If you absolutely must make your control code wait for the GUI to update, then there is also invokeAndWait, but my experience is that this is rarely necessary.
See also: document on event dispatch in Swing.
This is super old, but I found a simple solution, which I'll show with a JPasswordField:
var pw = new JPasswordField();
...
pw.paint(pw.getGraphics()); // paints immediately

SWT: prevent Tree from expanding by doubleclick?

I have a problem with SWT Tree.
My situation is like this: I have a SWT Tree, which contains many TreeItems (Log entries), which contain TreeItems too. Those log entries have really long messages, which could not be shown in the TreeColumns at all. So my idea was: adding a Listener to the tree, which opens a new Dialog by DoubleClick, which shows the entries' details. So far so good.
If I do a double click on a item, it works. BUT: If I do a double click on a parent Item, it will expand (and thats good), but my double click Listener is active then as well and the Dialog will open.
That's not, what I want.
So, there are two solutions to the problem:
1) prevent the Tree from expanding/collapsing by double click automatically and implement the method by myself or
2) recognize, that the item was expanded and the event has to be aborted.
I do not really know how to do 1 or 2. Do u guys know that?
Thanks in advance.
Other answers did not work for me. This worked:
treeViewer.getControl().addListener(SWT.MeasureItem, new Listener(){
#Override
public void handleEvent(Event event) {
}});
I found this in a discussion in the Eclipse Community Forums: Disabling Treeviewer doubleclick expand/collapse.
When you look at this code you might be tempted to believe that it pretends to the tree control that your tree items have a size of zero, and as a result the tree control fails to detect that the double-click happened within the item, so it does not perform the double-click action. However, this is not what is actually happening. Instead, what this snippet does is that it leverages some weird code in the implementation of the tree control, which checks whether a listener has been added for SWT.MeasureItem, and if so, it deliberately avoids handling a double-click. This piece of code is even prefixed with a lengthy comment which a) fails to make sense and b) does not agree with what the code does. (Whatever.) So, bottom line is that by simply adding a handler for SWT.MeasureItem, and regardless of what the handler does, we are preventing the tree control from handling double-clicks. This is a prime example of Programming by Coincidence1.
1 The term "Programming by coincidence" was coined in the book The Pragmatic Programmer by Andy Hunt and Dave Thomas. It refers to relying on luck and accidental successes rather than programming deliberately.
If you are using TreeViewer, you could make use of IOpenListener
treeViewer.addOpenListener(new IOpenListener() {
#Override
public void open(OpenEvent event) {
}
}
There is another solution which works much better.
The problem with the solution from 'sambi reddy' was, that the tree was prevented from expanding by doubleclick, but it was prevented from expanding by clickling on the left handside cross as well.
My solution (that works well), was easy: I added a TreeListener, which listens to expanding/collapsing the tree and removed the expanding/collpasing implementation from the MouseDoubleClick-Listener.
No JFace TreeViewer - it works fine.

SwingWorker locks GUI on (unsuccessful) JLabel Icon updating

Ok im really struggling with unlocking my GUI which is locked due to separate SwingWorker thread. Basically what my program does: Initializes webcam, and then grabs single frame and displays it as JLabel icon (doing single grab+display on Button click is ease, however i have immense difficulties in doing such operation consecutively in order to do some image processing). I am aiming to obtain such result:
Grab frame -> process it -> display as ImageIcon of Jlabel > ... repeat Grab frame >...
I need results while webcam is streaming, therefore i used SwingWorker publish and process. In my code "processing part" is not included as it is not necessary since i cant even obtain proper continuous frame grabbing. Generally my background thread will never finish unless cancelled (well thats the assumption as i want to process images as fast as possible with maximum frames per second - unless i should do it other way? - i guess separate thread for single frame grab&process would be bad idea due to fact that im aiming to get 10+ FPS). I know my SwingWorker thread works, since i made tests of saving consecutive images to C:\, and it did work, but my GUI is locked anyway, but at least i know that thread is running and grabbing frames.
Generally i have 2 problems:
no JLabel icon update
Locked GUI
My SwingWorker code:
private class FrameStream extends SwingWorker<Void, BufferedImage> {
#Override
protected Void doInBackground() throws InterruptedException{
BufferedImage processedImage = null;
while (!isCancelled()) {
processedImage = getPIC_COLOR(player);
publish(processedImage);
Thread.sleep(5000); // i made such delay to check whether program is not "choking" with data, but its not the case, without this delay everthing is the same
}
return null;
}
#Override
protected void process(List<BufferedImage> mystuff) {
Iterator it = mystuff.iterator();
while (it.hasNext()) {
img_field.setIcon(new ImageIcon(mystuff.get(mystuff.size()-1)));
}
}
#Override
protected void done() {
infoBAR.setText("FINISHED");
}
}
I am so desperate that i rewritten my code completely basing on tutorials example: Flipper as you can see it is ridiculously similar. All my previous efforts also locked gui so tried the 'tutorial way', nonetheless it did not work, which is a pity. Im in a dead end because i have no clue how to fix that. Im desperate for help since as you can see it seems exactly the same as the tutorial one, maybe something other causes issues: MY FULL CODE
Please help, i'm unable to solve it by myself.
One thing that looks a little different to me is your process method. Rather than specifying the last image, you might wish to iterate through all images like so:
#Override
protected void process(List<BufferedImage> mystuff) {
for (BufferedImage bImage : mystuff) {
img_field.setIcon(new ImageIcon(bImage));
}
}
I'm not sure if this will make a significant difference, but I believe that this is how process should be written. Another thought -- if the BufferedImages are large you may wish to create the ImageIcon in the background thread and publish the ImageIcon rather than the BufferedImage.
Nothing stands out as an issue. Steps I would suggest to further debug.
Instead of using a loop and the process method, just pull one frame and set the Icon once. You need to get that working before you try to make it loop. Your application should be able to set the icon that fact that it doesn't highlights a problem.
Second, because your GUI is locking up, there is something still happening on the EDT. Try, running a profiler or adding System.out.println in your code to find what is running while the GUI is locked.
Last, make sure you don't need to be repainting, revalidating the Label's container to make the image visible.
hmmmm, if I read your last post about this issue, there are maybe lots of possible mistakes (and I see your code), that's nothing to do with SwingWorker, another example just replace change Color for JButton#setBackground() with your Icon or ImageIcon
Have you tried to set the label to observe the image icon?
icon.setImageObserver(label);

JTree refreshing after setting new jtree model

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).

How are Swing components internally created, laid out, repainted, notified of events, ...?

I wonder if there's a good documentation (or a (viewable) ebook) about
the lifecycle of Swing components.
Is "lifecycle" the correct term, anyway?
I hope to find answers to question such as:
How, when, in which order painting methods are called?
How, when, which events are called by whom?
What is the exact sequence of method calls for component creation?
From time to time I encounter strange behavior of my apps, for example:
ComponentListener's resize event is called before setVisible(true)
(so that root pane has negative dimensions!)
Some components are laid out correctly only after resizing the JFrame by hand
Changing a super class from JPanel to JLayeredPane causes my class
to be laid out differently inside an other container.
And lot of other strange things...
I had the same question long ago.
I can't believe how hard is to find a good resource about this topic in the internet.
Fortunately I've found this link and now I have it in my bookmark with golden tag. :)
A Swing Architecture Overview
Once you have a good grasp of how they work conceptually you will be able to fix most of the problems you mention.
I hope it helps.

Categories