Scrollable JTextArea that adjusts its size on resize - java

I've a JFrame with multiple panels. One of those should contain a JTextArea of a given size, that can scroll if the text exceeds the area, and that resizes acording to the frame size.
The thing is that when the panel is an instance of JPanel, it looks as I'd like to both in window or fullscreen size, as long as the content doesn't exceed the current area, when it does, it takes the space given to the other components, making them shrink in the frame (here it should show scrollbars instead).
On the other hand, when I use a JScrollPane, I can't manage to make it have the same behaviour of the JPanel, keeping the proper size. Actually it seem to adjust to it's content, and since it's empty, it's just some pixels wide.
How can I achieve what I'm looking for?
Thanks in advance
Following the code that keeps the right size (JPanel):
add(new JPanel(){
{
input = new JTextArea(20,20);
input.setLineWrap(true);
input.setBackground(Color.WHITE);
input.setBorder(cb);
this.setLayout(new BorderLayout());
//this.setPreferredSize(new Dimension(20,20));
this.setBorder(eb);
this.add(input);
}
});

Don't add the text area to the frame.
this.add(input);
Instead you need to add a JScrollPane containing the text area to the frame:
this.add(new JScrollPane(input));

Related

The size of a JTextArea

I have a set of JPanel's within a JFrame. One of the panels contains a JTextArea. At the moment I create this like so:
JTextArea = new JTextArea(5, 40);
And this gives me a text area which is 5 rows by (roughly) 40 columns.
Vertically this works as I'd like it to, the area fills the entire height of the parent container - probably because the parent is the only element positioned in that row.
Horizontally the parent width is determined by elements underneath and it is (usually) wider than the JTextArea is. So I end up with a text area with large margins on either side. What is worse, when I resize the frame smaller to the point where the text area is exactly the width of the parent container, it suddenly 'flicks' and changes into a text area that is 1 row high and is then the width of the parent.
Excuse the crude drawing below which hopefully illustrates the issue.
In short: How to I create a JTextArea that always fills the maximum space available to it? (and if possible with a minimum width after which a scrollbar appears if the user sizes the frame even smaller)
In the parent container of the JTextArea (denoted as Panel 1 in your drawing), call the function:
panel1.setLayout(new BorderLayout());
For reference, see this documentation page:
https://docs.oracle.com/javase/7/docs/api/java/awt/BorderLayout.html
As you only have a single child in panel1, the BorderLayout layout manager of panel1 will by default stretch the text area to use all available space in the parent container.
You may want to take away the constructor parameters specifying the size of your TextArea. The BorderLayout should take care of sizes for you :)
You can request that Swing respects a certain minimum size for the text area by calling:
textArea.setMinimumSize(new Dimension(minimum_width, minimum_height));
You have to use layout manager, for start see oficial Oracle docu about layout managers. For your situation, BorderLayout or GridBagLayout should work fine.
Start with:
panel1.setLayout(new BorderLayout());
or
panel1.setLayout(new GridBagLayout());
With GridBagLayout you can more preciselly do layouting (with BorderLayout you have five areas - no more, no less). With GridBagLayout you can do more complicated layouts.

Fill JPanel only to the height of inner elements

I'm trying to achieve a design whereby one of my JPanel's heights is only set to the height of it's inner components. Currently it's laid out like so:
JPanel (BoxLayout)
JPanel (CardLayout)
JPanel (BoxLayout)
JPanel (BoxLayout)
JPanel (FlowLayout)
It currently displays as so, I want the top bit to expand the both on the x and y axis pushing the "Your Name" to above the status bar.
I need to use BoxLayouts it seems so that it flows from top to bottom.
Please help!
I want the top bit to expand the both on the x and y axis pushing the "Your Name" to above the status bar.
Then is sounds like you can use a BorderLayout as the top level panel, instead of the BoxLayout.
Since the default layout manager for the content pane of the frame is a BorderLayout you can just add the panels directly to the content pane of the frame:
frame.add(cardLayoutPanel, BorderLayout.CENTER);
frame.add(flowLayoutPanel, BorderLayout.PAGE_END);
When you add a panel to the "PAGE_END", its preferred height is respected.
When you add a panel to the "CENTER" it gets all the extra spaces available in the frame.
Read the Swing tutorial on Layout Managers for more information and working examples.
I need to use BoxLayouts it seems so that it flows from top to bottom.
You don't need to use a BoxLayout (as demonstrated above), but you can still use it if you want. BoxLayout respects the maximum size of a panel. So you could override the getPreferredSize() method of your panel using the flow layout to return the preferred height of the panel.
#Override
public Dimension getMaximumSize()
{
Dimension preferred = super.getPreferredSize();
Dimension maximum = super.getMaximumSize();
maximum.height = preferred.height;
return maximum;
}
Now the height of the flow panel will be respected and all the extra space will go to the other panel.

Get a Fixed sized GridLayout

I need to make a fixed sized for a GridLayout with 100 buttons located in the center portion of a BorderLayout. On the east portion of the border layout is another Gridlayout that keeps shrinking the center component whenever the text is longer then the size of the current JTextAreas located in the east. The JFrame is not resizable also.
Is there a way to get a fixed size for the center component while allowing the JTextArea to still expand?
"I need to make a fixed sized for a GridLayout with 100 buttons located in the center portion of a BorderLayout".
Sorry, but that's not going to work. BorderLayout doesn't work like that. You can nest JPanel containers with different Layout managers to get your desired effect.
"Gridlayout that keeps shrinking the center component whenever the text is longer then the size of the current JTextAreas located in the east."
You should wrap your text area in a JScrollPane, and setLineWrap(true) and setWrapStyleWord(true) on you text area. The last two will set it, so that the line typed wraps when it is reaching the right edge of the text area. Also If you are setting the size to the text area, don't. Instead, use the following constructor to set its size
JTextArea jta = new JTextArea(20, 50); <--- rows, and character columns
jta.setLineWrap(true);
jta.setWrapStyleWord(true);
JScrollPane scroll = new JScrollPane(jta);
container.add(scroll); <--- make sure you don add jta anywhere else
Without more context to your querstion, these are really the only valid suggestions I can make.

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)

Make a panel use the exact space it needs and fill in the rest with another panel

I want to make a layout with two componenents in a vertical row.
The first component is an instance of my own class, ImagePanel, that extends Panel and shows an image, and I want it to take up the exact space that it needs to show the entire image. The remaining space should then be filled by the other component (in this case another Panel with a GridLayout). See the picture.
In Android you can do this by using the weight property, but I have not been able to find anything like that in Java, and I canĀ“t see that any of the standard layout managers in Java would be suitable for this.
I tried putting the ImagePanel in BorderLayout.NORTH and the other panel in BorderLayout.CERNTER, but the second panel was then overlapping the image, so that didn't work.
I also thougth about using a GridLayout but the grid would not care about the size of the image, so I don't think that would work either.
Any help is appreciated.
A BorderLayout should work, provided the image panel's getPreferredSize() returns the correct dimension (i.e. the dimension of the image it displays).
Using a simple JLabel containing an ImageIcon and no text instead of your custom ImagePanel would do that for you.
The most powerfull layout in java is GridBagLayout. It has weightx and weighty properties, anchor, fill, etc.
By default, with GridBagLayout each component has all the necessary space to show fully. If you want the second panel to expand, it should be enough with weighty=0.0 in your image and weighty=1.0 in your other panel.
The javax.swing.Box should be exactly what you want. There are 2 types of boxes, vertical and horizontal, you need a vertical:
Box box = Box.createVericalBox();
box.add(comp1);
box.add(Box.createVerticalStrut(5)); // add some empty space
.
.
.
add(box);
Box will only force one side to be equal, for vertical, it's the width, the length could be any size.

Categories

Resources