Creating Square Buttons in Swing - java

I would like to create something like the following in Swing:
The top part is relatively easy: I can just create a table and display it. What I'm having trouble with is the square plus and minus buttons at the bottom, which are designed to add a new item or remove the selected item respectively. In particular, I haven't been able to make the square shape because on Mac OS X and some other platforms, JButtons are rectangles with rounded corners and I can't find a way to change that. Also, I'm wanting to make sure it's a perfect square and without any space in between buttons.
How can this be accomplished in a cross-platform way on Swing?

JButtons are rectangles with rounded corners and I can't find a way to change that.
Change the Border:
button.setBorder( new LineBorder(Color.BLACK) );
Edit.
Another approach is to create your own icon from an existing button. Something like the following:
JButton button = new JButton("+");
Dimension size = button.getPreferredSize();
size.x += 6;
size.y += 6;
button.setPreferredSize(size);
Rectangle rectangle = new Rectangle(3, 3, size.x - 3, size.y - 3);
ScreenImage buttonImage = ScreenImage(button, rectangle);
ImageIcon icon = new ImageIcon(buttonImage);
JButton plus = new JButton(icon);
plus.setBorder( ... );
The above code should create an image of your button on any platform. I increased the preferred size to avoid taking an image of the border.
You will need to use the Screen Image class.

This is most easily achieved by returning a preferred size that is NxN - where N is the larger of preferred width or height.
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
class SquareButton extends JButton {
SquareButton(String s) {
super(s);
}
#Override
public Dimension getPreferredSize() {
Dimension d = super.getPreferredSize();
int s = (int)(d.getWidth()<d.getHeight() ? d.getHeight() : d.getWidth());
return new Dimension (s,s);
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
JComponent gui = new JPanel(new FlowLayout());
for (int ii=0; ii<5; ii++) {
gui.add(new SquareButton("" + ii));
}
gui.setBorder(new EmptyBorder(4, 8, 4, 8));
JFrame f = new JFrame("Square Buttons");
f.add(gui);
// Ensures JVM closes after frame(s) closed and
// all non-daemon threads are finished
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
// See http://stackoverflow.com/a/7143398/418556 for demo.
f.setLocationByPlatform(true);
// ensures the frame is the minimum size it needs to be
// in order display the components within it
f.pack();
// should be done last, to avoid flickering, moving,
// resizing artifacts.
f.setVisible(true);
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency/initial.html
SwingUtilities.invokeLater(r);
}
}

You can set the size of a button using using setPreferredSize():
JButton button = new JButton("+");
button.setPreferredSize(new Dimension(10, 10));
You might be able to remove the rounded corners using:
button.setBorder(BorderFactory.createEmptyBorder());
If this does not work then you can override the paintComponent() method on JButton.

Well in order to make them square, you have 2 options: 1. Make the button hold an icon image of just a square image of a transparent image. 2. you could set the button dimensions on your own. I am not sure how to set the dimensions, but that is a an option you could choose. You can just create a JToolBar that is set on the BorderLayout.SOUTH end of the window whenever you add, and whatever buttons are added onto that, will be right next to each other. To add the buttons do this:
JButton button1 = new JButton("+");
JButton button2 = new JButton("-");
JToolBar toolbar = new JToolBar();
<JPanel,JFrame,Whatever>.add(toolbar, BorderLayout.SOUTH);
toolbar.add(button1);
toolbar.add(button2);
This will add the toolbar onto the JFrame, JPanel, or whatever you're adding it onto, and it will set it to the bottom of the screen as you see above.
Hope this helps!

Related

Vertical JPanel manual positioning: which layout?

Given my requirements:
Single vertical column of JPanels.
Set the vertical location* of the JPanel without using the properties of a sibling.
Component position and size are fixed when the frame is resized.
Keep other layout aspects automatic (such as preferred size calculation), as much as possible
(*) Location: I mean location as in Component.setLocation(x, y).
is there a solution which is obvious, and if this is GridBagLayout, how to do this?
Details:
I want to put components vertically in a column container (like a vertical Box) by specifying their vertical location only. What is the best way to do this without loosing the other benefits of a layout such as BoxLayout?
In a vertical Box, setting the vertical position of a component must be done using a filler, or by adjusting the size of the component just above, there is no such possibility like:
panel.setLocation(getLocation().x, y)
On the other hand using a no layout container puts on me the task manage:
The initial size of the component
The container resizing events.
Here the solution of null layout is recommended, here this is a custom one, and here this is GridBagLaout. Also MIGLayout appears to be universal one (but I'd prefer no adding another library to my project).
I have written the following program for someone who was also looking for the same requirements.
Note: Make sure to add the first element to 0 position because there will be no more components and no position will be available other than 0, 2nd to 0 or 1, 3rd to 0 or 1 or 2 and so on
public class VerticalList extends JFrame {
JPanel pnl = null;
TextField tf = new TextField(10);
Box center = Box.createVerticalBox();
JScrollPane jsp = new JScrollPane(center);
JPanel ctrl = new JPanel(new FlowLayout());
JButton send = new JButton("Send");
public VerticalList() {
jsp.setAutoscrolls(true);
ctrl.add(send);
ctrl.add(new JLabel("Position:"));
ctrl.add(tf);
Container cnt = getContentPane();
cnt.add(jsp, BorderLayout.CENTER);
cnt.add(ctrl, BorderLayout.SOUTH);
send.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
pnl = new JPanel(new FlowLayout());
pnl.setBorder(BorderFactory.createLineBorder(Color.red));
pnl.add(new JLabel("Added to Position: "+tf.getText()));
pnl.setMaximumSize(new Dimension(Integer.MAX_VALUE, (int)pnl.getPreferredSize().getHeight()));
try{
int index = Integer.parseInt(tf.getText());
center.add(pnl, index);
}catch(Exception ex){
JOptionPane.showMessageDialog(null, "Please Provide a Valid position", "Position Error", JOptionPane.ERROR_MESSAGE);
}
validate();
}
});
setPreferredSize(new Dimension(300, 300));
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
pack();
}
public static void main(String[] args) {
new VerticalList();
}
}

JButton Appears on One Computer, But Not Others (BorderLayout)

I am new to Swing. I am building a JFrame with a JScrollPane inside it using Eclipse IDE. Inside of the JScrollPane is a JPanel in Border Layout. I tried to add a JButton (called "submitAnswers") to the JFrame using the code below, but for some reason the button only appears at the end of the frame on my computer, but not on other computers (my friend tried it on his Mac and I tried it on a separate Windows OS like mine). Some proposed solutions that I have tried and from other sites that have not worked include:
Use the pack() method. Reason: since the preferred size of the JPanel is much longer in height than the JFrame (hence I employed a JScrollPane), packing the JFrame only causes the text to be not visible on the desktop.
Place button on content JPanel. Reason: I don't know. It just wouldn't appear on another desktop computer or my friend's mac computer.
Use BorderLayout.SOUTH instead of BorderLayout.PAGE_END. Reason: There was absolutely no change. The button would still be visible on my computer, but invisible on others.
Place button directly on JFrame. Reason: I don't know.
In addition, my JFrame is nested within a static method; hence, I've only included the relevant code for the specific method I'm having issues with.
Has anyone had this issue before? I would really appreciate your insight.
Code:
public static void createTestPage() {
JFrame testFrame = new JFrame("testing...1,2,3");
//Customizes icon to replace java icon
try {
testFrame.setIconImage(ImageIO.read(new File("src/icon.png")));
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
//Centers location of introFrame to center of desktop
Dimension screenDimensions = Toolkit.getDefaultToolkit().getScreenSize();
testFrame.setLocation(screenDimensions.width / 16,screenDimensions.height / 14);
//Size and display the introFrame.
Insets insets = testFrame.getInsets();
//Format size of screen itself
testFrame.setSize(1200 + insets.left + insets.right,
400 + insets.top + 250 + insets.bottom);
//Temporarily set screen so that it cannot be resized
testFrame.setResizable(false);
//Set background color of testFrame
testFrame.getContentPane().setBackground(new Color(75, 0, 130));
testFrame.setLayout(new BorderLayout());
//Set layout of testFrame
testFrame.setLayout(new BorderLayout(10, 1));
//Test content
JPanel testContentPanel = new JPanel();
testContentPanel.setBackground(new Color(75, 0, 130));
testContentPanel.setSize(new Dimension(900,2060));
testContentPanel.setPreferredSize(new Dimension(900, 2060));
//Test content pane layout
testContentPanel.setLayout(new BoxLayout(testContentPanel, BoxLayout.PAGE_AXIS));
//Create panel to hold instructions text
JPanel instructionsPanel = new JPanel();
instructionsPanel.setBackground(new Color(75, 0, 130));
instructionsPanel.setLayout(new BorderLayout(10,1));
//Create JPanel for submit answers button
JPanel submitAnswersPanel = new JPanel(new BorderLayout());
submitAnswersPanel.setBackground(new Color(75, 0, 130));
submitAnswersPanel.setVisible(true);
//Create button to submit personality test answers
JButton submitAnswers = new JButton("Submit Answers");
submitAnswers.setVisible(true);
submitAnswers.setBorder(new EmptyBorder(10, 400, 10, 400));
//Add submitAnswers button to panel
submitAnswersPanel.add(submitAnswers);
//Add submitAnswersPanel to test content panel
testContentPanel.add(submitAnswersPanel);
//Create scroll pane to allow for scrollable test (contents cannot fit one page)
JScrollPane testScrollPane = new JScrollPane();
testScrollPane.setViewportView(testContentPanel);
//Get rid of horizontal scroll bar and add vertical scrollbar
testScrollPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS);
testScrollPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
//Speed up scrolling
testScrollPane.getVerticalScrollBar().setUnitIncrement(16);
testFrame.add(testScrollPane);
//Experiment to show button
testFrame.setVisible(true);
}
I've refactored your code a little to use method to create the individual components of the GUI. You can find the full code at this ideone link
What I saw when I first copied your code to my machine was that the only thing visible was the button. So I create all the components in their own methods and then added them to the frame and panels using the Border Layout. This then enabled me to put the instructions in the NORTH sections, the button in the SOUTH section and then the main bits would go in the CENTER section.
One thing to note about the sections: (From the documentation)
The components are laid out according to their preferred sizes and the constraints of the container's size. The NORTH and SOUTH components may be stretched horizontally; the EAST and WEST components may be stretched vertically; the CENTER component may stretch both horizontally and vertically to fill any space left over.
So you should add the component you want to scale in size to the CENTER section.
My main method now looks like this:
public static void main(final String[] args) {
final JButton submitAnswers = createSubmitAnswersButton();
final JPanel instructionsPanel = createInstructionsPanel();
final JPanel testContentPanel = createContentPanel();
testContentPanel.add(instructionsPanel, BorderLayout.NORTH);
testContentPanel.add(submitAnswers, BorderLayout.SOUTH);
final JScrollPane scrollingContentPane = createScrollPaneFor(testContentPanel);
final JFrame testFrame = createJFrame();
testFrame.add(scrollingContentPane, BorderLayout.CENTER);
testFrame.setVisible(true);
}

GridLayout hgap vgap "not working" on JPanel?

JPanel grid = new JPanel();
GridLayout layout = new GridLayout (6,7,0,0);
grid.setLayout (layout);
slot = new ImageIcon ("");
for (int x = 0; x < 42; ++x)
{
slotbtn = new JButton(slot);
slotbtn.setContentAreaFilled (false);
//slotbtn.setBorderPainted (false);
slotbtn.setBorder (BorderFactory.createEmptyBorder (0,0,0,0));
slotbtn.setFocusPainted (false);
grid.add(slotbtn);
}
This is the output I get:
I am creating a 6x7 grid. The output I need is for there to be no space in between the rows and columns, everything should be compressed together. I tried pack and it didn't work. What am I doing wrong?
-- I tried FlowLayout but I had to resize the frame and I have other buttons on the frame so I don't think I'd prefer resizing it to make the buttons fit in their proper places.
-- I placed this JPanel inside another jpanel(which uses borderlayout and contains two other panels) and I placed it at the center, the two other panels North and South.
this issue because you divide the grid (the whole size of grid) to 7*6 so if you re-size the window you will see this gaps changed so if you wan't to remove this gab
calculate the size of the window (ex: width = 7* width of your image , hight = 6*hight of your mage)
or re-size your image
JButton employs a margin property to provide additional padding to the content area of the button, you could try using...
slotbtn.setMargin(new Insets(0, 0, 0, 0));
I would also try using something like slotbtn.setBorder(new LineBorder(Color.RED)); to determine if the spacing is from the button, icon or layout
GridLayout will also provide each cell with equal amount of space, based on the available space to the container, this means that the cell may increase beyond the size of the icon.
While a little more work, GridBagLayout would (if configured properly) honour the preferred size of each component.
Have a look at How to use GridBagLayout for more ideas.
I get no margins using your code, with any image I use. Check your image. And maybe post a runnable example replicating the problem. Maybe there's something going on you're not showing us. I'd start by checking the image for margins. Check it against this. If it still has margins, than its your image. Also, Don't set the size to anything! You may be stretching the panel unnecessarily, which will cause the gaps. Also if there an of your other panels are larger than the grip panel, it will also cause it to stretch. But take all your set(Xxx)sizes out and see what happens. Just pack()
import java.awt.GridLayout;
import javax.swing.*;
public class TestButtonGrid {
public TestButtonGrid() {
ImageIcon icon = new ImageIcon(getClass().getResource("/resources/stackoverflow3.png"));
JPanel panel = new JPanel(new GridLayout(6, 7));
for (int i = 0; i < 42; i++) {
JButton slotbtn = new JButton(icon);
slotbtn.setContentAreaFilled(false);
//slotbtn.setBorderPainted (false);
slotbtn.setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
slotbtn.setFocusPainted(false);
panel.add(slotbtn);
}
JFrame frame = new JFrame();
frame.add(panel);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
new TestButtonGrid();
}
}

Overlapping components in JPanel

I have a JButton and a Point (it's motion controlled by leap motion) on the same JPanel.
However, they are overlapping with JButton on top.
Is there a way to have my Point always on top in the JPanel application window?
Here's a code snippet:
public leapPanel()
{
setLayout(null); //18-12-13
setBackground(Color.WHITE);
setVisible(true); //18-12-13
button = new JButton();
button.setBounds(100, 150, 100, 100);
button.setBackground(Color.BLACK);
add(button);
points[nPoints] = new Point(PWIDTH/2, PHEIGHT/2);
nPoints++;
listener = new leapListener(this);
controller = new Controller();
controller.addListener(listener);
}
public Dimension getPreferredSize()
{
return new Dimension(PWIDTH, PHEIGHT);
}
public void paintComponent(Graphics shape)
{
super.paintComponent(shape);
Graphics2D shaped = (Graphics2D)shape;
shaped.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
for(int i=0; i<nPoints; i++)
{
shaped.setColor(Color.ORANGE);
shaped.fillOval(points[i].x, points[i].y, 12, 12);
}
}
private Point2D.Float calcScreenNorm(Hand hand, Screen screen)
/* The dot position is calculated using the screen position that the
user's hand is pointing at, which is then normalized to an (x,y)
value between -1 and 1, where (0,0) is the center of the screen.
*/
{
Vector palm = hand.palmPosition();
Vector direction = hand.direction();
Vector intersect = screen.intersect(palm, direction, true);
// intersection is in screen coordinates
// test for NaN (not-a-number) result of intersection
if (Float.isNaN(intersect.getX()) || Float.isNaN(intersect.getY()))
return null;
float xNorm = (Math.min(1, Math.max(0, intersect.getX())) - 0.5f)*2; // constrain to -1 -- 1
float yNorm = (Math.min(1, Math.max(0, (1-intersect.getY()))) - 0.5f)*2;
return new Point2D.Float(xNorm, yNorm);
} // end of calcScreenNorm()
I have a JButton and a Point (it's motion controlled by leap motion) on the same JPanel.
Not when components are on the same panel. The order of painting is to paint the component first (ie. your paintComponent() method is invoked). Then the child components of the panel are painted (ie. the button is painted). This is how Swing implements the parent/child relationship between components.
Try using two panels. The main panel will have a BorderLayout. Then you can use:
main.add(button, BorderLayout.NORTH);
main.add(leapPanel, BorderLayout.CENTER);
The other option is to try to use the OverlayLayout. It allows you to stack two components on top of one another, although I must admit I have problems controlling the exact location of components when using this layout. The basic code would be:
JPanel main = new JPanel();
main.setLayout( new OverlayLayout(main) );
JPanel buttonPanel = new JPanel();
buttonPanel.add( button );
main.add(buttonPanel);
main.add(leapPanel);
Using the OverlayLayout you may experience weird painting problems with the button. If so then check out the suggestion to override isOptimizedDrawingEnabled() from Overlap Layout.
JPanel main = new JPanel();
main.setLayout(new OverlayLayout(main));
//main.setBackground(Color.WHITE);
setSize(800, 600); //18-12-13
Container con = getContentPane();
con.setBackground(Color.WHITE);
BPanel = new buttonPanel();
panel = new leapPanel();
main.add(BPanel);
main.add(panel);
con.add(main);
This only allows me to show only BPanel on the application window.
What i need is to have both the point(panel) and button(BPanel) to be displayed on the application window with the point always on top.
Correct me if i am missing something here. Thanks!

Is there any 'top to bottom' and 'right to left' in boxlayout?

I have some tables which should draw from right to left and top to bottom at the frame. Right now I used absolute layout and working with coordination. Is there any BoxLayout or any other Java layout can do it? I should mention that the number of tables is dynamic.
My second question is how can I dock these tables to frame? I mean I want when the frame resize, tables keep their positions on the screen.
Most layout managers will respect the orientation of the component:
panel.setComponentOrientation( ComponentOrientation.RIGHT_TO_LEFT );
panel.add(...);
Or you can always just add the components to the beginning of the container
panel.add(component1, 0);
panel.add(component2, 0);
You may want to use a grid if you are arranging things into a table. All of the elements in a grid should be the same size.
To arrange some items vertically where the size of each row can vary, try this:
static JPanel buildPanel() {
JPanel vPanel = new JPanel();
BoxLayout layout = new BoxLayout(vPanel, BoxLayout.Y_AXIS);
vPanel.setLayout(layout);
JPanel[] rowPanels = new JPanel[5];
int counter=1;
for (int i = 0; i < rowPanels.length; i++) {
rowPanels[i] = new JPanel();
rowPanels[i].setLayout(new FlowLayout(FlowLayout.LEFT, 2, 2));
rowPanels[i].add(new JButton("button " + counter++));
rowPanels[i].add(new JButton("Your button " + counter++));
rowPanels[i].add(new JButton("Shabutton"));
vPanel.add(rowPanels[i]);
}
return vPanel;
}
public static void main(String[] args) {
JFrame gridFrame = new JFrame();
gridFrame.add(buildPanel() );
gridFrame.pack();
gridFrame.setVisible(true);
}
You can prevent the whole JFrame from resizing using gridFrame.setResizable(false);
You can prevent sapce from being added between the rows when the window is resized with a method call like this:
rowPanels[i].setMaximumSize(new Dimentsion(400,32));

Categories

Resources