JTree enlarges width when a node gets expanded - java

I've got a real hard problem with a JTree.
I've implemented a JTree with a selfwritten Model (wich is extended from TreeModel).
fileSystemModel = new MyModel(new File(directory));
fileTree = new JTree(fileSystemModel);
fileTree.setEditable(true);
fileTree.setDragEnabled(true);
fileTree.addTreeSelectionListener(new TreeSelectionListener() {
public void valueChanged(TreeSelectionEvent event) {
File file = (File) fileTree.getLastSelectedPathComponent();
}
});
So i added it to a JPanel and this JPanel to a JFrame.
No i got this Problem: I start the Frame, and if i expand a single Node, the width of JTree is going to enlarge to the width which is needed to show the leafs.
I tried to set this:
fileTree.setMaximumSize(width, height);
But it failed and i also tried to embedd the JTree into JScrollPanel with a Maximum-Size, and this has also failed.
The JTree is still adjusting its width how many it needs.
So i tried now for two days and doesn't find anything, so i would be apprecciate if someone of you could help me.
Thanks!

The effect described is characteristic of the default FlowLayout of JPanel. You can see the change when you click on the left panel is this example.
Addendum: As seen in the example, GridLayout allows the component to expand; it works particularly well with setVisibleRowCount() followed by pack().

Related

How can SWT layout resize (grow/shrink) based on content

I have an explorer in my RCP application to which I added an inner composite with a RowLayout to show various category items. When the width of the explorer is resized I want the category items to wrap to new rows and expand the size of their parent composite.
If I initialize my inner composite with defaults, nothing happens, not even wrapping. If I set it to grab vertical space, it takes half the space, leaving the other half for the tree, which is ugly and not what is wanted. If I set hints, I does wrap but the size of its composite never changes, thus hiding the next rows. I tried adding a resize event listener and resizing my inner composite. That allows me to resize it and show all the rows, but it then covers up and hide part of the tree. I tried to do a setLocation and setSize for the tree itself to move/resize it accordingly but to no avail, it doesn't change.
How can this be made to work. What am I missing. Isn't there a simple way to ask for a layout that will use the minimum required height and no more but adjust if needed?
Thanks for your help.
Here the code:
innerComposite = new Composite(parent, SWT.NONE);
innerComposite.addListener(SWT.Resize, listenerComp);
GridDataFactory.fillDefaults().hint(10, 30).applyTo(innerComposite);
GridLayoutFactory.fillDefaults().applyTo(innerComposite);
Listener listenerComp = new Listener() {
public void handleEvent(Event event) {
Widget widget = event.widget;
Composite comp = (Composite)widget;
Composite parent = comp.getParent();
Point parentSize = parent.getSize();
Point size = comp.computeSize(parentSize.x, SWT.DEFAULT);
comp.setSize(size);
}
}
And here's an image:
And after resize (noticing that the 1st row of the tree is covered up):
When you are using Layouts calling setSize (or setBounds) will mess up the layout that has been setup.
Instead you should call layout(true) (or even layout(true, true) on the Composite which owns both the Tree and your innerComposite.

Set the vertical scroll to current position after revalidate

I know that this question might have been asked before, but I just can't get by head around this, and hopefully we could produce a complete answer to a somewhat tricky interface.
The GUI could be described as follows:
Application extends JFrame. Application adds a JPanel mPanel. mPanel adds a JScrollPane ml containing a MoviePanel extending JPanel.
The JScrollPane ml has vertical scrolling. My goal is that once the content of MoviePanel changes, and a run a revalidate() on it, the scroll pane should not, as it currently does, scroll to the bottom. Rather I'd like it to scroll to what ever position it had before the change to MoviePanel. Giving the feel that it never scrolled at all.
I have tried to manually set the scroll position after I run the revalidate() method:
removeAll(); // Removes all components from the JPanel MoviePanel
add(mList()); // Adds a bunch of content (other JPanels) to MoviePanel
revalidate();
ml.getVerticalScrollBar().setValue(0); // Scroll to top (don't work) - and I'd like this value to be the position of the scroll before these lines started to run
but it seems it really doesn't do anything.
I would be so grateful if someone might help me with this!
Add the scrolling code to a SwingUtilities.invokeLater:
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
ml.getVerticalScrollBar().setValue(0);
}
});

JScrollPane does not update scrollbar

I am trying to create a JScrollPane that contains a JPanel that will be increasing and decreasing in height. When it becomes larger than the size of the JScrollPane, it should create a vertical scroll bar which will allow me to scroll through the entire JPanel. However, I am having difficulty achieving this. Yes, I know I am not using LayoutManagers. No, I will not be using them, and I need a solution that does not involve their usage.
Here are the two button's AbstractActions that add and subtract from the JPanel:
class AddACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
info.setSize(420,info.getHeight() + 40);
info.add(new SubPanel); // Adds another JPanel into the main JPanel (for content input)
gui.repaint();
infoS.validate();
}
}
class RemoveACT extends AbstractAction
{
public void actionPerformed(ActionEvent e)
{
info.remove(subPanel()); // This would remove the last JPanel added to the main JPanel
info.setSize(420,info.getHeight() - 40);
gui.repaint();
infoS.validate();
}
And here is the code for the main JPanel and the JScrollPane:
final JPanel info = new JPanel();
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
info.setLayout(null);
info.setSize(420,600);
infoS.setLocation(10,80);
infoS.setSize(420,490);
gui.add(infoS); // gui is the frame's content pane (the overall JPanel)
This is the second project I've been trying to learn GUI by doing. I am a complete novice in Swing and am only intermediate in Java. Sorry if I am making a blindingly obvious mistake.
1) Use LayoutManagers (+1 to #kleopatra and #GagandeepBali comments)
The absence of LayoutManagers only guarantees your GUI's will look very trashy (especially when run on other OSes/builds) and being a Novice you should rather learn the correct way than learn the wrong way and get into bad habits like calling setSize() etc.
Have a read on these links to get you started:
A Visual Guide to Layout Managers
Concurrency in Swing
2) See this example for how to use a JScrollPane, it simply adds a JPanel with buttons to a JScrollPane which in-turn is added to the JFrame.
3) Also see this example for how to make the JScrollPane vertically scroll-able only.
4) For more on JScrollPanes have a look here: How to Use Scroll Panes.
5) As for how it interacts with LayoutManager, if you do not explicitly set its size via setPreferredSize(Dimension d) the scroll pane computes it based on the preferred size of its nine components (the viewport, and, if present, the two scroll bars, the row and column headers, and the four corners)
6) On your usage of validate():
validate() is used when new JComponents are added to a visible component
revalidate() is used when JComponent is removed/added from a visible component
revalidate() covers validate() too
Thus always use this:
//add or remove component(s)
revalidate();
repaint();
References:
http://www.daniweb.com/software-development/java/threads/405568/validate-vs-revalidate
LayoutManager is not required to solve the problem. The problem in Thrfoot's example is in these lines:
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
info.setLayout(null);
info.setSize(420,600);
The program appears to recognize there is a need for scroll bars (it would show the scroll bar if your setting was VERTICAL_SCROLLBAR_AS_NEEDED), but the actual scrolling does not work (the scroll bar slider is not there).
To fix this, first set the preferred size of info, then construct the infoS.
Example:
info.setPreferredSize(420,600);
final JScrollPane infoS = new JScrollPane(info, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
The idea is to set the preferred size of the info panel before it is used for the scroll pane. This is the same reason to set the size and location of infoS before adding to the gui:
infoS.setLocation(10,80);
infoS.setSize(420,490);
gui.add(infoS); // gui is the frame's content pane (the overall JPanel)

Can I get multiple rows in JPanel with FlowLayout

I need solution similar to GridLayout but without resizing components in JPanel.
Everything works great with JFrame, but I need to put those components into JPanel instead JFrame.
I've seen two approaches that may suit your requirement:
Nest each component in a JPanel having FlowLayout, which respects the component's preferred size, as shown here.
Use the HORIZONTAL_WRAP or VERTICAL_WRAP orientation of JList, as shown here.
The following link might help you to choose the most appropriate layout for your needs. Its the Java Tutorial called "A Visual Guide to Layout Manager", which shows nice pictures of each layout and what they look like...
http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html
Otherwise, if you say GridLayout is similar to what you need, you could always write your own MyGridLayout class (that extends GridLayout) and overwrite the method that does the autoresizing.
I stumbled upon this question myself and even though I think using z JList might be a good solution, there's an even simpler way of doing it with a customized FLowLayout, called WrapLayout, available here: https://tips4java.wordpress.com/2008/11/06/wrap-layout/
I ended up using it in my project and it works very well. The only issue I run into is when I set my window to the full screen mode the layout did not update correctly. I used a simple workaround, which was this:
//int targetWidth = target.getSize().width;
int targetWidth = target.getParent().getSize().width; // FIXME: this is a hack for getting the correct size when switching between full screen modes on Mac
With that small hack it works perfectly.
Just Override preferredLayoutSize() in flowlayout and set Maximum size to it. set Alignment as LEADING and set it to your JPanel. You'll get what you want
private FlowLayout getFlowLayout(int maximumSize)
{
if (flowLayout == null)
{
flowLayout = new FlowLayout()
{
#Override
public Dimension preferredLayoutSize(Container target)
{
Dimension dimension = super.preferredLayoutSize(target);
dimension.width = Math.min(maximumSize, dimension.width);
return dimension;
}
};
flowLayout.setAlignment(FlowLayout.LEADING);
}
return flowLayout;
}

Resize JScrollPane client without scrollbars rolling

I have a JScrollpane which contains a scrollable client that changes its size dynamically while using the application. I want the JScrollPane to be aware of the changes without moving the viewport when the client size changes.
To clarify what I mean:
Refer to the Java Webstart example ScrollDemo2 from the article How to use scroll panes by Sun. When clicking at the bottom of the window, a circle appears partly outside the window and the scrollbars move. It's the latter behavior I want to avoid.
My guess is that it's just a matter of setting a simple flag in one of the many components that are involved in a scroll pane solution, but I just can't find where it is. Does anyone know?
I managed to solve this problem by overriding the standard behavior of the viewport in my JScrollPane. This might be a solution that is not suitable for all, but in my GUI this works like a charm.
JScrollPane pane = new JScrollPane();
pane.setViewport(
new JViewport(){
/**
* An empty override implementation to prevent undesired scrolling on
* size changes of the client.
*/
#Override
public void scrollRectToVisible(Rectangle rect){}
});
I would try something like:
Point p = scrollPane.getViewport().getViewportPosition();
revalidate();
scrollPane.getViewport().setViewportPosition(p);
You may need to wrap the last line of code in a SwingUtilities.invokeLater.
If that doesn't work then maybe you can disable/enable the viewport before and after the revalidate()?

Categories

Resources