I am trying to set up a GUI in Java using the Swing library. I have created a custom button class that has a custom initializer to make things easier. It is below:
public class JTButton extends JButton {
char type;
public JTButton(String title, ActionListener listener, char type) {
super(title);
this.type = type;
addActionListener(listener);
setForeground(Color.BLACK);
setBackground(Color.WHITE);
setFont(new Font("Monospaced", 1, 10));
setBorderPainted(false);
if (type == 'h') {
setFont(new Font("Monospaced", 1, 24));
}
setOpaque(true);
}
public void setColor(Color t, Color b) {
setBackground(b);
setForeground(t);
}
}
However, when I run the program it is showing elipses in my grid of buttons, like below.
16x16 grid
It should look like this (this is the smaller grid):
9x9 grid
I saw some stuff on GetPreferredSize() but haven't been able to make anything work. Let me know what I can do!
Extra info: Running in macOS, the grid is set up in a GridLayout
When I run my program, it shows ellipses in my grid of buttons.
The ellipses are appearing because the buttons are too small for the text to appear.
This is happening because ultimately you're not using Layout Managers correctly, as HovercraftFullOfEels has mentioned. To explain how to use Layout Managers properly is far too big of an answer (and not what I think you're looking for), so instead I will provide you with some quick ways to get rid of the ellipses.
Here are a few ways to remove the ellipses...
"Quick Fix" Solutions:
1. Modify the JButton Margins.
The margins on JButtons are notoriously small. You can resize them to provide extra room for your text to appear.
You can do this in your JTButton constructor by calling...
setMargin(new Insets(0, 0, 0, 0));
Don't forget to import java.awt.Insets;
You can see the documentation for this function here.
2. Make each JButton larger.
Since you are using a GridLayout, you can make each button larger by making your "Grid container" larger. The buttons will stretch out to fill the available space evenly.
Depending on what Layout Manager you're using for the parent of the Grid container, there will be different ways to resize it. It's outside the scope of this answer to go into depth on those.
Related
I am trying to put a border around the buttons inside of my JPanel. I have this:
Border lineBorder = BorderFactory.createLineBorder(Color.black);
welcomePanel.setBorder(lineBorder);
But that only puts the border around my entire application window, which makes sense. I am wanting to be able to place the border where I want.... I did this when placing my buttons in the desired location
button1.setBounds(10, 10, 60, 30);
And I looked in the API and saw a paintBorder method with parameters of int x, int y, int width, int height, which would make sense to me, but I couldn't get it to work.
Any advicewould be appreciated
Start by adding you buttons to another JPanel...
JPanel buttons = new JPanel();
buttons.setLayout(...);
// add buttons...
Set the Border of this panel...
buttons.setBorder(BorderFactory.createLineBorder(Color.black));
Add this to you main container...
welcomePanel.add(buttons);
Pixel perfect layouts are an illusion in modern UI design, you don't control factors like font choices, rendering pipelines, DPI and other factors which will change the requirements needed for each component to be positioned, that is the role of layout managers.
Swing has been designed to work with layout managers, attempting to do without will cause no end of issues and frustration as you try and find more hacks to get around the issues.
You can use things like EmptyBorders to introduce empty space between components or Insets with a GridBagLayout
Current implementation layout:
((EDIT: added
Code: ))
private JPanel panelCenter;
private List<BufferedImage> listCreatedImages;
public ChooseCircuitPanel(List<BufferedImage> listCreatedImages) {
this.listCreatedImages = listCreatedImages;
initiate();
}
private void initiate() {
setLayout(new BorderLayout(50, 50));
panelCenter = new JPanel();
LayoutManager theLayout = new GridLayout(0, 3, 0, 0);
panelCenter.setLayout(theLayout);
panelCenter.setBorder(BorderFactory.createLineBorder(Color.BLACK));
for (BufferedImage bufferedImage : listCreatedImages) {
ImageIcon theImage = new ImageIcon(bufferedImage);
JLabel lblForImage = new JLabel(theImage);
lblForImage.setBorder(BorderFactory.createLineBorder(Color.BLACK));
panelCenter.add(lblForImage);
}
this.add(panelCenter, BorderLayout.CENTER);
}
Situation:
We want to display a race circuit here. A circuit should be displayed by placing standards tiles next to each other. It should be possible to resize the window, and with that, the circuit tiles should also resize.
((EDIT: bit more info: The race circuit data is stored on a server and the desktop application has to translate the data to a visual thing, by placing some standard tiles in the right order. ))
((EDIT: we are not allowed to use any external library. It should be doable by only using Java Swing code.))
I thought about placing the images in a JLabel and placing these JLabels in a panel with GridLayout as layout manager.
Using a GridLayout - I thought - it should be rather easy to get to a solution:
the components in the GridLayout (= JLabels) already scale and do exactly what I want.
Now, it would only be a matter of finding a way to resize the images so they fill the JLabels.
As you can see: right now, the images have a fixed size and don't scale at all.
I browsed a bit and saw lots of solutions that boil down to using Graphics2D and super.paintComponent, etc.
But most of these solutions had nothing to do with a GridLayout.
So conclusive question:
Is there an easier solution aside from using Graphics2D, etc. knowing that I use a GridLayout?
If not, I will of course use Graphics2D, etc. but I'm now just exploring my options. :)
((EDIT: SOLVED The tiles now neatly fit on each other. Don't mind the misalignments, that's our fault.))
There are no Swing components that do what you want so you will need to write your own code.
The easiest approach would be to use Darryl's Stretch Icon on your JLabel.
Or another approach is to create your own custom component that dynamically scales the image as it is painted. Something like the Background Panel which has code that allows you to scale or tile an image.
Given the nature of the view, I would recommend abandoning images altogether and instead implement the rendering in an Icon. Presuming you can make an icon scale with the label.
I'm creating an applet and having problems with the positioning as size of my buttons. I've added two buttons, but the "OK" button seems to position and size itself correctly, but the "CLEAR" button fills the entire applet area behind the "OK" button. Any suggestions as to what is the problem?
#Override
public void init()
{
super.init();
setSize(J_WIDTH, J_HEIGHT);
setLayout(new BorderLayout());
btn_OK = new Button("OK");
btn_CLEAR = new Button("CLEAR");
btn_OK.setBounds(50, 450, 75, 50);
btn_CLEAR.setBounds(125, 50, 75, 50);
add(btn_OK);
add(btn_CLEAR);
btn_OK.addActionListener(this);
btn_CLEAR.addActionListener(this);
}
When using a BorderLayout, you should specify a location where you want to place the component. If you don't, the default is BorderLayout.CENTER. Also, each position can only contain one component. So when you call add(btn_OK), the OK button is added to the center of the panel. But then you replace it with the Clear button by calling add(btn_CLEAR);.
In addition, each position in the BorderLayout takes up a certain amount of space. The component at that position will stretch to fill that space. In particular, the CENTER takes up all remaining space not used by the other positions.
I think that BorderLayout is not what you want here. Check out the Visual Guide to Layout Managers for more information on each LayoutManager. You can also follow the rest of the tutorial trail for details about how to implement each of them.
You should also bookmark and familiarize yourself with the Java API docs. These are an essential tool for every Java programmer and will help you answer many questions on your own.
The text in my JOptionPanes are way to small I was wondering how I could change the font of the text inside the pane. Also, I would like to be set a space between two buttons.
Something like
|Canecl| |DoneSave| |Save|
I guess you mean the fonts on your JButtons inside the JOptionPane are too small.
For that I suggest using Swing Utils by Darryl Burke. Now you can easily do e.g.
for (JButton button : SwingUtils.getDescendantsOfType(JButton.class, pane)) {
button.setFont(new Font("Verdana", Font.BOLD, 32));
}
to set the fonts on all JButtons inside of JOptionPane pane.
If you want to set the font of the JOptionPane message itself, use e.g.
UIManager.put(
"OptionPane.messageFont",
new FontUIResource(new Font("Verdana", Font.BOLD, 32))
);
In regard to the "spacing of buttons" question: I don't know if that can be done without extending & make a customized JOptionPane yourself.
You cannot specify a spacing between just 2 buttons out of 3 (as per the OP's question) but you can increase the size of the spacing between ALL the buttons :
JPanel buttonPanel = (JPanel) myOptionPane.getComponent(1);
BasicOptionPaneUI.ButtonAreaLayout lm2 = (BasicOptionPaneUI.ButtonAreaLayout) buttonPanel.getLayout();
lm2.setPadding(20);
lm2.setSyncAllWidths(false); // buttons will vary in size as needed.
or perhaps something like :
lm2.setPadding(lm2.getPadding() * 2) // double the spacing between ALL buttons.
If there were just 2 buttons, then using these LayoutManager calls you could achieve the desired outcome.
However for varying-sized spaces between the buttons you need to implement your own JDialog where you control the layout of its JPanel yourself.
A JOptionPane is made up of 2 JPanels... one for the message (and icon) itself, and one for the buttons, that's why we getComponent(1) above.
I know the question is 4 years old but I made this answer because I had a similar need today and couldn't find the answer ANYWHERE on Stack overflow or elsewhere.
I need to make a button that will display different things depending on the state if the app. So for example if nothing has been opened its title will be "Lesson Plans" and if project B is open it will be "project B Lesson Plan", I am using the java.awt.Button class for this. My question, is there a way to determine how big the button should be to fit the given text. For example can I somehow get the width of each character in the given font used by the button then multiply this by the characters in the title I want to use? How would I get this character width or is there some better way? Thanks!
Measuring widths of individual characters in particular fonts (not all characters are the same width) gets complicated, especially if you want to take into account the spaces between characters, and add some margin either side so they don't butt up against the edges of the button. (N.B. Others have provided a few ways of doing this more simply than I realized was possible!)
Much better/more usual solution is to let Java do the work for you. If you're using using a java.awt.Button (or javax.swing.JButton), then it will usually automatically size to the text on it. If your particular button is behaving strangely, then you probably have a layout problem. Check the section of the Java tutorial on Layout Managers for more information.
As an example (in Swing, rather than AWT - sorry!), these two buttons end up being the right size for the text on them:
import javax.swing.*;
public class ButtonTest {
public static void main(String[] args) {
JButton button1 = new JButton("Some label");
JButton button2 = new JButton("Some much longer label");
JFrame frame = new JFrame();
JPanel panel = new JPanel();
panel.add(button1);
panel.add(button2);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
If you really do want the size, rather than just letting Java do its best, then I would recommend calling button1.getPreferredSize() and button2.getPreferredSize() after the call to frame.pack().
Just a quick glance at the API Docs shows:
public Rectangle2D getStringBounds(String str, FontRenderContext frc)
in java.awt.Font
Returns the logical bounds of the specified String in the specified FontRenderContext. The
logical bounds contains the origin, ascent, advance, and height, which includes the leading.
So that should help you.
On the awt Button you can call getFontMetrics and then ask for the getStringBounds. This you can then set the preferred size of the button based on this. It won't take into account the extra spacing you'll need for the borders though (which varies depending on platform).
I'd try setting each to the strings in turn, getting the preferred sizes and then just set the preferred size for the largest size.
Have you tried using either getMinimumSize() or getPreferredSize() on the button? I believe one of them will tell you the minimum size the button needs to be to display its label.