Allowing User to Resize JScrollPane - java

When the user moves the cursor over to the border of the JScrollPane, can I turn the cursor into two little arrows that are pointing at the opposite directions of each other thus the user may shrink or grow the entire JScrollPane?
JScrollPane scrollPane = new JScrollPane(buddyList,
ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
layoutConstraints.gridx = 0; layoutConstraints.gridy = 0;
layoutConstraints.gridwidth = 3; layoutConstraints.gridheight = 8;
layoutConstraints.fill = GridBagConstraints.BOTH;
layoutConstraints.insets = new Insets(10, 6, 10, 36);
layoutConstraints.anchor = GridBagConstraints.NORTHWEST;
layoutConstraints.weightx = 0.8; layoutConstraints.weighty = 1.0;
layout.setConstraints(scrollPane, layoutConstraints);
add(scrollPane);//Adds the Scrollpane straight to the panel The class extends JPanel

You are looking at the wrong place. If you want to allow resizing of the scrollpane, the scrollpane is the wrong object to look at. It’s the responsibility of the parent container (or its layout manager) to give or take space from the component (which happens to be a scrollpane here) and distribute it to other children. The simplest way is to put the scrollpane into a split pane. You may put the split pane into another split pane with a different orientation to allow resizing in both direction, however this will resize the direct neighbor of the scroll pane (the other child of the inner split pane) as well. There is no solution to this with all these layouts forming a kind of grid.
Note that with your currently used GridBagLayout in the parent container it’s very hard to achieve such a resize support. And even if you implement this tricky trick the GridBagLayout will always size entire rows or columns. Thus you will have the same problem as with nested split panes even worse.

Related

Java - Resize buttons in GridBagLayout

how can I make the buttons height a bit bigger and the width of right and left columns on the same size. I have tried weightx weighty heightx heighty but it didn't work. Thanks in advance. Here's my code:
Container contentPane = getContentPane();
contentPane.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
c.insets = new Insets(20,20,20,20);
c.fill = GridBagConstraints.HORIZONTAL;
c.weightx = 1.0;
JButton back = new JButton("Back to previous menu");
c.gridx = 1;
c.gridy = 0;
contentPane.add(back,c);
JLabel welcome = new JLabel("Hi secretary, please select an action");
c.gridx = 0;
c.gridy = 0;
contentPane.add(welcome,c);
There's more code of buttons definition but it's just positioning themselves on the layout.
Do not set the preferred size of your buttons. This will cause serious visual issues for users who have desktop fonts which are different from yours.
You should let the button define its own preferred size. The best way to augment the preferred height is with GridBagConstraints.ipady:
c.ipady = 24;
Another option is to use JButton.setMargin to give each button an additional margin:
Insets margin = new Insets(12, 0, 12, 0);
back.setMargin(margin);
welcome.setMargin(margin);
Forcing the left and right sides to have equal widths is more difficult. GridBagLayout is not capable of doing that. The weightx field only determines the distribution of extra space, when the window is wider than it needs to be in order to accommodate all child components’ preferred sizes. If the columns have different widths to begin with, distributing the extra space with weightx will not make their widths equal.
Personally, I don’t think forcing the two sides to have equal widths will add any value. If you insist on the left and right sides being exactly equal width, you will have to abandon the use of GridBagLayout. SpringLayout can do it, but it’s difficult to use. If you’re willing to introduce a third-party dependency, something like MiG Layout may be able to do it.

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.

Why does the last item added to a panel occupy the whole panel?

I'm adding a quantity of JTextField to a panel, and all of them are added but, the last one added takes the whole panel and seems all other text boxes added on the last one..... here is the code
public JPanel crearCartonFormulario() {
panel = new JPanel();
panel.setLayout(new BorderLayout());
JTextField[] textBoxes = new JTextField[25];
int cont = 0;
int posX = 10;
int posY = 0;
llenarArreglo();
while (cont <= 4) {
for (int i = 0; i <= 4; i++) {
if (cont == 2 && i == 2) {
textBoxes[i] = new JTextField("");
} else {
textBoxes[i] = new JTextField(String.valueOf(numeros[cont][i]));
}
textBoxes[i].setBounds(i + posX, 15 + posY, 40, 40);
textBoxes[i].setEditable(false);
panel.add(textBoxes[i]);
posX += 50;
}
posY += 50;
posX = 10;
cont++;
}
return panel;
}
This is returned at a panel where I keep multiple panels of this one, it works but in this one the last JTextField takes the whole panel space....
The new JFrame that contains the panels created by the method, adopt the last JTextField size and that text box doesn't take the bounds indicated by the method, but all the other text boxes still inside and correctly added.
panel.setLayout(new BorderLayout());
You are using a BorderLayout.
panel.add(textBoxes[i]);
When you use the add() method the default is to add the component to the CENTER of the BorderLayout. However, only a single component can be added to the center so the layout manager will only manage the size/location of the last component added. The rules of the BorderLayout is to make the component take up all the available space.
However, you have also used the setBounds() methods for the other text fields which is causing a problem. You should NOT attempt to use a layout manager and manage the bounds of the components yourself.
The solution is to just use a layout manager and let the layout manager do its job. Read the section from the Swing tutorial on Using Layout Managers for more information and use a more appropriate layout manager.
Update:
its a bingo table
Then maybe you shouldn't even be using JTextFields. Maybe a JTable would be a better component to use. The tutorial also has a section on How to Use Tables.
Your problem is here:
panel.setLayout(new BorderLayout());
You set the layout to BorderLayout and yet add components to the JPanel as if it were a GridLayout. Understand that when you add components to a BorderLayout-using container in a default way, the components get added in the BorderLayout.CENTER position which fills this position, covering anything added prevsiously.
Perhaps you wish to use a GridLayout instead? You will want to read the layout manager tutorial for more.
This is because you are using BorderLayout and BorderLaout Always requires a parameter like BorderLayout.CENTER, BorderLayout.WEST, BorderLayout.EAST, BorderLayout.NORTH and BorderLayout.SOUTH.
So basically BorderLayout only has 5 position where a component can go. And if you do not specify where when adding a component it defaults to BorderLayout.CENTER. And as there can only be one component at a time in the BorderLayout.CENTER position it only really adds the last one. So I'd suggest an other layout manager like GridLayout( if you want all the components to be equally sized).
I hope this helps :).
P.S. If you want me to give some explination on GridLayout just ask.

How to improve GUI by changing BoxLayout into a different LayoutManager?

I've a big problem with Swing in Java, I used BoxLayout for this but still it looks bad.
Any suggestions about my usage of layouts, or how to change it to look like in assumptions? (here are assumptions)
Container main = new Container();
Container left = new Container();// here goin buttons
Container right = new Container(); // here goin tabs + more buttons, textfields and other stuff
BoxLayout lewyL = new BoxLayout(left, BoxLayout.Y_AXIS);
left.setLayout(lewyL);
left.add(rastrowa); //radiobutton
left.add(wektorowa);//radiobutton
left.add(apDwuliniowa);//checkbox
left.add(wczytaj);//button
left.add(zapisz);//obutton
left.add(wyczysc);//button
BoxLayout prawyL = new BoxLayout(right, BoxLayout.Y_AXIS);
right.setLayout(prawyL);
right.add(zakladki);// tabs (mostly i use BoxLayout but for last one i need something more "complicated")
EDIT: I almost solve this problem, I need to move all elements to left (how it look like)but I have no idea how ;/ Here is constructor of this class.
JLabel label = new JLabel("O wektor");
JLabel labelA = new JLabel("a:");
JLabel labelB = new JLabel("b:");
JButton wykonaj = new JButton("Wykonaj");
JTextField a = new JTextField(5);
JTextField b = new JTextField(5);
add(label);
add(labelA);
add(a);
add(labelB);
add(b);
add(wykonaj);
There's nothing wrong with the way it looks (in my opinion), but if you want it to look a little better, why don't you convert the left panel (which is 6x1) into a 3x2 panel, with the checkboxes/radiobuttons on the left, and buttons on the right? Sounds like a job for GridLayout - one of my favorite classes...
JPanel leftPanel = new JPanel(new GridLayout(3,2));
leftPanel.add(rastrowa); //radiobutton
leftPanel.add(wczytaj); //button
leftPanel.add(wektorowa); //radiobutton
leftPanel.add(zapisz); //obutton
leftPanel.add(apDwuliniowa); //checkbox
leftPanel.add(wyczysc); //button
Note that the 3,2 defines the number of rows,columns. When adding panels, they are added to the grid from left-to-right, and top-to-bottom. GridLayout also auto-sizes the components, so all the buttons etc will be the same width and height, making it look more consistent.
The GridLayout documentation might be useful, and the Visual Guide to Layout Managers is a great place to see other layout managers that might work better for your different situations. I personally find BorderLayout and GridLayout to be the most useful, and cover about 95% of the situations I ever need for my GUIs.

How do you stop a JLabel changing its size when its text changes?

I'm generating some JComponents in code and using the GridBag layout to arrange them. My layout consists of 12 rows and 3 columns, with each row consisting of a JSlider, a JCheckBox and a JLabel. Here's the code I'm using to generate the UI:
final int NUM_MOTORS = 12;
// This is the panel I'm adding the components to.
pnlMotorSliders.setLayout(new GridBagLayout());
GridBagConstraints c = new GridBagConstraints();
for (int i = 0; i < NUM_MOTORS; ++i) {
c.gridy = i;
// Create the slider
JSlider slider = new JSlider(SwingConstants.HORIZONTAL, 10, 4085, 10);
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 0;
c.weightx = 0.9;
pnlMotorSliders.add(slider, c);
// Create the checkbox
JCheckBox checkBox = new JCheckBox();
checkBox.setOpaque(true);
checkBox.setBackground(Color.blue);
c.fill = GridBagConstraints.NONE;
c.gridx = 1;
c.weightx = 0.1;
pnlMotorSliders.add(checkBox, c);
// Create the current label
JLabel label = new JLabel("0");
label.setBorder(BorderFactory.createLineBorder(Color.red));
c.fill = GridBagConstraints.HORIZONTAL;
c.gridx = 2;
c.weightx = 0.2;
pnlMotorSliders.add(label, c);
}
The problem I'm having is that when I set the text in any of the JLabels, they change their width and affect the rest of the layout, even if the width of the text that I'm setting appears to be much smaller than the width of the JLabel. The following two screenshots demonstrate what I mean (the red and blue borders were for debugging purposes):
I've set the text on the bottom JLabel to "-12". Even though the JLabel appears to be much wider than the text, it has changed its size, affecting the rest of the layout.
Why is this happening and what can I do to prevent it?
You can fix the size of the labels by setting the minimum, prefered and maximum size:
label.setMinimumSize(width, height);
label.setPreferedSize(width, height);
label.setMaximumSize(width, height);
Also make sure to set the GridBagConstraints#fill to NONE, although I am not sure if that is still neccessary (I think it is).
EDIT: btw, to get rid of those nasty dashed lines around the focused Component, you can just set it to be not focusable:
slider.setFocusable(false);
The set-the-preferred-size solution works only if you don't have the components horizontally fill their bag in the GridBagLayout.
Another solution is to remove the weight you have placed on components in that column of your GridBagLayout. You can then control the column width manually. An easy way to do so (at design time) is to place a JLabel in the column with zero height and the specific width you desire.
Why is this? You need to dig into how GridBagLayout works:
The GridBagLayout sizes its columns based on the space required, and then uses the weights to allocate the "left over" space so that the resulting column widths then add up to the total width of the panel. The space required for each column is computed by finding the widest of the components in that column.
The space required for each component is determined by asking it what width it would prefer. In your case, a JLabel with "0" is smaller than a JLabel with "-12" and so the column is changing size.
The left over space is allocated based on the horizontal weights assigned to components in each column. The weights are totaled and percentages for each column are determined based on that column's percent of the total.
The column size is determined based on the space required PLUS the left over space. So, if all your components in the column have no weight then you'll not get any left over space, and hence not get dynamic changes.
A third solution is to just not use GridBagLayout.
Explicitely set the preferred size of your labels using JLabel#setPreferredSize(Dimension).
This way, you lock the size of the component, and tell the layout manager not to resize it.
label.setPreferredSize(new Dimension(width, height));
This was only way i could find to make it work. Setting a Minimum and/or a Maximum didn't do anything for me. Also, for me on java 8 i needed to use a Dimension, or there was no change to the previous, inappropriate sizes.

Categories