Layout - the height of the inside panel will not be affected - java

Hi I am fairly new to Java. I have JPanel which added other JPanel. The number of the inside JPanel is depend on the list. If the list is delete or add then I remove all inside JPanel and add JPanel according updated list. The inside panel will have different height depend of the data of the list. My problem is the height of the inside panel will change to fit the outside JPanel because of the total amount of inside panel change. I want the height of the inside panel will not be affected when I delete or add the new inside JPanel. I use BoxLayout for the outside panel. Would someone tell me how to solve it. Thanks in advance.
There is the code I add the inside JPanel into the outsider JPanel
jpListCommentPane=new JPanel();
jpListCommentPane.setLayout(new BoxLayout(jpListCommentPane,
BoxLayout.Y_AXIS));
//sortPage
Component[] components = jpListCommentPane.getComponents();
for (Component component : components) {
jpListCommentPane.remove(component);
jpListCommentPane.repaint();
}
sortComment= lstComment;
Collections.sort(sortComment,CommentItem.sortPage);
for(CommentItem comm: sortComment){
DivCommentJPane d=new DivCommentJPane(comm, this);
jpListCommentPane.add(d);
}
jpListCommentPane.revalidate();
There is the screen shot for comparison:

Related

How to resize a panel if a child component is added with it at runtime?

I have a window, containing a frame and JScrollBar. JScrollBar has panel, whose size i want to change at run time if any child component is added with it. Child component size is constant and should not change.
I have Horizontal scrollBar disabled. So if placement of Child Component exceeds panel width, it should go to next row and panel height should change automatically.
Here is code snippet
JScrollPane scrollPane = new JScrollPane();
menuPane = new JPanel();
menuPane.setLayout(new FlowLayout(FlowLayout.CENTER));
scrollPane.setViewportView(menuPane);
MenuTray mtFile = new MenuTray("File"); // MenuTray extends JPanel
menuPane.add(mtFile);
Menu mNew = new Menu((new ImageIcon(MenuScreen.class.getResource("/com/srinar/res/New.png"))), "New"); // Menu extends JLabel
mtFile.add(mNew);
frame.getContentPane().add(scrollPane);
. So if placement of Child Component exceeds panel width, it should go to next row and panel height should change automatically
The FlowLayout will wrap components automatically but it doesn't recalculate the preferred size with the components on the new row.
Instead you can use the Wrap Layout which extends FlowLayout so it can recalculate the preferred size correctly when components wrap.
Note, the wrapping will occur even if you don't use a scroll pane.

Set height but not width of JTextArea

I have multiple JTextAreas inside a JPanel. I am using a BoxLayout to make them align vertically and fill the width of the container.
It works, but they seem to expand to fill the entire height as well.
What I really want is simple - a text area that wraps text where I can control the width but allow the height to scale dynamically as more lines are added. The above method was just my best attempt at it. If there is a solution that uses a different layout manager, different text component, etc, that works.
minimal verifiable example below:
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setPreferredSize(new Dimension(300, 300));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel textAreas = new JPanel();
textAreas.setLayout(new BoxLayout(textAreas, BoxLayout.Y_AXIS));
JTextArea area1 = new JTextArea();
area1.append("this is a string");
area1.setLineWrap(true);
area1.setWrapStyleWord(true);
textAreas.add(area1);
JTextArea area2 = new JTextArea("and another that is much longer, so that it wraps to the next line");
area2.setLineWrap(true);
area2.setWrapStyleWord(true);
textAreas.add(area2);
JScrollPane scrollPane = new JScrollPane();
scrollPane.setViewportView(textAreas);
frame.add(scrollPane);
frame.pack();
frame.setVisible(true);
}
I have done research on this topic on my own, including looking at different layout managers (http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html), and checking other questions on the site, but I haven't had much luck.
TLDR: Can I make it so each element of a layout has a height that scales to its content but a fixed width? If so how?
What I really want is simple - a text area that wraps text where I can control the width but allow the height to scale dynamically as more lines are added.
The BoxLayout respects the maximum size so the text area grows to fill all the space available in the panel. You can override the getMaximumSize() method to return the preferred height by using something like:
JTextArea area1 = new JTextArea()
{
public Dimension getMaximumSize()
{
Dimension d = super.getMaximumSize();
d.height = getPreferredSize().height;
return d;
}
};
It works...
Not really. Make the frame wider and the text will unwrap. Then shrink the frame and the scrollbar will appear. That is the text will not wrap again
What you need to do is force the panel added to the scroll pane to be the same width as the viewport. This will allow wrapping to work properly.
You do this by implementing the Scrollable interface on the panel. Specifically you need to override the getScrollableTracksViewportWidth() method to return true.
Or an easier solution is to use the Scrollable Panel class which allows you to set properties of the panel to control this behaviour.
You can replace a JPanel with the ScrollablePanel:
//JPanel textAreas = new JPanel();
ScrollablePanel textAreas = new ScrollablePanel();
textAreas.setScrollableWidth( ScrollablePanel.ScrollableSizeHint.FIT );
Edit:
If there is a solution that uses a different layout manager
Without overriding the getMaximumSize() method of the text areas and when using the Scrollable Panel you should be able to use the following layout managers.
The GridBagLayout allows you to specify the "weightx" constraint. This will allow the component to fill all the available space in the panel.
Or if you don't like specifying all the constrains of the GridBagLayout you could use the Relative Layout which support vertical/horizontal layout of components at their preferred size.
You would just need to use the following to force the component to fill the horizontal space:
//textAreas.setLayout(new BoxLayout(textAreas, BoxLayout.Y_AXIS));
RelativeLayout rl = new RelativeLayout(RelativeLayout.Y_AXIS);
rl.setFill( true );
textAreas.setLayout(rl);

Adding JPanels through a loop

Made it work! Thank you guys! The code follows. I used BoxLayout since I thought it'd be ideal for stacking questions one on top of the other, but now I got issues with the layout... When I stack several questions the question panels start overlapping. Any thoughts?
panels1 = new MultipleChoice[5];
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
for(int i=0; i<4; i++){
panels1[i]= new MultipleChoice();
panels1[i].setAlignmentX(CENTER_ALIGNMENT);
add(panels1[i]);
}
setVisible(true);
I'm working on designing an Online Test applet. A test has multiple choice and true/false questions. To set up a test I created two JPanel classes, one for the multiple choice question and one for the true/false questions. So when a test is created I'll just dynamically add these panels to a JPanel container according to the non-fixed number of questions.
First, how can I dynamically add new panels to a panel? I thought about declaring an array of the JPanel type. I created and then add objects of this panel class using a for loop:
MultitipleChoicePanel[] PanelArray;
for (...){
PanelArray[i] = new MultipleChoicePanel();
containerpanel.add(PanelArray[i]);
}
I don't know if this is technically possible. This is my first time using Swing, and I tried doing this but obviously it didn't work. Does anyone have an idea how correctly dynamically add these panels?
Second, which of the layout managers is best suited for the container panel in order to fit every new panel added right under the previous one? I thought about dynamically setting up a GridLayout of one column and add rows as I add panels. But I've been really struggling modifying swings dynamically.
Any suggestions?
Thank you so much for your help!
JPanel default layout is FlowLayout and add each component by default to the right so it would fit your problem.
You also may interested in swingx they have HorizontalLayout.
Example:
//in some place
JPanel myBigPanel = new JPanel();
myBigPanel.setLayout(new HorizontalLayout()); // swingx api
List<MultitipleChoicePanel> panelList = new ArrayList<>();
// panelList.add(new MultipleChoicePanel()).. .n times
for(MultipleChoicePanel mp : panelList){
myBigPanel.add(mp);
}
myBigPanel.revalidate(); // revalidate should call repaint but who knows
myBigPanel.repaint();
How to use various Layout Managers
how correctly dynamically add these panels?
After adding components to a visible GUI you need to do:
panel.add(...);
panel.revalidate();
panel.repaint();
"and then add objects of this panel class using a for loop:.....I dont know if its technically possible"
As far as an array of panels, I would do it with an arraylist and do it similarly to how you did it.
import java.util.ArrayList;
ArrayList<MultipleChoicePanel> array = new ArrayList<MultipleChoicePanel>();
for(...){
array.add(new MultipleChoicePanel());
containerPanel.add(array.get(i));
}
import java.awt.*;
import javax.swing.*;
public class JavaSwing extends JApplet {
public void init(){
Container content = getContentPane();
JScrollPane pane= new JScrollPane();
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel,BoxLayout.Y_AXIS));
panel.add(addPanel("title121"));
panel.add(addPanel("title112"));
panel.add(addPanel("title12"));
panel.add(addPanel("title11"));
pane.getViewport().add(panel);
content.add(pane);
}
public static JPanel addPanel(String title){
JPanel panel = new JPanel();
panel.add(new JButton(title));
return panel;
}
}

Placing JTextFields in a JFrame of a Java GUI

I have:
public class BaseStationFrame1 extends JFrame
{
JButton activateButton;
JButton deactivateButton;
BaseStation bs;
JTextField networkIdField;
JTextField portField;
public BaseStationFrame1(BaseStation _bs){
bs = _bs;
setTitle("Base Station");
setSize(600,500);
setLocation(100,200);
setVisible(true);
activateButton = new JButton("Activate");
deactivateButton = new JButton("Deactivate");
Container content = this.getContentPane();
content.setBackground(Color.white);
content.setLayout(new FlowLayout());
content.add(activateButton);
content.add(deactivateButton);
networkIdField = new JTextField("networkId : "+ bs.getNetworkId());
networkIdField.setEditable(false);
content.add(networkIdField);
portField = new JTextField("portId : "+ bs.getPort());
portField.setEditable(false);
content.add(portField);}
}
My problem is that i don't want the two TextFields to appear on the right of Activate and Deactivate buttons but below them. How can i fix that?
Specify your layout manager, like this:
content.setLayout(new GridLayout(2,2));
That would use the Grid Layout Manager to establish a grid with 2 columns and 2 rows, that your components would then be placed in.
The layout manager you are currently using, FlowLayout, only adds contents onto the end of the current row. it will wrap around once it reaches the constrained edge of the pane, though.
You should also check the other layout managers here
You could alternatively use GridBagLayout , but you will have to specify a GridBagConstraints object you then add alongside the individual elements, like so:
content.add(networkIdField, gridConstraints);
see more on that in the linked tutorial.
can I suggest that you use a Null Layout for the parent component?
setLayout(null);
then use a setBounds(xPos,yPos, Width, Height);
to position the components on the panel etc?
Doing this will prevent Java's UI Manager to manage the components to the Frame, Panel etc.
That seems to be the easiest and less painful way.
Regards

Problem resizing JScrollPane and JTabbedPane

I have a problem with resizing some of my components in my java application. When I resize my main JFrame they keep their previous size instead of filling out the surrounding component.
For example I have in my program a JTabbedPane within a tab of another JTabbedPane (which is located within the main JFrame). I make tabs added to the inner JTabbedPane fill the whole surrounding space via various .setPreferredSize(). And then when I resize the JFrame by dragging the corner of the window, the tabs out the outer JTabbedPane resizes just fine but the JTabbedPane located within it stays the same old size.
The same thing with happens when I test it with a JScrollPane: the outer JTabbedPane resizes by the JScrollPane stays the same size.
Here below is the code for creating the tabbed panels in case you can see something obvious I missed. It's the tabPane/jsp objects in createEndGamePane() than wont resize when the JFrame is resized. mainTabPane resizes as it should.
class MyFrame extends JFrame {
private JTabbedPane mainTabPane;
private JPanel endGameInfo;
//....
private void createTabbedCenterPane(){
this.mainTabPane = new JTabbedPane();
this.endGameInfo = new JPanel();
this.createEndGamePane();
this.mainTabPane.addTab("Turneringschema", null, this.scheduleHolder, "Spelschemat för turneringen");
this.mainTabPane.addTab("Grupper & Pooler", null, this.poolInfo, "Information om grupper, lag och pooler");
this.mainTabPane.addTab("Slutspelsträd", null, this.endGameInfo, "Information om slutspelen");
this.add(this.mainTabPane, BorderLayout.CENTER);
}
private void createEndGamePane(){
JTabbedPane tabPane = new JTabbedPane();
tabPane.setPreferredSize(this.endGameInfo.getSize());
for (int i = 0; i < this.tournament.data.getGroups().size(); i++) {
EndGame e = this.tournament.data.getEndGames().get(i);;
//Create the gameTree
EndGameTreeCanvas gameTree = new EndGameTreeCanvas(e, this.endGameInfo.getSize());
//Create the ScrollPane
JScrollPane jsp = new JScrollPane(gameTree);
jsp.setPreferredSize(tabPane.getSize());
jsp.setBorder(BorderFactory.createEmptyBorder());
//Add to the endGameIndo panel
tabPane.addTab(this.tournament.data.getGroups().get(i).getName(), jsp);
}
this.endGameInfo.add(tabPane);
}
}
If you want the components to resize dynamically, you should avoid telling Swing what their size is. Instead, how about this:
JTabbedPane tabs = new JTabbedPane();
JScrollPane inner1 = new JScrollPane(myOtherComponent);
tabs.add("Scroll", inner1);
JTabbedPane inner2 = new JTabbedPane();
tabs.add("Tabs", inner2);
And that's all. No setPreferredSize().
You should read the swing layout tutorial :
http://java.sun.com/docs/books/tutorial/uiswing/layout/index.html
The layout manager i prefer is the gridbaglayout that allow maximum flexibility
( http://java.sun.com/docs/books/tutorial/uiswing/layout/gridbag.html ).
In particular, you should not use the BorderLayout.CENTER if you wish the component to fill all the available space around him.
an example with a gridbaglayout manager :
this.add(this.mainTabPane,
new GridBagConstraints(
0,0, // position
1,1, // size
1.0,1.0, // fill ratio
GridBagConstraints.CENTER, GridBagConstraints.BOTH, // position inside the cell
new Insets(2,2,2,2),0,0)); // margins
As others have said, you need to be using layout managers to handle your GUI's layout requirements.
However I recommend that your primary layout manager be a table-based layout like MatrixLayout, MigLayout, TableLayout, or any of a number of other free ones.
Using a table-based layout will simplify your GUI coding by about an order of magnitude, because it will vastly reduce the amount of layout nesting required. I find that 90% of my GUI is done with one layout manager, and the remaining 10% draws on the simpler layout managers provided with Java.
I have never had cause to use GridBagLayout and I absolute do not recommend it - it's unnecessarily complicated and make ongoing maintenance harder.

Categories