Swing: An automatic resizing Text above a button? - java

I am looking for a way to do the following:
Have a JDialog with a fixed width.
In it is a JTextArea (or whatever you suggest is a better component...) which receives a text of varying length (somewhere between 0 and 30 line)
Below that text is a button.
The dialog is automatically sized in height to make sure all the Text AND the button is being displayed.
The closest I have come to a solution is this, but the JTextArea does not seem to know how large it is after it did the automatic line breaks!
public PleaseResize(){
super();
Container cp = this.getContentPane();
cp.setLayout(new BoxLayout(cp, BoxLayout.Y_AXIS));
JTextArea area = new JTextArea();
area.setColumns(20);
area.setLineWrap(true);
area.setEditable(false);
area.setWrapStyleWord(true);
area.setText("Once upon a midnight dreary, while I pondered, weak and weary, over many a quaint an curious volume of forgotten lore.");
cp.add(area);
cp.add(new JButton("Hallo"));
this.pack();
}
Scrolling the Text is unfortunately not an option.
I have asked this is a slightly different way before here: Resize Dialog properly after automatic LineWrap, but perhaps the JTextArea is the wrong component after all? Am I using the wrong LayoutManager? All of them seem unable to determine how large the dialog should be, though. Why does the JTextArea fail to communicate it's height after adding line-breaks to the text to the outside?
Here is the working code:
public PleaseResize() throws BadLocationException {
super();
Container cp = this.getContentPane();
cp.setLayout(new BorderLayout());
JTextArea area = new JTextArea();
area.setColumns(20);
area.setLineWrap(true);
area.setEditable(false);
area.setWrapStyleWord(true);
area.setText("Once upon a midnight dreary, while I pondered, weak and weary, over many a quaint an curious volume of forgotten lore.");
System.out.println(area.getLineCount());
JScrollPane pane = new JScrollPane(area);
cp.add(pane, BorderLayout.CENTER);
cp.add(new JButton("Hallo"), BorderLayout.SOUTH);
this.pack();
this.pack();
}
Packing twice still seems a bit weird to me, but it does solve the resizing problems :).

Try this aproach to resize JTextArea based in its model.
Rectangle modelToView = area.modelToView(area.getDocument().getLength());
if (modelToView != null) {
area.setSize(area.getWidth(), Math.max(area.getHeight(), modelToView.height + modelToView.y));
area.doLayout();
}

Related

JComponent partially hidden due to scrollpane in a BoxLayout

I want to add the possibility for my users to add a comment on a form. To display them, I created JPanel inside a simple JScrollPane. I set the layout of this JPanel to BoxLayout because I wish to add them all in only one column and it seemed to be the easiest way by calling BoxLayout.Y_AXIS in the constructor. I also tried GridLayout and GridBagLayout but it was not what I was looking for.
My problem is that when a JPanel has the BoxLayout layout, it's width automatically is the same as it's container, but my container is a JScrollPane and the caret hides the right side of my comment!
You can see the JTextField and a JButton on the bottom left, here's the code on the click event :
private void btnAjoutCommentaireActionPerformed(java.awt.event.ActionEvent evt) {
//I take the text from the JTextField and format it to html
String formattedComment = "<html><br><div style='width:280px;'>" +
txtArCommentaire.getText().replaceAll("\n", "<br>") +
"</div><br></html>";
JLabel label = new JLabel(formattedComment);
//I add a blue border
label.setBorder(new TitledBorder(new EtchedBorder(Color.lightGray, Color.blue), ConfigUser.getCu().toString()));
//this below doesn't work
label.setSize(280, 200);
//I tried adding a JPanel in between but it didn't really worked out
//JPanel panel = new JPanel();
//panel.setLayout(new GridLayout(1, 1));
//panel.setSize(297, 200);
//panel.add(label);
///pnlCommentaire is the JPanel inside the JScrollPane
pnlCommentaire.setLayout(new BoxLayout(pnlCommentaire, BoxLayout.Y_AXIS));
pnlCommentaire.add(label);
pnlCommentaire.revalidate();
pnlCommentaire.repaint();
}
As you can see I tried to adust the size in html using style='width:280px'and on the JLabel using label.setSize(280, 200); but none of them worked.
Do you have any idea on how I could resize this Jlabel?
EDIT :
I added a margin-right property to the div so that I can at least fully see the text in the JLabel but the right border is still hidden.
String formattedComment = "<html><br><div style='width:280px;margin-right:50px;'>" +
txtArCommentaire.getText().replaceAll("\n", "<br>") +
"</div><br></html>";

Java JTextField view from the Right

I have a JTextField that I'm trying to get to automatically view from the Right (Not align to the right), so if the text is to long for the JTextField it will display the last characters in the String instead of the beginning.
Ive been searching for ages trying to locate an answer but keep coming up with aligning.
The 2 images below show what i get and what I'm after, the text is "123456789_123", the JTextField is only big enough to contain the "123456789" but i want to see the "56789_123" instead without having to focus on the field. (i can use something other than a JTextField if needed, tried a JTextArea but had the same issue).
What i Get
What I'm after
I can not just make the Field bigger as I'm restricted by other Objects in my program. Usually the text fits fine but every now and then its too big.
Found a work around.
you create a JScrollPane, make its vertical and horizontal bars invisible by setting there dimensions to 0,0. then scroll to end using 'setValue' to max.
hope this helps anyone trying to do something similar.
JTextArea editArea2 = new JTextArea(5,5);
editArea2.setText("123456789_12345");
editArea2.setAlignmentX(CENTER_ALIGNMENT);
asd = new Dimension();
asd.height = 20;
asd.width = 70;
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(editArea2);
scrollPane.setMinimumSize(asd);
scrollPane.setMaximumSize(asd);
scrollPane.getVerticalScrollBar().setPreferredSize (new Dimension(0,0));
scrollPane.getHorizontalScrollBar().setPreferredSize (new Dimension(0,0));
scrollPane.getVerticalScrollBar().setMinimumSize(new Dimension(0, 0));
scrollPane.getVerticalScrollBar().setMinimumSize(new Dimension(0, 0));
scrollPane.getVerticalScrollBar().setMaximumSize(new Dimension(0, 0));
scrollPane.getVerticalScrollBar().setMaximumSize(new Dimension(0, 0));
scrollPane.getHorizontalScrollBar().setValue( scrollPane.getHorizontalScrollBar().getMaximum() );

Swing JPanel Resizing: won't fit the contents of text file - cuts out text

The java application I'm building utilises the Swing framework. I'm new to Swing, and I'm trying to display some text from a file. The problem is that not all my text is displayed using the code below - it is cut off.
The code
So far, I've created a JFrame component to contain everything:
//initial frame that holds everything
frame = new JFrame(WINDOW_NAME);
frame.setSize(new Dimension((SCREEN_WIDTH.intValue()/100)*80, (SCREEN_HEIGHT.intValue()/100)*80));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Within that, I've created a scroll pane to allow the user to read through the contents of the text file by scrolling vertically; it's quite a large text file - a few chapters from a book.
JScrollPane scrollPane = new JScrollPane(contentPane);
scrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
scrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setWheelScrollingEnabled(true);
frame.setContentPane(scrollPane);
The scroll pane contains a JPanel object. I've utilised the GridBagLayout layout manager for this. The panel itself holds an EditorPane which I've instantiated with the text file's URL.
JPanel contentPane = new JPanel();
contentPane.setPreferredSize(new Dimension(frame.getWidth(), frame.getHeight()));
buildAndAddComponentsToFrame(contentPane);
private void buildAndAddComponentsToFrame(Container container) {
container.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.fill = GridBagConstraints.BOTH;
c.gridx = 0;
c.gridy = 0;
c.weightx = 1.0;
c.weighty = 1.0;
c.insets = new Insets((frame.getHeight()/100)*10, (frame.getWidth()/100)*10, (frame.getHeight()/100)*10, (frame.getWidth()/100)*10);
//create a non-editable editor pane to hold the contents of the religious texts
JEditorPane textContainer = new JEditorPane();
textContainer.setEditable(false);
//TODO load the content of the pane from a URL (local)
File textFile = new File(*my text file*);
try {
textContainer.setPage(textFile.toURI().toURL());
} catch (IOException e) {
e.printStackTrace();
}
container.add(textContainer,c);
}
This works - I'm able to read the contents of the file but not in its entirety: it only shows what it can fit within the height of the JPanel object. I don't want to place the text content within a ScrollPane - but make the JPanel's height be relative to the contents of the text file.
Is there any way to achieve this? I've used the container to make the "text area" appear like a microsoft word document hence the insets - it looks like a paper document in the middle of the jframe - this is intentional.
Thanks for any help - sorry if my explanation was a bit vague. I've added a screenshot to help explain.
You're creating a JPanel, using default FlowLayout, you're forcing its preferred size to some value, and then wondering why it won't get bigger when the JTextPane it holds has text greater than it's size. This is not happening for the mistakes that you're making above.
Suggestions:
Best to place the JTextPane into the JScrollPane, to not constrain the JTextPane's size or preferred size.
Otherwise if you must wrap the JTextPane in a JPanel, give it a JPanel that will expand if its components expand. Use a BorderLayout and add the JTextPane BorderLayout.CENTER. Then place that into a JScrollPane's viewport and if must constrain sizes, do so of the viewport.

MigLayout Shrink Behavior

with the JPanel defined below (embedded in a JTabPanel in a JSplitPane):
If I maximize, the panel is redrawn correctly to the new dimensions
If I minimize the panel is NOT redrawn to the previous dimensions
If I drag the corner to increase the size the panel is redrawn to correct dimensions
If I drag a corner to decrease size the panel is NOT redrawn to the expected dimensions
container.setLayout(new MigLayout("debug,fillx,wrap 5",
"[75:75:75][fill][75:75:75][fill][140:140:140,align left]"));
container.add(labelSrcTitle, "span 4");
container.add(buttonAddRef, "");
container.add(srcTitle, "span");
container.add(srcListing, "span,grow");
container.add(sepRef,"span,growx");
container.add(refTitle,"span");
container.add(refListing,"span 4,grow");
container.add(buttonEdit,"split 2");
container.add(buttonDelete,"");
container.add(name,"span 4,growx");
container.add(buttonSEdit,"split 3");
container.add(buttonSDelete);
container.add(buttonSAdd,"");
container.add(lType,"");
container.add(lClaim,"grow");
container.add(lQual,"");
container.add(lNotes,"grow");
container.add(buttonCEdit, "split 3");
container.add(buttonCDelete);
container.add(buttonCAdd, "");
I would like (and expect) that if I maximize then minimize, the screen will get redrawn to its original configuration. what am I missing? If it matters, all the JTextArea fields are line wrap true.
Edited:
Here is a much simpler example - the issue seems to be with JTextArea with linewrap set on. The following code in a JFrame recreates the issue:
JPanel root = new JPanel(new MigLayout("fill,debug"));
JTextArea t = new JTextArea();
t.setLineWrap(true);
root.add(t,"growx");
setContentPane(root);
setLocationRelativeTo(null);
setSize(200, 200);
Problem solved. After identifying the issue to JTextArea and Line Wrap, I determined that it was a symptom of MigLayout and JTextArea Line wrap documented in several places; and resolved it by changing root.add(t,"growx") to root.add(t,"growx,wmin 10")

Please help me understanding BoxLayout alignment issues

I'm trying to create a very simple window using Java Layouts. I have got three elements to arrange: a button, a progress bar and a label. The button has to be vertically centered, the progress bar has to take full width, and the label has to be left aligned.
Here's some code (just assume pane is the content pane of a JFrame, and button, progressBar and label have been created before):
BoxLayout layout = new BoxLayout(pane, BoxLayout.Y_AXIS);
pane.setLayout(layout);
button.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(button);
progressBar.setAlignmentX(Component.CENTER_ALIGNMENT);
pane.add(progressBar);
label.setAlignmentX(Component.LEFT_ALIGNMENT);
pane.add(label);
When I test the application I see everything misaligned and screwed up: the button and the label are randomly indented, and if I resize the window the indentation amount changes in a strange way.
The progress bar looks good (full width).
I just don't understand what's happening. Can you give me a clue?
BoxLayout cannot handle different alignments: see http://download.oracle.com/javase/tutorial/uiswing/layout/box.html
quoting from that article: "In general, all the components controlled by a top-to-bottom BoxLayout object should have the same X alignment. Similarly, all the components controlled by a left-to-right Boxlayout should generally have the same Y alignment."
Sometimes you need to get a little creative and use nested panels. But I like this approach better then trying to learn and memorize all the constraints required when using other layout managers (GridBagLayout, GroupLayout) there where designed to be used by IDE's that generate code for you.
import java.awt.*;
import javax.swing.*;
public class BoxLayoutVertical extends JFrame
{
public BoxLayoutVertical()
{
Box box = Box.createVerticalBox();
JButton button = new JButton("A button");
button.setAlignmentX(Component.CENTER_ALIGNMENT);
box.add(button);
JProgressBar progressBar = new JProgressBar(0, 100);
progressBar.setAlignmentX(Component.CENTER_ALIGNMENT);
box.add(progressBar);
JPanel panel = new JPanel( new BorderLayout() );
JLabel label = new JLabel("A label");
label.setAlignmentX(Component.LEFT_ALIGNMENT);
panel.add(label);
box.add(panel);
add(box, BorderLayout.NORTH);
}
public static void main(String[] args)
{
BoxLayoutVertical frame = new BoxLayoutVertical();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.setSize(300, 200);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
To complement my comment to the original question, here is a snippet that uses DesignGridLayout:
JButton button = new JButton("Button");
JProgressBar progressBar = new JProgressBar();
JLabel label = new JLabel("Label");
// The interesting stuff is in the next 4 lines
DesignGridLayout layout = new DesignGridLayout(getContentPane());
layout.row().center().add(button).withOwnRowWidth();
layout.row().center().fill().add(progressBar);
layout.row().left().add(label);
pack();
It does exactly what wou describe in your question and doesn't require any specific call of any of the components.
Maybe your code is just a snippet, but I'm missing a call to pack().
Coding swing layout by hand can be very frustrating with the standard Layout managers. I use MiG Layout for that purpose. It is straight forward and you have a nice layout with just a few lines of code. If you're not forced to use BoxLayout I would suggest you give it a try.
Don't use BoxLayout. It works only for very simple cases.
For your case, I would recommend either GridBagLayout or (my favorite) GroupLayout.
For GroupLayout, I created a subclass (LayoutHelper) with some utility methods and useful constructors, which makes writing the Layout much easier.
Of course, usually I align all components in a group the same way, so it is not as short in your case as it would be in the simple case.
LayoutHelper h = new LayoutHelper(pane);
h.setVerticalGroup
( h.sequential( button, progressBar, label));
h.setHorizontalGroup
( ((ParallelGroup)h.parallel())
.addComponent(button, Alignment.CENTER)
.addComponent(progressBar)
.addComponent(label, Alignment.TRAILING));
Here is a screenshot:
For a simple "everything aligned the same way", the horizontal group would look like this:
h.setHorizontalGroup
( h.parallel (button, progressBar, label));
(optionally with a first argument indicating the alignment).

Categories