I have a bar at the top of my application that has a number of buttons either side of a JLabel. The button's visibility is dependent upon the current task a user is carrying out and one of the button's text may also change depending on the current state.
What I would like to do is have a number of buttons stick to the left of the JPanel, the JLabel's center to be in the very center of the JPanel and the rest of the buttons to be to the right of the JPanel.
So far I have managed to get the buttons sticking to the left and the right using various methods and layout managers but I cannot get the JLabel's center to be in the dead center of the JPanel. The best I have managed to get is the label near enough to the center but it would then move around as the buttons are set to visible or their text changes.
Is it possible to force the JLabel to remain dead center?
Note: the buttons will never become big enough to meet either edge of the JLabel, so that is not a problem.
You could also use a BoxLayout, with X_AXIS layout, and add to the container
Edit: Here's an example
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.add(Box.createHorizontalGlue());
panel.add(innerPanel);
panel.add(Box.createHorizontalGlue());
As I see it you need the label to be displayed at its preferred size and then you need a left and right panel to equally fill the remaining space available in the window.
You can use the Relative Layout class.
import java.awt.*;
import javax.swing.*;
public class RelativeSSCCE extends JPanel
{
public RelativeSSCCE()
{
JPanel left = new JPanel( new FlowLayout(FlowLayout.LEFT) );
left.add( new JButton("L1") );
left.add( new JButton("L2") );
left.add( new JButton("L3") );
JLabel center = new JLabel("Centered");
JPanel right = new JPanel( new FlowLayout(FlowLayout.RIGHT) );
right.add( new JButton("Right1") );
right.add( new JButton("Right2") );
right.add( new JButton("Right3") );
// choose your layout manager here
setLayout( new RelativeLayout() );
Float ratio = new Float(1);
add(left, ratio);
add(center);
add(right, ratio);
}
private static void createAndShowUI()
{
JFrame frame = new JFrame("Basic RelativeSSCCE");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new RelativeSSCCE() );
frame.setSize(600, 100);
frame.setLocationRelativeTo( null );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Use BorderLayout. Add the JLabel with the BorderLayout.CENTER constraint and add a pair of JPanels with the BorderLayout.EAST and BorderLayout.WEST constraints. Add your additional buttons to the appropriate JPanel.
To have the text appear centered, you also need to set the Label's horizontalAlignment to JLabel.CENTER.
setAlignmentX(java.awt.Component.CENTER_ALIGNMENT)
and
setAlignmentY(java.awt.Component.CENTER_ALIGNMENT)
may help if used with the elements which have to be centered, e.g. JPanel
may be I`m necroposting, but setAlignmentX(java.awt.Component.CENTER_ALIGNMENT) and setAlignmentY(java.awt.Component.CENTER_ALIGNMENT) may help...
Related
So I have this JFrame that contains a JPanel and in there I add JLabels with information I want but since I'll be adding labels all the time at some point the text is too long to appear so I want to add a scrollbar. Basically I want to make my JFrame with a JPanel in it scrollable. I have this code but my problem is that even though the scrollbar appears but it doesnt move and doesn't really work when the text is a lot, meaning the text still gets cut out and the scrollbar is there not moving. Does anyone know how to fix this?
import javax.swing.*;
import java.awt.*;
import java.util.*;
public class Bar {
JFrame info = new JFrame("Information");
JLabel ballinf = new JLabel();
JPanel contentPane = new JPanel();
JScrollPane scrolling = new JScrollPane();
public Bar(){
contentPane.setOpaque(true);
contentPane.setBackground(Color.WHITE);
contentPane.setLayout(null);
scrolling = new JScrollPane(contentPane,JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
info.add(scrolling);
info.setSize(750, 600);
info.setLocationByPlatform(true);
info.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
info.setVisible(true);
}
public void adding(int pos){
ballinf = new JLabel("Something ",JLabel.CENTER);//assume the text will be bigger here and have more info
ballinf.setSize(700, 30);
ballinf.setForeground(Color.green);
ballinf.setLocation(5, 5+pos);
contentPane.add(ballinf);
info.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
info.setVisible(true);
}
public static void main(String[] args){
Bar stats = new Bar();
stats.adding(0);
stats.adding(20);//this will be done in a for loop for more than 2 times so the text ends up to be a lot
}
}
contentPane.setLayout(null);
Don't use a null layout!!!
You need to use an appropriate layout manager. Read the section from the Swing tutorial on Layout Managers for more information and working examples. The layout manager will then determine the preferred size of the panel as you add components to the panel.
The scrollpane will then display the scrollbars when necessary.
If you dynamically add components to the panel (after the GUI is visible) then the code should be something like:
panel.add(...);
panel.revalidate();
panel.repaint();
Okay so before you ask, yes I'm not using any Layout Manager. No, that doesn't make this bad design (as I've seen people in here saying because someone simply didn't use one). The thing is i want the label to always (and I mean always) show over the two buttons (over the gap left by them which makes it impossible to put it as an Icon or a text on the JButton).
JFrame frame = new JFrame("ColorTap");
private void init() {
JButton jb1 = new JButton(""), jb2 = new JButton("-");
JLabel label = new JLabel("TEXT HERE");
label.setForeground(Color.white);
label.setFont(new Font("Arial Bold",Font.ITALIC,30));
label.setBounds(60,249,200,100);
frame.setLayout(null);
jb1.setBounds(0, 0, 300,298);
jb2.setBounds(0, 302, 300, 300);
jb1.setBackground(Color.black);
jb2.setBackground(Color.black);
jb1.setBorderPainted(false);
jb2.setBorderPainted(false);
frame.add(label);
frame.add(jb1);
frame.add(jb2);
frame.setResizable(false);
frame.setSize(300, 628);
frame.setLocation(550, 50);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
After this what's stranger to me is that the button on the bottom stays under the label and not the one on the top... HELP! Thanks
Swing is optimized to paint components in two dimensions. That is it assumes components will never overlap. Overlapping JButtons cause a problem because of the rollover effects which only cause the buttons to be painted, not the label, so the button is painted over the top of the label.
So you need to tell Swing that components do overlap so Swing can make sure components are painted in the proper ZOrder:
JPanel panel = new JPanel()
{
#Override
public boolean isOptimizedDrawingEnabled()
{
return false;
}
};
Now you can set the layout manager of the panel and add your components to the panel and they will be painted properly.
See: How to put a JButton with an image on top of another JButton with an image? for a working example that DOES use layout managers.
I am learning how to use Swing and found myself quite difficult task.
What I am trying to accomplish: I want to have panel (call it menu panel) on the left side (let's say 100px width) and the second panel (call it content panel), which takes the rest of available place.
In menu panel there are 3 buttons. When I press on of them, to the right side of menu panel (over content panel) second menu panel (submenu) should appear (and it should start in the middle of button which was pressed).
It may be hard to understand, so I've created simple draft:
I tried JLayeredPane but there were problems with resizing window (elements in Layered Pane didn't resize).
JLayeredPane miss implementations for LayoutManager, you have to setPreferredSize or setBounds manually for sizing/place JComponents,
there is one possible workaround you can add ComponentListener to the JFrame, then on componentResized(ComponentEvent e) you can resize/replace JComponent(s) to the desired Bounds
for example
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class LayeredPaneWithOverlap {
private JTextArea textArea = new JTextArea(2, 10);
private JPanel textPanel = new JPanel(new BorderLayout());
private JTable table = new JTable(30, 5);
private JScrollPane scroll = new JScrollPane(table);
private JLayeredPane layer = new JLayeredPane();
private JFrame frame = new JFrame("Frame with resiziable JLayeredPane");
public void makeUI() {
textArea.setBorder(new LineBorder(Color.DARK_GRAY));
textArea.setText("Frame with resiziable JLayeredPane");
textPanel.setOpaque(false);
textPanel.add(textArea, BorderLayout.NORTH);
Font font = textArea.getFont();
FontMetrics fontMetrics = textArea.getFontMetrics(font);
int h = fontMetrics.getHeight() + frame.getInsets().top +
textPanel.getInsets().top + textArea.getInsets().top
+ textArea.getInsets().bottom;
scroll.setBounds(0, h, 400, 300);
layer.add(textPanel, new Integer(2));
layer.add(scroll, new Integer(1));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(600, 400);
frame.addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
resizeAll();
}
});
}
});
frame.setLocationRelativeTo(null);
frame.add(layer);
resizeAll();
frame.setVisible(true);
}
void resizeAll() {
Insets insets = frame.getInsets();
int w = frame.getWidth() - insets.left - insets.right;
int h = frame.getHeight() - insets.top - insets.bottom;
textPanel.setSize(w, h);
scroll.setSize(w, h - scroll.getY());
layer.revalidate();
layer.repaint();
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new LayeredPaneWithOverlap().makeUI();
}
});
}
}
You can set a layoutmanager for the layered pane, javax.swing.OverlayLayout uses the full available space and allows resizing.
JLayeredPane layer = new JLayeredPane();
layer.setLayout(new OverlayLayout(layer));
You probably don't want the submenu to occupy the fullspace. To avoid it you can override its get…size-methods. Or you can add a second LayeredPane (for it's transperancy and it's layoutmanager), set a normal BoxLayout and use a spacer.
JPanel normalContents = new JPanel();
layer.add(normalContents, JLayeredPane.DEFAULT_LAYER);
JLayeredPane subMenuAuxiliaryLayer = new JLayeredPane()
subMenuAuxiliaryLayer.setLayout(new BoxLayout(subMenuAuxiliaryLayer, BoxLayout.LINE_AXIS));
layer.add(subMenuAuxiliaryLayer, JLayeredPane.PALETTE_LAYER);
JPanel submenuContents = new JPanel();
subMenuAuliliaryLayer.add(submenuContents);
subMenuAuxiliaryLayer.add(Box.createHorizontalGlue());
contentPanel.setLayout(null); // Absolute positioning of children.
#Override
public void actionPerformed(ActionEvent evt) {
final JButton btn = (JButton) evt.getSource();
final int buttonY = btn.getY(); // Must be final for usage in new Runnable object.
SwingUtilities.invokeLater(new Runnable() { // Return fast from event handling.
#Override
public void run() {
JPanel child = new JPanel();
child.setBackground(Color.RED); // So we'll see it.
child.setBounds(0, buttonY, 100, 300);
contentPanel.removeAll(); // Clear content panel of prior additions.
contentPanel.add(child); // Add a new panel.
contentPanel.repaint(10L);
}
});
}
The JLayeredPane works by defualt with no Layout manager, which means that you are using absolute positioning and no resizing. You could add a resize listener and adjust positions and size of inner components from code, as you see fit.
If you don't want to do this from code, you will need a layout manager, nothing fancy, just something to fill the container as it resizes. But here's the thing... if you add a layout manager, it will layout the components as if they are all in one layer, but most layout managers don't overlap their children so they are useless. The only one you could use is the OverlayLayout - it can also resize children. But using an OverlayLayout with JLayeredPane is overkill. You can just use OverlayLayout with a JPanel. So, yes, JLayeredPane is kind of useless. I recommend using a JPanel with an OverlayLayout instead.
Here is how to set things up so that you can have great control over almost any overlapping UI scenario out there: Using a JPanel with an OverlayLayout, have a separate transparent JPanel for each layer. In this way you can combine various LayoutManagers on different layers, by setting a diferent layout manager for each pane, including absolute positioning if necessary. Then add your visible components inside the panels representing the layers. Don't add them directly to the OverlayLayout panel. Just make sure that all of the JPanels you are using as layers have setAlignmentX and Y to center (0.5f) so that they fill the entire OverlayLayout panel as it resizes.
It's very simple, what I want to do, but I can't figure out a way to do it. In a JFrame or JPanel, how do you center components vertically? That is, analogous to using the center tag in HTML. The components are in a column and they are all centered.
I have tried BoxLayout, with Y_AXIS and PAGE_AXIS, but it aligns the components in a strange way for me. I have tried to use FlowLayout with preferred size set so it wraps around, but it doesn't center it. I'd rather not resort to something powerful like GridBagLayout for such a simple thing unless it is really the only option. Help!
If I had to make a guess I would say that you are using components with a different "x alignment". Try using:
component.setAlignmentX(JComponent.CENTER_ALIGNMENT);
See the section from the Swing tutorial on Fixing Alignment Problems for more information.
If you need more help then post your SSCCE showing what you have tried.
Edit:
import java.awt.*;
import javax.swing.*;
public class BoxLayoutTest extends JFrame
{
public BoxLayoutTest()
{
Box box = new Box(BoxLayout.Y_AXIS);
add( box );
JLabel label = new JLabel("I'm centered");
label.setAlignmentX(JComponent.CENTER_ALIGNMENT);
box.add( Box.createVerticalGlue() );
box.add( label );
box.add( Box.createVerticalGlue() );
}
public static void main(String[] args)
{
BoxLayoutTest frame = new BoxLayoutTest();
frame.setDefaultCloseOperation( EXIT_ON_CLOSE );
frame.setSize(300, 300);
frame.setLocationRelativeTo( null );
frame.setVisible(true);
}
}
I have problem while setting the Jlabel location.
I set the content pane to some JPanel, I created and tried to add my JLabel.
JLabel mainTitle = new JLabel("SomeApp");
mainTitle.setFont(new Font("Arial",2 , 28));
mainTitle.setBounds(0,0, 115, 130);
getContentPane().add(mainTitle);
I want that my JPanel will be on the top left corner on my application and what I am getting is "SomeApp" on the top center.(and not top left).
btw I tried to add JButton the and the I can`t change the width,height,x,y of the JButton.
Swing uses Layout Managers to place the components.
You have to understand how they work to use them effectively. You can set the layout manager to null, and do the layout your self, but is not recommendable because you'll have to keep track of new components each time, and perform layout computation your self when the window moves shrink etc.
Layout managers are a bit hard to grasp at first.
Your windows could be like this:
Using this code:
import javax.swing.*;
import java.awt.Font;
import java.awt.FlowLayout;
class JLabelLocation {
public static void main( String [] args ) {
JLabel mainTitle = new JLabel("SomeApp");
mainTitle.setFont(new Font("Arial",2 , 28));
//mainTitle.setBounds(0,0, 115, 130); //let the layout do the work
JFrame frame = new JFrame();
JPanel panel = new JPanel(new FlowLayout(FlowLayout.LEFT));// places at the left
panel.add( mainTitle );
frame.add( panel );// no need to call getContentPane
frame.pack();
frame.setVisible( true );
}
}
Where a particular widget ends up in its container depends on the layout manager that it's using. The layout manager determines how to resize and arrange the widgets to make them fit appropriately. Obviously, the default layout for the content pane decided that the top center was the best place to put the JLabel.
If you want to get to not use a layout manager and just place everything yourself (which generally isn't the best way to lay things out btw), then add:
getContentPane().setLayout(null);
Using layouts is usually a better idea since they allow for dynamic resizing of components. Here's how you'd do it with a BorderLayout:
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add (new JLabel ("Main title"), BorderLayout.NORTH);
If you want to add something to the right of the label you could create an additionnal panel with it's own layout :
// Create a panel at the top for the title and anything else you might need
JPanel titlePanel = new JPanel (new BorderLayout());
titlePanel.add(new JLabel ("Main title"), BorderLayout.WEST);
// Add the title panel to the frame
this.getContentPane().setLayout(new BorderLayout());
this.getContentPane().add(titlePanel, BorderLayout.CENTER);
Here are some usefull links to get started with layouts:
http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/uiswing/layout/visual.html
http://download.oracle.com/docs/cd/E17409_01/javase/tutorial/uiswing/layout/using.html