I want to vertically align 3 buttons in a bottom panel.
Here's what I wrote:
ClientWindow(){
pickBtn = new JButton();
attackBtn = new JButton();
placeBtn = new JButton();
JPanel userPanel = new JPanel();
userPanel.setPreferredSize(new Dimension(100,100));
userPanel.setBackground(Color.red);
JFrame frame = new JFrame();
frame.setTitle("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.setResizable(false);
frame.setSize(1280,720);
frame.setLocationRelativeTo(null);
frame.add(userPanel,BorderLayout.SOUTH);
userPanel.add(pickBtn);
userPanel.add(attackBtn);
userPanel.add(placeBtn);
frame.setVisible(true);
}
How could I align them vertically?
Take a look at Laying Out Components Within a Container
For example, this following uses a GridBagLayout
import java.awt.BorderLayout;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JLabel label = new JLabel("This is just here to make some content");
label.setBorder(new EmptyBorder(32, 32, 32, 32));
JFrame frame = new JFrame();
frame.add(label);
frame.add(new UserPanel(), BorderLayout.SOUTH);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class UserPanel extends JPanel {
public UserPanel() {
JButton pickBtn = new JButton("Pick");
JButton attackBtn = new JButton("Attack");
JButton placeBtn = new JButton("Place");
setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridwidth = GridBagConstraints.REMAINDER;
gbc.fill = GridBagConstraints.HORIZONTAL;
add(pickBtn, gbc);
add(attackBtn, gbc);
add(placeBtn, gbc);
}
}
}
Make a ButtonLayout
Important
Please note: The following is intended to replace the GridBagLayout from the above example, as GridBagLayout is complicated and might be a little overkill for this purpose
A REALLY long time ago, I can across a really neat concept of a ButtonLayout, it basically provided a simple layout manager to layout buttons similar to how most OS'es do it (ie, the buttons are of equal size).
The following is a VERY basic example of that concept.
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.LayoutManager2;
import java.awt.Point;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
public class Main {
public static void main(String[] args) {
new Main();
}
public Main() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.add(new UserPanel());
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class UserPanel extends JPanel {
public UserPanel() {
JButton pickBtn = new JButton("Pick");
JButton attackBtn = new JButton("Attack");
JButton placeBtn = new JButton("Place");
setBorder(new LineBorder(Color.BLACK));
setLayout(new ButtonLayout(ButtonLayout.Alignment.VERTICAL, ButtonLayout.Anchor.TRAILING));
add(pickBtn);
add(attackBtn);
add(placeBtn);
}
}
public class ButtonLayout implements LayoutManager2 {
public enum Alignment {
VERTICAL, HORIZONTAL
}
public enum Anchor {
LEADING, CENTER, TRAILING
}
private Alignment alignment;
private Anchor anchor;
private int padding;
private Dimension virtualBounds;
public ButtonLayout() {
this(Alignment.HORIZONTAL, Anchor.TRAILING, 0);
}
public ButtonLayout(Alignment alignment, Anchor anchor) {
this(alignment, anchor, 0);
}
public ButtonLayout(Alignment alignment, Anchor anchor, int padding) {
this.alignment = alignment;
this.padding = padding;
this.anchor = anchor;
}
public Alignment getAlignment() {
return alignment;
}
public Anchor getAnchor() {
return anchor;
}
protected int getPadding() {
return padding;
}
protected int getTotalPadding(Container parent) {
int padding = getPadding();
return (padding * parent.getComponentCount()) - padding;
}
#Override
public void addLayoutComponent(Component comp, Object constraints) {
}
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
}
#Override
public void invalidateLayout(Container target) {
virtualBounds = null;
}
protected Dimension virtualLayout(Container parent) {
if (virtualBounds != null) {
return virtualBounds;
}
int maxWidth = 0;
int maxHeight = 0;
for (Component component : parent.getComponents()) {
Dimension preferredSize = component.getPreferredSize();
maxHeight = Math.max(maxHeight, preferredSize.height);
maxWidth = Math.max(maxWidth, preferredSize.width);
}
int padding = 0;
int width = 0;
int height = 0;
int componentCount = parent.getComponentCount();
switch (alignment) {
case HORIZONTAL:
width = (maxWidth * componentCount) + getTotalPadding(parent);
height = maxHeight;
break;
case VERTICAL:
width = maxWidth;
height = (maxHeight * componentCount) + getTotalPadding(parent);
break;
}
virtualBounds = new Dimension(width, height);
return virtualBounds;
}
#Override
public Dimension maximumLayoutSize(Container parent) {
return virtualLayout(parent);
}
#Override
public Dimension preferredLayoutSize(Container parent) {
return virtualLayout(parent);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return virtualLayout(parent);
}
#Override
public float getLayoutAlignmentX(Container target) {
return 0.5f;
}
#Override
public float getLayoutAlignmentY(Container target) {
return 0.5f;
}
#Override
public void layoutContainer(Container parent) {
int maxWidth = 0;
int maxHeight = 0;
for (Component component : parent.getComponents()) {
Dimension preferredSize = component.getPreferredSize();
maxHeight = Math.max(maxHeight, preferredSize.height);
maxWidth = Math.max(maxWidth, preferredSize.width);
}
Dimension defaultSize = new Dimension(maxWidth, maxHeight);
Point point = offsetForAnchor(parent, defaultSize);
int xDelta = 0;
int yDelta = 0;
switch (alignment) {
case HORIZONTAL:
xDelta = getPadding() + defaultSize.width;
break;
case VERTICAL:
yDelta = getPadding() + defaultSize.height;
break;
}
for (Component component : parent.getComponents()) {
component.setSize(defaultSize);
component.setLocation(point);
point = new Point(point.x + xDelta, point.y + yDelta);
}
}
protected Point offsetForAnchor(Container parent, Dimension defaultSize) {
switch (anchor) {
case LEADING:
return leadingOffSet(parent, defaultSize);
case TRAILING:
return trailingOffSet(parent, defaultSize);
case CENTER:
return centerOffSet(parent, defaultSize);
}
return new Point(0, 0);
}
protected Point leadingOffSet(Container parent, Dimension defaultSize) {
Point point = new Point(0, 0);
switch (alignment) {
case HORIZONTAL:
point.x = padding;
point.y = (parent.getHeight() - defaultSize.height) / 2;
break;
case VERTICAL:
point.x = (parent.getWidth() - defaultSize.width) / 2;
point.y = padding;
break;
}
return point;
}
protected Point trailingOffSet(Container parent, Dimension defaultSize) {
Point point = new Point(0, 0);
int componentCount = parent.getComponentCount();
switch (alignment) {
case HORIZONTAL:
int totalWidth = (defaultSize.width * componentCount) + getTotalPadding(parent);
point.x = parent.getWidth() - totalWidth;
point.y = (parent.getHeight() - defaultSize.height) / 2;
break;
case VERTICAL:
int totalHeight = (defaultSize.height * componentCount) + getTotalPadding(parent);
point.x = (parent.getWidth() - defaultSize.width) / 2;
point.y = parent.getHeight() - totalHeight;
break;
}
return point;
}
protected Point centerOffSet(Container parent, Dimension defaultSize) {
Point point = new Point(0, 0);
int componentCount = parent.getComponentCount();
switch (alignment) {
case HORIZONTAL: {
int totalWidth = (defaultSize.width * componentCount) + getTotalPadding(parent);
point.x = (parent.getWidth() - totalWidth) / 2;
point.y = (parent.getHeight() - defaultSize.height) / 2;
}
break;
case VERTICAL: {
int totalHeight = (defaultSize.height * componentCount) + getTotalPadding(parent);
point.x = (parent.getWidth() - defaultSize.width) / 2;
point.y = (parent.getHeight() - totalHeight) / 2;
}
break;
}
return point;
}
}
}
Related
Using the four buttons, the window should be moved in four directions (north, south, east, west) and the window should not leave the screen. This works smoothly to the north and west, but unfortunately not in the other directions. I guess that the error is in the getEffectiveScreenArea method, but I am not sure.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Insets;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
public class MoveWindowGUI extends JFrame {
private JButton moveUp, moveDown, moveLeft, moveRight;
private int x, y;
public MoveWindowGUI(String title) {
super(title);
this.initializeButtons();
this.prepareWindow();
this.addActionListener();
pack();
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
}
private void initializeButtons() {
this.moveUp = new JButton("U");
this.moveDown = new JButton("D");
this.moveLeft = new JButton("L");
this.moveRight = new JButton("R");
}
private void prepareWindow() {
setLayout(new BorderLayout(25, 25));
this.addComponents();
this.centerWindow();
setSize(300, 300);
}
private void centerWindow() {
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension windowSize = getSize();
int centralWidth = (screenSize.width - windowSize.width) / 2;
int centralHeight = (screenSize.height - windowSize.height) / 2;
setLocation(centralWidth, centralHeight);
}
private void addComponents() {
add(this.moveUp, BorderLayout.NORTH);
add(this.moveDown, BorderLayout.SOUTH);
add(this.moveLeft, BorderLayout.WEST);
add(this.moveRight, BorderLayout.EAST);
}
private void addActionListener() {
ActionListener listener = new WindowActionListener();
moveUp.addActionListener(listener);
moveDown.addActionListener(listener);
moveLeft.addActionListener(listener);
moveRight.addActionListener(listener);
}
class WindowActionListener implements ActionListener {
#Override
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
if (command.equals("U")) {
y -= 10;
} else if (command.equals("D")) {
y += 10;
} else if (command.equals("L")) {
x -= 10;
} else if (command.equals("R")) {
x += 10;
}
this.refreshWindow();
}
private void refreshWindow() {
Point lastLocation = getLocation();
Rectangle effectiveScreenArea = getEffectiveScreenArea();
int newX = lastLocation.x + x;
int newY = lastLocation.y + y;
if (newX < effectiveScreenArea.x) {
newX = effectiveScreenArea.x;
} else if (newY < effectiveScreenArea.y) {
newY = effectiveScreenArea.y;
} else if (newX >= effectiveScreenArea.width) {
newX = effectiveScreenArea.width;
} else if (newY >= effectiveScreenArea.height) {
newY = effectiveScreenArea.height;
}
setLocation(newX, newY);
this.resetHeightAndWitdhLocally();
pack();
}
public Rectangle getEffectiveScreenArea() {
int minX = 0, minY = 0, maxX = 0, maxY = 0;
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
int screenDevices = environment.getScreenDevices().length;
for(GraphicsDevice device : environment.getScreenDevices()) {
Rectangle bounds = device.getDefaultConfiguration().getBounds();
minX = Math.min(minX, bounds.x);
minY = Math.min(minY, bounds.y);
maxX = Math.max(maxX, bounds.x + bounds.width);
maxY = Math.max(maxY, bounds.y + bounds.height);
}
return new Rectangle(minX, minY, (maxX - minX) / screenDevices, (maxY - minY) / screenDevices);
}
/*
private Rectangle getEffectiveScreenArea() {
GraphicsConfiguration graphicsConfiguration = getGraphicsConfiguration();
Rectangle bounds = graphicsConfiguration.getBounds();
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets(graphicsConfiguration);
Rectangle effectiveScreenArea = new Rectangle();
effectiveScreenArea.x = bounds.x + screenInsets.left;
effectiveScreenArea.y = bounds.y + screenInsets.top;
effectiveScreenArea.height = bounds.height + screenInsets.top - screenInsets.bottom;
effectiveScreenArea.width = bounds.width - screenInsets.left - screenInsets.right;
return effectiveScreenArea;
}
*/
private void resetHeightAndWitdhLocally() {
x = 0;
y = 0;
}
}
}
I took your code and modified it somewhat. Here's the GUI I created.
I placed the JButtons on a JPanel. Then I placed the JPanel on the JFrame. Generally, it's a good idea to put Swing components on a JPanel, rather than directly on the JFrame.
I cleaned up the WindowActionListener class.
Here's the complete runnable code. I made the WindowActionListener class an inner class so I could post this code as one block.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class MoveWindowGUI implements Runnable {
public static void main(String[] args) {
SwingUtilities.invokeLater(new MoveWindowGUI());
}
private JFrame frame;
#Override
public void run() {
frame = new JFrame("Move Window GUI");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(createMainPanel(), BorderLayout.CENTER);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JPanel createMainPanel() {
JPanel panel = new JPanel(new BorderLayout());
panel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
WindowActionListener listener = new WindowActionListener(this);
JButton upButton = new JButton("Up");
upButton.addActionListener(listener);
panel.add(upButton, BorderLayout.NORTH);
JButton downButton = new JButton("Down");
downButton.addActionListener(listener);
panel.add(downButton, BorderLayout.SOUTH);
JButton leftButton = new JButton("Left");
leftButton.addActionListener(listener);
panel.add(leftButton, BorderLayout.WEST);
JButton rightButton = new JButton("Right");
rightButton.addActionListener(listener);
panel.add(rightButton, BorderLayout.EAST);
Dimension d = panel.getPreferredSize();
d.width = 300;
panel.setPreferredSize(d);
return panel;
}
public JFrame getFrame() {
return frame;
}
public class WindowActionListener implements ActionListener {
private final MoveWindowGUI view;
public WindowActionListener(MoveWindowGUI view) {
this.view = view;
}
#Override
public void actionPerformed(ActionEvent event) {
String command = event.getActionCommand();
int increment = 100;
switch (command) {
case "Up":
refreshWindow(0, -increment);
break;
case "Down":
refreshWindow(0, increment);
break;
case "Left":
refreshWindow(-increment, 0);
break;
case "Right":
refreshWindow(increment, 0);
break;
}
}
private void refreshWindow(int deltaX, int deltaY) {
Rectangle frameArea = view.getFrame().getBounds();
Rectangle screenArea = getEffectiveScreenArea();
int x = frameArea.x;
int y = frameArea.y;
int minX = screenArea.x;
int minY = screenArea.y;
int maxX = screenArea.width - frameArea.width;
int maxY = screenArea.height - frameArea.height;
x += deltaX;
y += deltaY;
x = Math.max(minX, x);
x = Math.min(maxX, x);
y = Math.max(minY, y);
y = Math.min(maxY, y);
view.getFrame().setBounds(new Rectangle(x, y, frameArea.width, frameArea.height));
}
private Rectangle getEffectiveScreenArea() {
int minX = 0, minY = 0, maxX = 0, maxY = 0;
GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment();
int screenDevices = environment.getScreenDevices().length;
for (GraphicsDevice device : environment.getScreenDevices()) {
Rectangle bounds = device.getDefaultConfiguration().getBounds();
minX = Math.min(minX, bounds.x);
minY = Math.min(minY, bounds.y);
maxX = Math.max(maxX, bounds.x + bounds.width);
maxY = Math.max(maxY, bounds.y + bounds.height);
}
return new Rectangle(minX, minY, (maxX - minX) / screenDevices,
(maxY - minY) / screenDevices);
}
}
}
im having trouble finding out a way to merge the two JFrames in the code. I basically need the grid and stuff from one of the JFrames and an extra border around it. Because I need some buttons added to it. Here's the full code:
package opimejpanelit;
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class OpimeJpanelit {
public static JFrame frame;
public static JPanel panel;
public static void main(String[] args) {
frame = new JFrame("Huinjaa");
frame.setSize(1000, 600);
frame.setLocationRelativeTo(null);
new OpimeJpanelit();
//adds JPanel
panel = new JPanel();
frame.add(panel);
panel.setSize(900,600);
frame.setVisible(true);
frame.setResizable(false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
public OpimeJpanelit() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private int columnCount = 9;
private int rowCount = 7;
private java.util.List<Rectangle> cells;
private Point selectedCell;
public TestPane() {
cells = new ArrayList<>(columnCount * rowCount);
MouseAdapter mouseHandler;
mouseHandler = new MouseAdapter() {
#Override
public void mouseMoved(MouseEvent e) {
Point point = e.getPoint();
int width = getWidth();
int height = getHeight();
int cellWidth = width / columnCount;
int cellHeight = height / rowCount;
int column = e.getX() / cellWidth;
int row = e.getY() / cellHeight;
selectedCell = new Point(column, row);
repaint();
}
};
addMouseMotionListener(mouseHandler);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(800, 400);
}
#Override
public void invalidate() {
cells.clear();
selectedCell = null;
super.invalidate();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
int cellWidth = width / columnCount;
int cellHeight = height / rowCount;
int xOffset = (width - (columnCount * cellWidth)) / 2;
int yOffset = (height - (rowCount * cellHeight)) / 2;
if (cells.isEmpty()) {
for (int row = 0; row < rowCount; row++) {
for (int col = 0; col < columnCount; col++) {
Rectangle cell = new Rectangle(
xOffset + (col * cellWidth),
yOffset + (row * cellHeight),
cellWidth,
cellHeight);
cells.add(cell);
}
}
}
if (selectedCell != null) {
int index = selectedCell.x + (selectedCell.y * columnCount);
Rectangle cell = cells.get(index);
g2d.setColor(Color.BLUE);
g2d.fill(cell);
}
g2d.setColor(Color.GRAY);
for (Rectangle cell : cells) {
g2d.draw(cell);
}
g2d.dispose();
}
}
}
I guess, It is not possible to merge two JFrame.
With a look at your code, It looks like you have tried adding up JPanel in the same container, but instead u created a new JFrame for it.
You can try using remove(component) method in JFrame to remove and add components again(If helpful).
If possible, Please provide a better clarity or pictorial representation of what you are trying to achieve.
I want to have a window containing two panels in proportion 3:1 vertically and have the bigger one contain a square panel inside. Additionally I'd like to draw something in the center of the square panel, say circle.
The behavior of my program suggests there is a conflict between the 3:1 proportion and the squareness. While resizing, the shapes are jumping oddly. The end result is incorrect, the first proportion does not hold. In addition the circle is off the center.
I am new to java, therefore I would appreciate any remarks on both what is wrong and how to implement this the correct way.
The result looks like:
I wanted to have: (1) red panel as a square (2) blue panel to be strictly 3 times higher than the green one (3) to have circle in the middle of the red box.
Here is my code:
import java.awt.Color;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class ProportionalPanels
{
private JFrame window = new JFrame("Proportional resizable panels");
private JPanel allContaining = new JPanel( new GridBagLayout() );
private JPanel upper = new JPanel( new GridBagLayout() );
private JPanel lower = new JPanel();
private JPanel square = new JPanel()
{
#Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
Container c = getParent();
if (c != null) {
d = c.getSize();
} else {
return new Dimension(10, 10);
}
int w = (int) d.getWidth();
int h = (int) d.getHeight();
int s = (w < h ? w : h);
return new Dimension(s, s);
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.setColor(Color.GRAY);
int x = this.getWidth(), y = this.getHeight();
g.fillOval(x/2,y/2,x/4,y/4);
}
};
public ProportionalPanels()
{
// setting colors
allContaining.setBackground(Color.WHITE);
square.setBackground(Color.RED);
upper.setBackground(Color.BLUE);
lower.setBackground(Color.GREEN);
// setting upper
upper.add(square);
// setting allContaining
GridBagConstraints g = new GridBagConstraints();
g.gridx = g.gridy = 0;
g.weightx = 1; g.weighty = 0.75;
g.fill = GridBagConstraints.BOTH;
allContaining.add(upper,g);
g.gridy += 1;
g.weighty = 0.25;
g.fill = GridBagConstraints.BOTH;
allContaining.add(lower,g);
window.add(allContaining);
// setting window
window.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
window.setLocationByPlatform(true);
window.pack();
window.setSize(400,200);
window.setVisible(true);
}
public static void main(String[] args)
{
SwingUtilities.invokeLater( new Runnable()
{
public void run()
{
new ProportionalPanels();
}
});
}
}
EDIT
Imagine a simple gui for chess, only for the sake of analogy. A window is spit into two panels, upper one (blue) is to contain the chessboard, the lower one (green) some buttons. The only constraint for these panels is to keep the vertical proportion - the upper one is to be 3x higher than the lower one. Then, going deeper into panel hierarchy, the upper panel contains square panel (red), which is a square, has the height of the upper panel and is horizontally placed in the middle of the upper panel. Extra space is on the left and right of the square panel, adjusts accordingly to keep red panel square and green's height 3 times smaller than the red's. Red panel holds some drawings at its center, here a gray circle, but to keep the chess analogy it can be an image of chessboard or anything else.
I'm not 100% sure I understand the question, however, it's never stopped me before...
Basically, this uses a VERY crude, custom layout manager. It will keep the first and last components sized do 3:1 ratio (width is ratio of the height)
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.LayoutManager;
import java.awt.LayoutManager2;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel master = new JPanel(new PropertionalLayoutManager());
master.add(new TestPane(), "left");
master.add(new DrawPane(), "center");
master.add(new TestPane(), "right");
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(master);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class PropertionalLayoutManager implements LayoutManager {
private Component left;
private Component right;
private Component center;
#Override
public void addLayoutComponent(String name, Component comp) {
if ("center".equals(name)) {
center = comp;
} else if ("left".equals(name)) {
left = comp;
} else if ("right".equals(name)) {
right = comp;
}
}
#Override
public void removeLayoutComponent(Component comp) {
}
public Dimension getSize(Dimension leftSize, Dimension centerSize, Dimension rightSize) {
Dimension size = new Dimension();
if (leftSize != null && right != null) {
int width = leftSize.width;
int height = leftSize.height;
size.width = Math.max(width, rightSize.width) * 2;
size.height = Math.max(height, rightSize.height);
} else if (leftSize != null) {
size.width = leftSize.width;
size.height = leftSize.height;
} else if (right != null) {
size.width = rightSize.width;
size.height = rightSize.height;
}
if (center != null) {
size.width += centerSize.width;
size.height = Math.max(centerSize.height, size.height);
}
return size;
}
#Override
public Dimension preferredLayoutSize(Container parent) {
Dimension leftSize = left == null ? null : left.getPreferredSize();
Dimension centerSize = right == null ? null : right.getPreferredSize();
Dimension rightSize = center == null ? null : center.getPreferredSize();
return getSize(leftSize, centerSize, rightSize);
}
#Override
public Dimension minimumLayoutSize(Container parent) {
Dimension leftSize = left == null ? null : left.getMinimumSize();
Dimension centerSize = right == null ? null : right.getMinimumSize();
Dimension rightSize = center == null ? null : center.getMinimumSize();
return getSize(leftSize, centerSize, rightSize);
}
#Override
public void layoutContainer(Container parent) {
// Get rid of anything else that might have been added...
for (Component comp : parent.getComponents()) {
comp.setBounds(0, 0, 0, 0);
}
int width = parent.getWidth();
int height = parent.getHeight();
int outterWidth = height / (3 / 1);
if (left != null) {
left.setBounds(0, 0, outterWidth, height);
}
if (right != null) {
right.setBounds(width - outterWidth, 0, outterWidth, height);
}
if (center != null) {
center.setBounds(outterWidth, 0, width - (outterWidth * 2), height);
}
}
}
public class DrawPane extends JPanel {
public DrawPane() {
setBackground(Color.BLUE);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - (getWidth() / 4)) / 2;
int y = (getHeight()- (getHeight() / 4)) / 2;
g.setColor(Color.GRAY);
g.fillOval(x, y, getWidth() / 4, getHeight() / 4);
}
}
public class TestPane extends JPanel {
private JLabel size;
public TestPane() {
setBackground(Color.GREEN);
setLayout(new GridBagLayout());
size = new JLabel();
addComponentListener(new ComponentAdapter() {
#Override
public void componentResized(ComponentEvent e) {
size.setText(getWidth() + "x" + getHeight());
}
});
add(size);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 300);
}
}
}
Updated
Something more like ...
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.LayoutManager;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JPanel master = new JPanel(new SquareLayoutManager());
master.setBackground(Color.BLUE);
master.add(new DrawPane());
JPanel green = new JPanel();
green.setBackground(Color.GREEN);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.gridx = 0;
gbc.gridy = 0;
gbc.weightx = 1;
gbc.weighty = 0.66666666666667;
gbc.fill = GridBagConstraints.BOTH;
frame.add(master, gbc);
gbc.gridy++;
gbc.weighty = 0.33333333333333;
frame.add(green, gbc);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class SquareLayoutManager implements LayoutManager {
#Override
public void addLayoutComponent(String name, Component comp) {
}
#Override
public void removeLayoutComponent(Component comp) {
}
#Override
public Dimension preferredLayoutSize(Container parent) {
int width = 0;
int height = 0;
for (Component comp : parent.getComponents()) {
width = Math.max(comp.getPreferredSize().width, width);
height = Math.max(comp.getPreferredSize().width, height);
}
// You could define rows and columns and blah, blah, blah, but I'm to lazy...
return new Dimension(Math.max(width, height) * parent.getComponentCount(), Math.max(width, height));
}
#Override
public Dimension minimumLayoutSize(Container parent) {
return preferredLayoutSize(parent);
}
#Override
public void layoutContainer(Container parent) {
Insets insets = parent.getInsets();
int size = (parent.getHeight() - (insets.bottom + insets.top));
int x = (parent.getWidth() - (insets.left + insets.right) - size) / 2;
int y = insets.top;
for (Component comp : parent.getComponents()) {
comp.setBounds(x, y, size, size);
x += size; // Could define a gap, but, lazy...
}
}
}
public class DrawPane extends JPanel {
public DrawPane() {
setBackground(Color.RED);
}
#Override
public Dimension getPreferredSize() {
return new Dimension(100, 300);
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
int x = (getWidth() - (getWidth() / 4)) / 2;
int y = (getHeight() - (getHeight() / 4)) / 2;
g.setColor(Color.GRAY);
g.fillOval(x, y, getWidth() / 4, getHeight() / 4);
}
}
}
I want customize the JScrollBar Design. I use Mac to develop the app with eclipse. I already tried to scrollPane.getVerticalScrollBar().setBackground(Color.BLACK); but nothing happen.
My code:
scrollPane = new JScrollPane(scriptView);
scrollPane.setBorder(BorderFactory.createEmptyBorder());
scrollPane.getVerticalScrollBar().setUnitIncrement(6);
window.getContentPane().add(scrollPane);
The Object scriptView is from the class JEditorPane.
How it should look:
Thanks for every help.
I guess you are looking for a transparent scrollbar.
This is just presented as an idea(NOT tested code):
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.plaf.basic.*;
public class TranslucentScrollBarTest {
public JComponent makeUI() {
JTextArea cmp = new JTextArea();
String str = "1234567890abcdefghijklmnopqrstuvwxyz";
for(int i=0; i<20; i++) {
cmp.append(str+str+"\n");
}
cmp.setForeground(Color.WHITE);
cmp.setBackground(Color.BLACK);
cmp.setOpaque(true);
JScrollPane scrollPane = new JScrollPane(
cmp, ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS,
ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
scrollPane.setComponentZOrder(scrollPane.getVerticalScrollBar(), 0);
scrollPane.setComponentZOrder(scrollPane.getViewport(), 1);
scrollPane.getVerticalScrollBar().setOpaque(false);
scrollPane.setLayout(new ScrollPaneLayout() {
#Override
public void layoutContainer(Container parent) {
JScrollPane scrollPane = (JScrollPane)parent;
Rectangle availR = scrollPane.getBounds();
availR.x = availR.y = 0;
Insets insets = parent.getInsets();
availR.x = insets.left;
availR.y = insets.top;
availR.width -= insets.left + insets.right;
availR.height -= insets.top + insets.bottom;
Rectangle vsbR = new Rectangle();
vsbR.width = 12;
vsbR.height = availR.height;
vsbR.x = availR.x + availR.width - vsbR.width;
vsbR.y = availR.y;
if(viewport != null) {
viewport.setBounds(availR);
}
if(vsb != null) {
vsb.setVisible(true);
vsb.setBounds(vsbR);
}
}
});
scrollPane.getVerticalScrollBar().setUI(new BasicScrollBarUI() {
private final Dimension d = new Dimension();
#Override protected JButton createDecreaseButton(int orientation) {
return new JButton() {
#Override public Dimension getPreferredSize() {
return d;
}
};
}
#Override protected JButton createIncreaseButton(int orientation) {
return new JButton() {
#Override public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D)g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar)c;
if(!sb.isEnabled() || r.width>r.height) {
return;
}else if(isDragging) {
color = new Color(200,200,100,200);
}else if(isThumbRollover()) {
color = new Color(255,255,100,200);
}else {
color = new Color(220,220,200,200);
}
g2.setPaint(color);
g2.fillRoundRect(r.x,r.y,r.width,r.height,10,10);
g2.setPaint(Color.WHITE);
g2.drawRoundRect(r.x,r.y,r.width,r.height,10,10);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
});
return scrollPane;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new TranslucentScrollBarTest().makeUI());
f.setSize(320, 240);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
Here is an improved version I did for a private project. It also supports horizontal scrollbar.
Code:
import javax.swing.*;
import javax.swing.plaf.basic.BasicScrollBarUI;
import java.awt.*;
/**
* This is an implementation of a JScrollPane with a modern UI
*
* #author Philipp Danner
*
*/
public class ModernScrollPane extends JScrollPane {
private static final long serialVersionUID = 8607734981506765935L;
private static final int SCROLL_BAR_ALPHA_ROLLOVER = 100;
private static final int SCROLL_BAR_ALPHA = 50;
private static final int THUMB_SIZE = 8;
private static final int SB_SIZE = 10;
private static final Color THUMB_COLOR = Color.Black;
public ModernScrollPane(Component view) {
this(view, VERTICAL_SCROLLBAR_AS_NEEDED, HORIZONTAL_SCROLLBAR_AS_NEEDED);
}
public ModernScrollPane(int vsbPolicy, int hsbPolicy) {
this(null, vsbPolicy, hsbPolicy);
}
public ModernScrollPane(Component view, int vsbPolicy, int hsbPolicy) {
setBorder(null);
// Set ScrollBar UI
JScrollBar verticalScrollBar = getVerticalScrollBar();
verticalScrollBar.setOpaque(false);
verticalScrollBar.setUI(new ModernScrollBarUI(this));
JScrollBar horizontalScrollBar = getHorizontalScrollBar();
horizontalScrollBar.setOpaque(false);
horizontalScrollBar.setUI(new ModernScrollBarUI(this));
setLayout(new ScrollPaneLayout() {
private static final long serialVersionUID = 5740408979909014146L;
#Override
public void layoutContainer(Container parent) {
Rectangle availR = ((JScrollPane) parent).getBounds();
availR.x = availR.y = 0;
// viewport
Insets insets = parent.getInsets();
availR.x = insets.left;
availR.y = insets.top;
availR.width -= insets.left + insets.right;
availR.height -= insets.top + insets.bottom;
if (viewport != null) {
viewport.setBounds(availR);
}
boolean vsbNeeded = isVerticalScrollBarfNecessary();
boolean hsbNeeded = isHorizontalScrollBarNecessary();
// vertical scroll bar
Rectangle vsbR = new Rectangle();
vsbR.width = SB_SIZE;
vsbR.height = availR.height - (hsbNeeded ? vsbR.width : 0);
vsbR.x = availR.x + availR.width - vsbR.width;
vsbR.y = availR.y;
if (vsb != null) {
vsb.setBounds(vsbR);
}
// horizontal scroll bar
Rectangle hsbR = new Rectangle();
hsbR.height = SB_SIZE;
hsbR.width = availR.width - (vsbNeeded ? hsbR.height : 0);
hsbR.x = availR.x;
hsbR.y = availR.y + availR.height - hsbR.height;
if (hsb != null) {
hsb.setBounds(hsbR);
}
}
});
// Layering
setComponentZOrder(getVerticalScrollBar(), 0);
setComponentZOrder(getHorizontalScrollBar(), 1);
setComponentZOrder(getViewport(), 2);
viewport.setView(view);
}
private boolean isVerticalScrollBarfNecessary() {
Rectangle viewRect = viewport.getViewRect();
Dimension viewSize = viewport.getViewSize();
return viewSize.getHeight() > viewRect.getHeight();
}
private boolean isHorizontalScrollBarNecessary() {
Rectangle viewRect = viewport.getViewRect();
Dimension viewSize = viewport.getViewSize();
return viewSize.getWidth() > viewRect.getWidth();
}
/**
* Class extending the BasicScrollBarUI and overrides all necessary methods
*/
private static class ModernScrollBarUI extends BasicScrollBarUI {
private JScrollPane sp;
public ModernScrollBarUI(ModernScrollPane sp) {
this.sp = sp;
}
#Override
protected JButton createDecreaseButton(int orientation) {
return new InvisibleScrollBarButton();
}
#Override
protected JButton createIncreaseButton(int orientation) {
return new InvisibleScrollBarButton();
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle trackBounds) {
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) {
int alpha = isThumbRollover() ? SCROLL_BAR_ALPHA_ROLLOVER : SCROLL_BAR_ALPHA;
int orientation = scrollbar.getOrientation();
int x = thumbBounds.x;
int y = thumbBounds.y;
int width = orientation == JScrollBar.VERTICAL ? THUMB_SIZE : thumbBounds.width;
width = Math.max(width, THUMB_SIZE);
int height = orientation == JScrollBar.VERTICAL ? thumbBounds.height : THUMB_SIZE;
height = Math.max(height, THUMB_SIZE);
Graphics2D graphics2D = (Graphics2D) g.create();
graphics2D.setColor(new Color(THUMB_COLOR.getRed(), THUMB_COLOR.getGreen(), THUMB_COLOR.getBlue(), alpha));
graphics2D.fillRect(x, y, width, height);
graphics2D.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
sp.repaint();
}
/**
* Invisible Buttons, to hide scroll bar buttons
*/
private static class InvisibleScrollBarButton extends JButton {
private static final long serialVersionUID = 1552427919226628689L;
private InvisibleScrollBarButton() {
setOpaque(false);
setFocusable(false);
setFocusPainted(false);
setBorderPainted(false);
setBorder(BorderFactory.createEmptyBorder());
}
}
}
public static void main(String[] args) {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setPreferredSize(new Dimension(400, 400));
JPanel content = new JPanel();
content.setBackground(Color.WHITE);
content.setPreferredSize(new Dimension(500, 500));
content.add(new JLabel("test"));
frame.add(new ModernScrollPane(content));
frame.pack();
frame.setVisible(true);
}
}
Custom scrollbar preview :
Custom scrollbar code :
public class CustomScrollBarUI extends BasicScrollBarUI {
private final Dimension d = new Dimension();
#Override
protected JButton createDecreaseButton(int orientation) {
return new JButton() {
private static final long serialVersionUID = -3592643796245558676L;
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected JButton createIncreaseButton(int orientation) {
return new JButton() {
private static final long serialVersionUID = 1L;
#Override
public Dimension getPreferredSize() {
return d;
}
};
}
#Override
protected void paintTrack(Graphics g, JComponent c, Rectangle r) {
}
#Override
protected void paintThumb(Graphics g, JComponent c, Rectangle r) {
Graphics2D g2 = (Graphics2D) g.create();
g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
Color color = null;
JScrollBar sb = (JScrollBar) c;
if (!sb.isEnabled() || r.width > r.height) {
return;
} else if (isDragging) {
color = Color.DARK_GRAY; // change color
} else if (isThumbRollover()) {
color = Color.LIGHT_GRAY; // change color
} else {
color = Color.GRAY; // change color
}
g2.setPaint(color);
g2.fillRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.setPaint(Color.WHITE);
g2.drawRoundRect(r.x, r.y, r.width, r.height, 10, 10);
g2.dispose();
}
#Override
protected void setThumbBounds(int x, int y, int width, int height) {
super.setThumbBounds(x, y, width, height);
scrollbar.repaint();
}
}
Then use it like this:
YOUR_COMPONENT.getVerticalScrollBar().setUI(new CustomScrollBarUI());
Sadly the proposed solutions will break JTable and won't display the table header, but I found this solution that seems to work.
I am trying to create custom layout which allows me to specify width of a component in percentage, and layout components based on that percentage widths. The following is the implementation I ended up with.
The problem I've is, one of the inner most panel' calculated width is not sufficient to hold all of its components in one row, and the below implementation wraps them to next line, but the height of the parent [all container in the hierarchy] is fixed to some pixels [in my case I used 40px], and its not allowing the wrapped components to show.
Can you please suggest a way to fix it...
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.Insets;
import java.awt.LayoutManager2;
import java.awt.Rectangle;
import java.util.LinkedHashMap;
import java.util.Map.Entry;
import javax.swing.BoxLayout;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
/**
* #author Rakesh.A
*
*/
public class Example extends JPanel {
public Example() {
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
for (int i = 0; i < 1; i++) {
JPanel row = new JPanel();
row.setLayout(new PercentageWidthLayout(5, 5));
JPanel column1 = new JPanel();
column1.setOpaque(true);
column1.setBackground(Color.white);
JPanel column2 = createColumn2();
row.add(column1, new MyConstraints(15, false)); // uses 15% of the available size
row.add(column2, new MyConstraints(50, false, true, true)); // uses 50% of the available size and wraps its contents
row.add(new JPanel(), new MyConstraints(25, false)); // uses 25% of the available size
add(row);
}
}
private JPanel createColumn2() {
JPanel column = new JPanel();
column.setOpaque(true);
column.setBackground(Color.green);
column.setLayout(new PercentageWidthLayout(3, 3, 35));
// total percentage is 100% for all the below components
column.add(new MyComponent(30, 28), new MyConstraints(20, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(20, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(20, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
column.add(new MyComponent(30, 28), new MyConstraints(10, true, false, true));
return column;
}
public static void main(final String[] args) {
JDialog dialog = new JDialog();
dialog.setSize(500, 150);
Example content = new Example();
JScrollPane scrl = new JScrollPane(content, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
dialog.getContentPane().add(scrl);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setVisible(true);
}
public static class MyComponent extends JPanel {
private Dimension minSize;
public MyComponent(final int minWidth, final int minHeight) {
minSize = new Dimension(minWidth, minHeight);
setOpaque(true);
setBackground(Color.yellow);
add(new JLabel("Block"));
}
#Override
public Dimension getPreferredSize() {
return minSize;
}
#Override
public Dimension getMaximumSize() {
return minSize;
}
#Override
public Dimension getMinimumSize() {
return minSize;
}
}
public static class PercentageWidthLayout implements LayoutManager2 {
private LinkedHashMap<Component, MyConstraints> components;
private final int leftMargin;
private final int topMargin;
private final int rowHeight;
// default size of the block
public static final Dimension minimumSize = new Dimension(10, 40);
public static final Dimension preferredSize = new Dimension(100, 40);
// default left margin between components
public static final int defaultLeftMargin = 5;
// default bottom margin between components
public static final int defaultTopMargin = 5;
// default row height
public static final int defaultRowHeight = 0;
public PercentageWidthLayout() {
this(defaultLeftMargin, defaultTopMargin);
}
public PercentageWidthLayout(final int leftMargin, final int topMargin) {
this(leftMargin, topMargin, defaultRowHeight);
}
public PercentageWidthLayout(final int leftMargin, final int topMargin, final int rowHeight) {
this.leftMargin = leftMargin;
this.topMargin = topMargin;
this.rowHeight = rowHeight;
components = new LinkedHashMap<Component, MyConstraints>();
}
#Override
public Dimension preferredLayoutSize(final Container parent) {
int maxX = 0;
int maxY = 0;
for (Entry<Component, MyConstraints> compEntry : components.entrySet()) {
Rectangle bounds = compEntry.getKey().getBounds();
maxX = Math.max(maxX, (int) bounds.getMaxX());
maxY = Math.max(maxY, (int) bounds.getMaxY());
}
if (maxX == 0 || maxY == 0) {
return preferredSize;
}
return new Dimension(maxX, maxY);
}
#Override
public Dimension minimumLayoutSize(final Container parent) {
return minimumSize;
}
#Override
public Dimension maximumLayoutSize(final Container target) {
return new Dimension(Integer.MAX_VALUE, Integer.MAX_VALUE);
}
#Override
public void layoutContainer(final Container parent) {
synchronized (parent.getTreeLock()) {
// validate total percentage
validatePercentages();
// calculate available width & height for the components
Insets insets = parent.getInsets();
// available width after removing border space
int maxClientWidth = parent.getWidth() - insets.left - insets.right;
// calculated available width for the components
int clientWidth = maxClientWidth - (parent.getComponents().length * leftMargin);
// calculated available height for the components
int clientHeight = ((rowHeight > 0) ? rowHeight : preferredSize.height) - insets.top - insets.bottom - topMargin * 2;
// layout the components
int x = insets.left + leftMargin;
int y = insets.top + topMargin;
if (clientWidth > 0 && clientHeight > 0) {
for (Component component : parent.getComponents()) {
// get the constraints to be applied
MyConstraints constraints = components.get(component);
// calculate component width according to the given percentage
int componentWidth = clientWidth * constraints.percentage / 100;
// calculate the preferred size of the component
int prefW = component.getPreferredSize().width;
if (constraints.usePreferredSize && componentWidth < prefW) {
// configured to use preferred size if calculated size is less than the
// preferred size
componentWidth = prefW;
}
// calculate the minimum size of the component
int minW = component.getMinimumSize().width;
if (constraints.useMinWidth && componentWidth < minW) {
// configured to use minimum width if calculated size is less than the
// minimum size
componentWidth = minW;
}
// check and wrap component to next row if needed
if (constraints.wrapComponents && x + componentWidth > parent.getWidth()) {
x = insets.left + leftMargin;
y += clientHeight + insets.top;
// update height of the parent component if it doesn fit
// if (parent.getHeight() < y + clientHeight) {
// parent.setSize(parent.getWidth(), parent.getHeight() + rowHeight);
// }
}
component.setBounds(x, y, componentWidth, clientHeight);
// update x coordinate
x += componentWidth + leftMargin;
}
}
}
}
#Override
public void addLayoutComponent(final String name, final Component comp) {
}
#Override
public void removeLayoutComponent(final Component comp) {
components.remove(comp); // remove component from map
}
#Override
public void addLayoutComponent(final Component comp, final Object constraints) {
if (constraints == null || !(constraints instanceof MyConstraints)) {
throw new IllegalArgumentException("Invalid constraints object! - " + constraints);
}
MyConstraints myConstraints = (MyConstraints) constraints;
if (myConstraints.percentage > 100) {
throw new IllegalArgumentException("Invalid percentage value [" + myConstraints.percentage + "]!");
}
components.put(comp, myConstraints);
}
#Override
public float getLayoutAlignmentX(final Container target) {
return 0;
}
#Override
public float getLayoutAlignmentY(final Container target) {
return 0;
}
#Override
public void invalidateLayout(final Container target) {
}
public int getLeftMargin() {
return leftMargin;
}
public int getTopMargin() {
return topMargin;
}
public int getRowHeight() {
return rowHeight;
}
public static Integer calculatePercentage(final float value, final int total) {
return new Integer((int) (value / total * 100));
}
private void validatePercentages() {
int total = 0;
for (Entry<Component, MyConstraints> compEntry : components.entrySet()) {
total += compEntry.getValue().percentage;
}
if (total > 100) {
throw new IllegalArgumentException("Total percentage [" + total + "] of the components in the layout is more than 100!");
}
}
}
/**
* #author Rakesh.A
*
*/
public static class MyConstraints {
public final int percentage;
public final boolean usePreferredSize, useMinWidth, wrapComponents;
public MyConstraints(final int percentage, final boolean usePreferredSize) {
this(percentage, usePreferredSize, false);
}
public MyConstraints(final int percentage, final boolean usePreferredSize, final boolean useMinWidth) {
this(percentage, usePreferredSize, useMinWidth, false);
}
public MyConstraints(final int percentage, final boolean usePreferredSize, final boolean useMinWidth, final boolean wrapComponents) {
this.percentage = percentage;
this.usePreferredSize = usePreferredSize;
this.useMinWidth = useMinWidth;
this.wrapComponents = wrapComponents;
}
}
}
added to this, the root panel is added to a JScrollPane and it also needs to be updated.
Thank you all for your inputs. I opted a workaround for this problem, instead of wrapping the components, I added a horizontal scroll bar :)