JScrollPanel JPanel and Layouts - java

What I have:
A split panel with a scroll panel in the right part.
In this scroll panel, I have a JPanel.
I want to have in this JPanel a series of others JPanels stacked one under the other one.
I set the Layout to be a BoxLayout. Now it stacks multiple JPanels, but I have 2 problems:
If my content from JPanel take less space then my frame, then will be lot of space between Jpanels.
If my content from JPanel it's bigger then my frame, the Pannels will go over each other and my scroll from scrollPanel wont activate.
frame = new Frame();
splitPane = new SplitPane();
scrollPane = new ScrollPane();
frame.add(splitPane);
scrollPane.setViewportView(new Lesson());
splitPane.setRightComponent(scrollPane);
splitPane.setLeftComponent(new JTree());
Where Frame, SplitPane, ScrollPane() are classes that extends JFrame, JSplitPane, JScrollPane. Atm they only have a constructor, after it will work, I want to make some customization there.
public class Lesson extends JPanel {
private static final long serialVersionUID = 1L;
public Lesson() {
customize();
String text = "text from pictures";
add(new Paragraph(text));
add(new Paragraph(text));
}
private void customize() {
BoxLayout boxLayout = new BoxLayout(this, BoxLayout.PAGE_AXIS);
setLayout(boxLayout);
}
}
public class Paragraph extends JPanel {
private static final long serialVersionUID = 1L;
public Paragraph(String text) {
setLayout(new FlowLayout(FlowLayout.LEFT));
setPreferredSize(new Dimension());
StringTokenizer splitStringTokenizer = new StringTokenizer(text, " ");
while(splitStringTokenizer.hasMoreTokens()){
add(label(splitStringTokenizer.nextToken().toString()));
}
}
private JLabel label(String string){
JLabel jlabel= new JLabel(string);
return jlabel;
}
}
Any hints about how I can resolve this ? Ty in advance.

A BoxLayout respects the maximum and minimum sizes of components added to it. You are using a FlowLayout o the Paragraph panel. The preferred size is always one line of components.
The panel will shrink until there is only one line displayed or grow to occupy all the space.
When there is more space the panels are allowed to grow.
Override the getMaximum/MinimumSize() of your Paragraph panel to return the preferred size.
The question is why are you using a panel of labels to display text. Why are you not using a text area.
Or another option may be to use the WrapLayout which will wrap components automatically and recalculate the preferred size based on the wrapping. You will still want to override the getMinimum/Maximum size calculations to return the preferred size.
I want later to add some mouse listener to some of jlabels.
Why? Again if you use a text area, you can add the MouseListener directly to the text area and then you can use the caret position (or convert the mouse position to an offset in the text area) to determine what word the mouse is over and then do your processing.

Related

How to center the view by middle panel in swing

I have to build a UI with three panels, leftPanel, middlePanel and rightPanel, Panels should be aligned Horizontally
left and right panels should get the maximum and equal width as possible while the middle panel can get the minimum width as its child component required, once the panels are added view should be centered by middle panel.
I have done following test code to build the UI
import java.awt.Color;
import java.awt.GridBagLayout;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
public class SwingTest extends JFrame {
private static final long serialVersionUID = 1L;
public SwingTest() {
setTitle("Swing Test");
setSize(750, 350);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(getParent());
// Rule used to find the component positions, for the testing purpose
Rule rule = new Rule(Rule.HORIZONTAL, true);
rule.setPreferredWidth(10);
rule.setPreferredHeight(40);
SidePanel leftPanel = new SidePanel("Left");
SidePanel rightPanel = new SidePanel("Right");
JPanel middlePanel = new JPanel();
middlePanel.setBorder(BorderFactory.createLineBorder(Color.black));
// Add left,right and middle panel horizontally
JPanel containerPanel = new JPanel();
containerPanel.setLayout(new BoxLayout(containerPanel, BoxLayout.X_AXIS));
containerPanel.add(leftPanel);
containerPanel.add(middlePanel);
containerPanel.add(rightPanel);
// Add rule and container panel Vertically
JPanel outerPanel = new JPanel();
outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.Y_AXIS));
outerPanel.add(rule);
outerPanel.add(containerPanel);
add(outerPanel);
}
public static void main(String[] args) {
SwingTest test = new SwingTest();
test.setVisible(true);
}
private static class SidePanel extends JPanel {
private static final long serialVersionUID = 1L;
private SidePanel(String text) {
setLayout(new GridBagLayout());
add(new JLabel(text));
}
}
}
I have used Rule class from oracle swing tutorial site, it can be used to find the position of components. get Rule.java
The problem i have is as shown in the UI screen shot, view is not get centered by middle panel, Right now the view centered as width of `left + middle panel = right panel'
I don't want to set the panel height and width manually, It should be handled by the LayoutManager itself.
What i want is middle panel has to be get centered in a way left + middle/2 = middle/2 + right panel width.
I couldn't find a way to make the middle panel to get centered to view, Could someone help me to find a solution for this?.
You need to understand how the BoxLayout works.
First space is allocated at the preferred size of each component. Then if there is extra space, that space is allocated to each component.
The middle doesn't appear to be centered because the preferred size of the right label is larger than the left label. So when the extra space is allocated the right side is larger than the left side.
This is easy to test. Just change the text of the right side panel to "LEFT".
However, that leads to another question - Why doesn't the size of the middle panel change? I don't know the answer to this. Although for some reason the default FlowLayout seems to work different than the GridBagLayout. Again you can test this by changing the layout of the middle panel to be a GridBagLayout.
If you always want the left/right panels to be the same size then you might want to consider using the Relative Layout. Using this layout the basic code would be:
RelativeLayout rl = new RelativeLayout(RelativeLayout.X_AXIS);
JPanel panel = new JPanel( rl );
panel.add(leftPanel, new Float(1));
panel.add(middle, new Float(3));
panel.add(rightPanel, new Float(1));
Now the left/right panels will be the same size independent of the components added to each panel.

JPanel Positioning using the Border Layout not working

I am trying to setup my JPanel's position to the right using i.add(jp, BorderLayout.EAST); but it is not working. Any ideas why? Thanks for the help in advance.
/* INSTANCE DECLARATIONS */
private JTextField tf;//text field instance variable
private JLabel jl2;//label instance variable
/*****************
* WINDOW METHOD *
* ***************/
public void window() {
LoadImageApp i = new LoadImageApp();//calling image class
JFrame gameFrame = new JFrame();//declaration
JPanel jp = new JPanel();
JLabel jl = new JLabel("Enter a Letter:");//prompt with label
tf = new JTextField(1);//length of text field by character
jl2 = new JLabel("Letters Used: ");
jp.add(jl);//add label to panel
jp.add(tf);//add text field to panel
jp.add(jl2);//add letters used
gameFrame.add(i); //adds background image to window
i.add(jp, BorderLayout.EAST); // adds panel containing label to background image panel
gameFrame.setTitle("Hangman");//title of frame window
gameFrame.setSize(850, 600);//sets size of frame
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//exit when 'x' button pressed
gameFrame.setIconImage(new ImageIcon("Hangman-Game-grey.png").getImage());//set the frame icon to an image loaded from a file
gameFrame.setLocationRelativeTo(null);//window centered
gameFrame.setResizable(false);//user can not resize window
gameFrame.setVisible(true);//display frame
}//end window method
What layout manager does i, your LoadImageApp instance, use? I'm betting it's not BorderLayout. I'm betting that the LoadImageApp class extends JPanel and if so and if you never explicitly set its layout, then it uses a FlowLayout by default, and as you're finding out, FlowLayout doesn't respect the BorderLayout.EAST int constant.
The solution is likely quite simple: make it use a BorderLayout:
setLayout(new BorderLayout());
Edit
You state in comment:
When I set the border layout of i to EAST, my background image shifts to the right also, is there a way to get around that?
No, you're missing the point. You need to set the layout of LoadImageApp to BorderLayout. You're not supposed to add i BorderLayout.EAST. This was never recommended to you.
i.e.,
public class LoadImageApp extends JPanel {
// in the constructor
public LoadImageApp() {
setLayout(new BorderLayout());
}
// .... etc....
}
THe LoadImageApp instance (which I would name loadImageApp, not i), should be added BorderLayout.CENTER, which you were doing before. Please read the layout manager tutorials which you can find here.

How to make a JTable fill entire available space?

I want to created a panel with a table, which fills the entire available space.
I do this using following code:
public class MyFrame extends JFrame {
public EconomyFrame() throws HeadlessException {
super("...");
final JTabbedPane tabbedPane = new JTabbedPane();
add(tabbedPane);
final JPanel companiesPanel = new JPanel();
final CompaniesTableModel companiesModel = new CompaniesTableModel
(ApplicationStateSingleton.INSTANCE.getPersistence().getCompanies());
final JTable companiesTable = new JTable(companiesModel);
ApplicationStateSingleton.INSTANCE.getEventBus().subscribeToPropertyChanges(companiesModel);
companiesPanel.add(new JScrollPane(companiesTable));
tabbedPane.addTab("Companies", companiesPanel);
}
}
But it doesn't work because when I resize the frame, the table fills only part of the available space (see screenshots below).
How can I fix (make the table fill the entire available space) ?
Use a layout manager that allows the JTable occupy the full area available rather than the default FlowLayout used by JPanel which only uses its components preferred sizes
JPanel companiesPanel = new JPanel(new GridLayout());
There are two issues:
1) first you need to use an appropriate layout manager to make sure that the scrollpane can resize to fill the available area. Typically people would add the scrollpane to the CENTER of a BorderLayout.
2) you need to let the table fill the available space in the viewport of the scrollpane. To do this you use:
table.setFillsViewportHeight(true);

Change Background and size of panels in card layout

I have some panels in a card layout container (no idea if that is correct terminology). I can't find a way to set the location, or size of these panels inside the container. I tried setBounds and setLayout(null) and I still can't get anything to change.
These are my fields and the constructor. I've gotten my frame working and I can see and use the buttons to change cards, but I really can't change much else about the cards. I set the two card panels two have different backgrounds, but they only make a small boarder of color around the button and leave it in the centre of the screen.
I also don't understand why this isn't pasting my code properly... So sorry!
public class TestPanel extends JPanel implements ActionListener {
CardLayout cl = new CardLayout();
private JPanel panelCont = new JPanel();
private JPanel panel1 = new JPanel();
private JPanel panel2 = new JPanel();
private static JButton but1 = new JButton("Change panels");
private static JButton but2 = new JButton("Change back");
public TestPanel() {
panelCont.setLayout(cl);
panel1.add(but1);
panel2.add(but2);
panel1.setBackground(Color.black);
panel2.setBackground(Color.blue);
panelCont.add(panel1, "1");
panelCont.add(panel2, "2");
cl.show(panelCont, "1");
but1.addActionListener(this);
but2.addActionListener(this);
add(panelCont);
}
}
Thanks. I apologise in advance. I'm finding it hard to understand card layout.
A CardLayout respects the preferred size of the panels added to the layout. That is the size will be the size of the largest panel added to the layout.
I set the two card panels two have different backgrounds, but they only make a small boarder of color around the button and leave it in the centre of the screen.
The default layout for a panel is the FlowLayout. A FlowLayout by default has a 5 pixel horizontal/vertical gap around each component. So the preferred size of your panel is the size of the button plus the 5 pixel gap.
The panel is displaying correctly. When you add other components to the panel the size will change as required.
It's not clear where you pack() the enclosing Window. By default, pack() causes a panel having CardLayout to adopt the the size of the largest panel's preferred size, which is determined by the size of its contents. This example uses setPreferredSize() to specify an arbitrary size, but you can override getPreferredSize() as shown here.

Activity Stream- Producing X amount of objects in a panel on app load

Just wondering if you could help wanting to produce an activity stream in Java, the idea was to have a JLabel and text area followed by a divider be displayed on a screen and then repeated X amount of times according to what data was in a database.
What I was wondering is how could I possibly repeat the placing the jlabel, text area, and diveder on the screen above the last rendered objects on the fly and all displayed correctly no matter the size of the text area of each set of object sort of like the image below.
Hope I made it clear as I could thanks
Just provide your own version of a JPanel containing all these things and place them in a scrollpane that will care about having a long list of these panels..
class MyPanel extends JPanel
{
ImageIcon icon;
JTextArea textArea;
MyPanel(ImageIcon icon, String text)
{
this.icon = icon;
this.setPreferredSize(/*max size of your panel */)
textArea = new JTextArea(10, 50);
textArea.append(text);
//the default manager will be a flow layout for single jpanels
this.add(icon);
JScrollPane sp = new JScrollPane(textArea);
sp.setPreferredSize(new Dimension(/* size of your text label */));
this.add(new JScrollPtextArea);
}
}
class MyContainer extends JFrame
{
JPanel container;
JScrollPane spContainer;
MyContainer()
{
container = new JPanel()
container.setGridLayout(100,1); //100 elements max
spContainer = new JScrollPane(container);
spContainer.setPreferredSize(/* max size of whole thing */)
this.add(spContainer);
pack();
}
void addElement(MyPanel panel)
{
container.add(panel);
this.pack();
}
}
It's not fully working (I just wrote it) but it should give you the idea..

Categories