I am trying to write a form in java, but after dynamically inserting JLabels to the current JDialog and doing a pack() the windows is resized to minimum. The JLabels are displayed, but I have to resize the window manually.
Here is the part where the JLabels are inserted:
public void displayQuizz(Test quiz){
int xLable = 44;
int yLable = 41;
int widthLable = 403;
int heightLable = 70;
int noOfQuestion = 1;
for(Question question : quiz.getQuestions()){
JLabel lblNewLabel = new JLabel(Integer.toString(noOfQuestion) + ". " + question.getStatement());
lblNewLabel.setBounds(xLable, yLable, widthLable, heightLable);
contentPanel.add(lblNewLabel);
contentPanel.revalidate();
contentPanel.repaint();
this.pack();
noOfQuestion++;
yLable += heightLable;
}
}
The pack() method sets the size of a Window (where JFrame and JDialog are subclasses from) to the preferred size.
The preferred size is determined by
The LayoutManager, which takes the arrangement of the components and
their preferred size into account
The component itself, if it does not have a layout manager
As you don't use a layout manager in your example (and set the bounds of the label manually), you also have to specify the preferred size yourself (see getPreferredSize(), the default is 0x0, that's the problem you encountered).
I'd encourage you to get used to always use layout managers (there's quite a lot of them, and you can easily write your own layout manager strategy if none suffices your needs).
Related
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.
So I'm developing an application. I have a huge problem, and I know I'm probably overlooking something stupid, but my scollpanes aren't scrolling. Could someone please checkout the following code and tell me what I did wrong?
rotationPanel = new JPanel();
rotationPanel.setLayout(null);
rotationLabels = new JLabel[countStarters(team)];
resetXY(5,5);
for(int i = 0; i < countStarters(team); i++){
rotationLabels[i] = new JLabel(team.rotation.get(i).getName());
rotationLabels[i].setForeground(Color.BLACK);
addComp(rotationLabels[i], rotationPanel, labelX, labelY, labelSize);
labelY += 25;
}
//Other Code in between
rotationBar = new JScrollPane(rotationPanel);
rotationBar.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
rotationBar.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED);
rotationBar.setPreferredSize(new Dimension(520, 150));
addComp(rotationBar, this, 15, 75, new Dimension(520, 150));
//addComp method:
public void addComp(JComponent comp, JComponent panel, int xPos, int yPos, Dimension size){
comp.setLocation(xPos,yPos);
comp.setSize(size);
panel.add(comp);
}
The resetXY() method just sets the x and y position for the components
Any help would be appreciated
Cheers,
Dave
JScrollPane uses either the components preferredSize or if implemented Scrollable#getPreferredScrollableViewportSize to determine what size the scroll pane and its view port can be. When the viewport is larger the the scroll pane, the scroll bars will appear
The Swing API has being designed around the use of the layout manager, choosing to do without the will cause you no end of problems and additional work.
Layout managers help you over come the difference between systems, including font rendering, DPI, screen sizes and rendering pipelines to mention a few.
I think your JPanel needs to have its size set, otherwise it will shrink to fit the JScrollPane.
I have a JDialog with just a few components inside it. I want to make the dialog as small as possible. Currently I am using pack(). This has the unintended effect of reducing the dialog's width so much that the title is no longer completely in view. I want the dialog's width to always be great enough such that the title is always completely in view.
I am using swing. I realize that the title bar appearance/font is determined by the OS. I would prefer to stick with swing so at the moment i am planning on calculating the title string width based on the font of a JLabel. Then I will set the minimum width of one of my components equal to that.
Is there any better way to pack a JDialog while keeping its title visible?
public static void adjustWidthForTitle(JDialog dialog)
{
// make sure that the dialog is not smaller than its title
// this is not an ideal method, but I can't figure out a better one
Font defaultFont = UIManager.getDefaults().getFont("Label.font");
int titleStringWidth = SwingUtilities.computeStringWidth(new JLabel().getFontMetrics(defaultFont),
dialog.getTitle());
// account for titlebar button widths. (estimated)
titleStringWidth += 110;
// set minimum width
Dimension currentPreferred = dialog.getPreferredSize();
// +10 accounts for the three dots that are appended when the title is too long
if(currentPreferred.getWidth() + 10 <= titleStringWidth)
{
dialog.setPreferredSize(new Dimension(titleStringWidth, (int) currentPreferred.getHeight()));
}
}
EDIT:
after reading trashgod's post in the link, I adjusted my solution to override the getPreferredSize method. I think this way is better than my previous static method. Using the static method, I had to adjust it in a pack() sandwich. pack(),adjust(),pack(). This wasy doesn't require special consideration with pack().
JDialog dialog = new JDialog()
{
#Override
public Dimension getPreferredSize()
{
Dimension retVal = super.getPreferredSize();
String title = this.getTitle();
if(title != null)
{
Font defaultFont = UIManager.getDefaults().getFont("Label.font");
int titleStringWidth = SwingUtilities.computeStringWidth(new JLabel().getFontMetrics(defaultFont),
title);
// account for titlebar button widths. (estimated)
titleStringWidth += 110;
// +10 accounts for the three dots that are appended when
// the title is too long
if(retVal.getWidth() + 10 <= titleStringWidth)
{
retVal = new Dimension(titleStringWidth, (int) retVal.getHeight());
}
}
return retVal;
}
};
1) Use FontMetrics to find out the width of your title
2) Add to this value a number representing the window icon and the X (close) button (you should guess that).
3) Set the dialog's width with the above value.
You can't find the exact width size you need but this is a way to make a good guess.
I'm trying to implement a quite simple UI using SpringLayout (partly because I, as opposed to most tutorial writers I find on the net, quite like the coding interface compared to other layout managers and partly because I want to learn how to use it). The UI basically looks like this:
This is all well. The UI resizes the way I want (keeping the welcome text centered and expanding the text area to fill all the new available space) if I increase the window size. However, below a certain point (more specifically when the window becomes too narrow for the welcome text):
I would like the window to not allow further shrinking, so that if the user tries to shrink the window to a size smaller than enough to house the components, it simply stops. How do I accomplish this, using the SpringLayout layout manager?
I know I could probably do this by handling some resize-event and checking if the minimum size is reach, and then just set the size to the minimum size. But this requires me to a) know, or know how to calculate, the minimum size of the window, even before it renders, b) write a bunch of event-handling code just to get some UI rendering right, and c) write a bunch of code for things that I expect a good layout manager to take care of ;)
you can override MinimumSize for TopLevelContainer
you have put JTextArea to the JScrollPane
easiest way is mixing LayoutManagers (called as NestedLayout) by spliting GUI to the parts (separated JPanels with same or different LayoutManager), rather than implements some most sofisticated LayoutManager (GridBagLayout or SpringLayout) for whole Container
some LayoutManagers pretty ignore setXxxSize
SpringLayout isn't my cup of Java
import java.awt.*;
import javax.swing.*;
public class MinSizeForContainer {
private JFrame frame = new JFrame("some frame title");
public MinSizeForContainer() {
JTextArea textArea = new JTextArea(15, 30);
JScrollPane scrollPane = new JScrollPane(textArea);
CustomJPanel fatherPanel = new CustomJPanel();
fatherPanel.setLayout(new SpringLayout());
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(fatherPanel, BorderLayout.CENTER);
frame.setLocation(20, 20);
frame.setMinimumSize(fatherPanel.getMinimumSize());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
MinSizeForContainer Mpgp = new MinSizeForContainer();
}
});
}
}
class CustomJPanel extends JPanel {
private static final long serialVersionUID = 1L;
#Override
public Dimension getMinimumSize() {
return new Dimension(400, 400);
}
}
There are several issues to achieve a "real" (that is not shrinkable beyond) min size:
the child components must return some reasonable (based on their content) min size, many core components don't
the layoutManager must respect the compounded min of all children, no matter how little space is available
the top-level container (here the JFrame) must not allow shrinking beyond the min
The first is true for a JLabel, the second is met for SpringLayout (that's why the label is truncated) - which leaves the third as the underlying problem, the solution to which isn't obvious, actually I wasn't aware it's even possible before running #mKorbel's example. The relevant line indeed is
frame.setMinimumSize(someSize);
With that line in place, it's not possible to shrink the frame below. Without, it is. Starting from that observation, some digging turns out the doc for its override in Window
Sets the minimum size of this window to a constant value. [..] If
current window's size is less than minimumSize the size of the window
is automatically enlarged to honor the minimum size. If the setSize or
setBounds methods are called afterwards with a width or height less
[...] is automatically enlarged to honor the minimumSize value.
Resizing operation may be restricted if the user tries to resize
window below the minimumSize value. This behaviour is platform-dependent.
Looking at the code, there are two (implementation, don't rely on them :-) details related to the min size
Dimension minSize;
boolean minSizeSet;
and public api to access
public Dimension getMinimumSize()
public boolean isMininumSizeSet()
the first rather oldish (jdk1.1), the latter rather newish (jdk1.5) - implying that the first can't rely on the latter but internally has to check for a null minSize. The overridden sizing methods (with their guarantee to doing their best to respect a manually set minSize) on Window are the latest (jdk6) and do rely on the latter. Or in other words: overriding isMinimumSizeSet does the trick.
Some code snippet (beware: it's a hack, untested, might well be OS dependent with undesirable side-effects!):
// JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame("some frame title") {
/**
* Overridden to tricks sizing to respect the min.
*/
#Override
public boolean isMinimumSizeSet() {
return true; //super.isMinimumSizeSet();
}
/**
* Overridden to adjust for insets if tricksing and not using
* LAF decorations.
*/
#Override
public Dimension getMinimumSize() {
Dimension dim = super.getMinimumSize();
// adjust for insets if we are faking the isMinSet
if (!super.isMinimumSizeSet() && !isDefaultLookAndFeelDecorated()) {
Insets insets = getInsets();
dim.width += insets.left + insets.right;
dim.height += insets.bottom + insets.top;
}
return dim;
}
};
// add a component which reports a content-related min
JLabel label = new JLabel("Welcome to my application!");
// make it a big min
label.setFont(label.getFont().deriveFont(40f));
frame.add(label);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
I've got a Jlist inside a JScrollPane and I've set a prototype value so that it doesn't have to calculate the width for big lists, but just uses this default width.
Now, the problem is that the Jlist is for some reason replacing the end of an element with dots (...) so that a horizontal scrollbar will never be shown.
How do I disable with "wrapping"? So that long elements are not being replaced with dots if they are wider than the Jlist's width?
I've reproduced the issue in a small example application. Please run it if you don't understand what I mean:
import javax.swing.*;
import java.awt.*;
public class Test
{
//window
private static final int windowWidth = 450;
private static final int windowHeight = 500;
//components
private JFrame frame;
private JList classesList;
private DefaultListModel classesListModel;
public Test()
{
load();
}
private void load()
{
//create window
frame = new JFrame("Test");
frame.setSize(windowWidth, windowHeight);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setUndecorated(true);
frame.getRootPane().setWindowDecorationStyle(JRootPane.PLAIN_DIALOG);
//classes list
classesListModel = new DefaultListModel();
classesList = new JList(classesListModel);
classesList.setPrototypeCellValue("prototype value");
classesList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
classesList.setVisibleRowCount(20);
JScrollPane scrollClasses = new JScrollPane(classesList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED);
for (int i = 0; i < 200; i++)
{
classesListModel.addElement("this is a long string, does not fit in width");
}
//panel
JPanel drawingArea = new JPanel();
drawingArea.setBackground(Color.white);
drawingArea.add(scrollClasses);
frame.add(drawingArea);
//set visible
frame.setVisible(true);
}
}
Even if you force horizontal scrollbar, you still won't be able to scroll because the element is actually not wider than the width because of the dot (...) wrapping.
Thanks in advance.
Scrollbars appear automatically when the preferred size of the component added to the scrollpane is greater than the size of the scrollpane.
By using the setPrototypeCellValue(...) method you are affecting the way the list calculates its preferred size, which means you are responsible for providing the proper value that ensures the strings will not be truncated.
So the simple solution is not not use that method, but in addition you will need to set the preferred size of the scrollpane to be whatever you want. Then the horizontal scrollbars will appear if required.
My answer to that question is that first find the longest element in the list then use
setPrototype method on that elements
When you call classesList.setPrototypeCellValue("prototype value") you are telling the JList classesList to limit its maximum width to the length of the string "prototype value". (See javadocs)
Then later on when you populate the list with the strings "this is a long string, does not fit in width", no wonder it does not fit in the width! Because the width of the prototype you gave it is smaller than the width of the string you are filling the list with.
The JScrollPane will automatically show the scrollbars and you usually don't need to adjust their behavior. The JList will also automatically adjust its width to try and show the maximum width item in the list. The problem occurs when you tell the JList to fix its width by calling the setPrototypeCellValue().
If you comment out
classesList.setPrototypeCellValue("prototype value");
or replace it with
classesList.setPrototypeCellValue("this is a long string, does not fit in width");
then it will function as you expected it to.