I need to put some JButtons in a very small place, and the problem is that the Nimbus LAF automatically puts some space around them, and as a result the buttons look smaller than they really are.
In the following example program I use a FlowLayout with 0 horizontal and vertical gaps, and I expected the buttons to sit tightly without any space between them. If I comment out the setting of the Nimbus LAF, they behave as expected.
import javax.swing.*;
import java.awt.FlowLayout;
public class NimbusSpace {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
buildGUI();
}
});
}
private static void buildGUI() {
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
JFrame f = new JFrame("Test");
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
p.add(createButton("aa"));
p.add(createButton("bb"));
p.add(createButton("cc"));
f.add(p);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
}
private static JButton createButton(String text) {
JButton b = new JButton(text);
// b.setBorder(null);
// b.setBorderPainted(false);
// b.setMargin(new Insets(0,0,0,0));
// b.putClientProperty("JComponent.sizeVariant", "large");
// b.putClientProperty("JComponent.sizeVariant", "mini");
// UIDefaults def = new UIDefaults();
// def.put("Button.contentMargins", new Insets(0,0,0,0));
// b.putClientProperty("Nimbus.Overrides", def);
return b;
}
}
As you can see in the commented out code in createButton, I tried quite a few things, but they didn't remove the space around the buttons.
EDIT: Based on the discussions in the comments, it seems that it is not possible to remove the space between the rectangular edges of the button and the drawn rounded-rectangle outline. Nimbus reserves these two pixels for the "focus highlight", and probably this cannot be changed without re-implementing a lot of Nimbus functionality.
So I accepted guleryuz's trick: if the buttons are positioned at overlapping and negative positions, they can look bigger. In practice this idea seems to work, but it is not a very clean solution, so if you know a better (and reasonably easily implemented) solution, don't hesitate to answer...
approach 1:
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, -4, 0));
approach 2:
JPanel p = new JPanel(new FlowLayout(FlowLayout.LEFT, 0, 0));
p.add(createButton("aa", 1));
p.add(createButton("bb", 2));
p.add(createButton("cc", 3));
with some modifications in createButton method
private static JButton createButton(String text, final int s) {
JButton b = new JButton(text){
#Override
public void setLocation(int x, int y) {
super.setLocation(x-(s*4), y);
}
};
return b;
}
approach 3
JPanel p = new JPanel(new MigLayout("ins 0, gap -5","[][][]"));
Note that if you set the background color and then call setOpaque(true), you can see that the buttons ARE right up against each other. That's just how Nimbus draws a button; I don't think you can change the space between the rectangular edges of the button and the drawn rounded-rectangle outline.
If space is a premium, you can shrink the size a bit by uncommenting your UIDefaults lines and modifying the contentMargins property (but don't use 0,0,0,0, use something like 2,8,2,8).
Related
I can't get the standard BorderFactory.createEmptyBorder working properly in Java Swing.
I tried it with a simple Java app that creates a Spinner View and declares an empty border around it. The border is shown everywhere except for the right side of the spinner view. but that only happened in Windows, on OSX it works as intended.
To clarify the use of a border: In my real application I have a visible border at the outside of the spinner and then I want to center the text inside. I found the createCompoundBorder property very useful for that.
import javax.swing.*;
import java.awt.*;
import javax.swing.border.Border;
class HelloWorldSwing {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {}
Runnable guiCreator = new Runnable() {
public void run() {
JFrame fenster = new JFrame("Hallo Welt mit Swing");
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SpinnerNumberModel model = new SpinnerNumberModel(1,1,9,1);
JSpinner spinner = new JSpinner(model);
JFormattedTextField textField = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
textField.setOpaque(true);
// textField.setBackground(Color.);
spinner.setBorder(BorderFactory.createEmptyBorder(50, 100, 50, 100));
spinner.setUI(new javax.swing.plaf.basic.BasicSpinnerUI() {
protected Component createNextButton() {
Component c = new JButton();
c.setPreferredSize(new Dimension(0, 0));
c.setFocusable(false);
return c;
}
protected Component createPreviousButton() {
Component c = new JButton();
c.setPreferredSize(new Dimension(0, 0));
c.setFocusable(false);
return c;
}
});
spinner.setBackground(Color.LIGHT_GRAY);
fenster.add(spinner);
fenster.setSize(300, 200);
fenster.setVisible(true);
}
};
SwingUtilities.invokeLater(guiCreator);
}
}
=
I don't want to find a solution that implements one more UI element. This would be an easy and simple solution (Thanks to Andrew Thompson). The reason is that it is just a small project where I got into this error. In small projects I mostly want a clean and good looking code, which means that such bugs are fixed by trying to fix the broken code and not by doing a workaround.
It looks like a JSpinner is using a custom layout manager and is not handling the Border correctly.
I modified your code to give the buttons the width of the right edge of the border minus 1. I guess the layout manager leaves a 1 pixel gap between the edge of the text field and the button.
Seems to work on Windows, but it might mess up OSX?
import javax.swing.*;
import java.awt.*;
import javax.swing.border.Border;
class HelloWorldSwing {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {}
Runnable guiCreator = new Runnable() {
public void run() {
JFrame fenster = new JFrame("Hallo Welt mit Swing");
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
SpinnerNumberModel model = new SpinnerNumberModel(1,1,9,1);
JSpinner spinner = new JSpinner(model);
JFormattedTextField textField = ((JSpinner.DefaultEditor)spinner.getEditor()).getTextField();
textField.setOpaque(true);
// textField.setBackground(Color.);
spinner.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 0));
spinner.setUI(new javax.swing.plaf.basic.BasicSpinnerUI() {
protected Component createNextButton() {
Component c = new JButton();
c.setPreferredSize(new Dimension(9, 0));
c.setVisible(false);
return c;
}
protected Component createPreviousButton() {
Component c = new JButton();
c.setPreferredSize(new Dimension(9, 0));
c.setVisible(false);
return c;
}
});
spinner.setBackground(Color.LIGHT_GRAY);
fenster.setLayout( new FlowLayout() );
fenster.add(spinner);
fenster.setSize(300, 200);
fenster.setVisible(true);
}
};
SwingUtilities.invokeLater(guiCreator);
}
}
The other solution is to not use a JSpinner. You could easily use a JTextField and write a custom Action for the Up/Down arrows. A little more work but it will work on all platforms.
Also since you seems to be worried about creating extra components this will be far more efficient in that regard. The JSpinner is a complex component itself and the JFormattedTextField is far more complex than a simple JTextField.
I created a website that acts as a software.
Now i'm trying to do the exact same thing with Java.
is there a way to draw some objects like "div" in html, that i can change x and y position (absolute), background-image, background-color, and put other object into it, [...] with Java ?
I tried this code :
import javax.swing.*;
import javax.swing.border.*;
import javax.accessibility.*;
import java.awt.*;
import java.awt.event.*;
/*
* LayeredPaneDemo.java requires
* images/dukeWaveRed.gif.
*/
public class Demo extends JPanel implements ActionListener, MouseMotionListener{
private String[] layerStrings = { "Yellow (0)", "Magenta (1)",
"Cyan (2)", "Red (3)",
"Green (4)" };
private Color[] layerColors = { Color.yellow, Color.magenta,
Color.cyan, Color.red,
Color.green };
private JLayeredPane layeredPane;
private JLabel dukeLabel;
private JCheckBox onTop;
private JComboBox layerList;
//Action commands
private static String ON_TOP_COMMAND = "ontop";
private static String LAYER_COMMAND = "layer";
//Adjustments to put Duke's toe at the cursor's tip.
private static final int XFUDGE = 40;
private static final int YFUDGE = 57;
public Demo() {
setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS));
//Create and load the duke icon.
final ImageIcon icon = createImageIcon("images/dukeWaveRed.gif");
//Create and set up the layered pane.
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 310));
layeredPane.setBorder(BorderFactory.createTitledBorder(
"Move the Mouse to Move Duke"));
layeredPane.addMouseMotionListener(this);
//This is the origin of the first label added.
Point origin = new Point(10, 20);
//This is the offset for computing the origin for the next label.
int offset = 35;
//Add several overlapping, colored labels to the layered pane
//using absolute positioning/sizing.
for (int i = 0; i < layerStrings.length; i++) {
JLabel label = createColoredLabel(layerStrings[i], layerColors[i], origin);
layeredPane.add(label, new Integer(i));
origin.x += offset;
origin.y += offset;
}
//Create and add the Duke label to the layered pane.
dukeLabel = new JLabel(icon);
if (icon != null) {
dukeLabel.setBounds(15, 225, icon.getIconWidth(), icon.getIconHeight());
} else {
System.err.println("Duke icon not found; using black square instead.");
dukeLabel.setBounds(15, 225, 30, 30);
dukeLabel.setOpaque(true);
dukeLabel.setBackground(Color.BLACK);
}
layeredPane.add(dukeLabel, new Integer(2), 0);
//Add control pane and layered pane to this JPanel.
add(Box.createRigidArea(new Dimension(0, 10)));
add(createControlPanel());
add(Box.createRigidArea(new Dimension(0, 10)));
add(layeredPane);
}
/** Returns an ImageIcon, or null if the path was invalid. */
protected static ImageIcon createImageIcon(String path) {
java.net.URL imgURL = Demo.class.getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
//Create and set up a colored label.
private JLabel createColoredLabel(String text, Color color, Point origin) {
JLabel label = new JLabel(text);
label.setVerticalAlignment(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setOpaque(true);
label.setBackground(color);
label.setForeground(Color.black);
label.setBorder(BorderFactory.createLineBorder(Color.black));
label.setBounds(origin.x, origin.y, 140, 140);
return label;
}
//Create the control pane for the top of the frame.
private JPanel createControlPanel() {
onTop = new JCheckBox("Top Position in Layer");
onTop.setSelected(true);
onTop.setActionCommand(ON_TOP_COMMAND);
onTop.addActionListener(this);
layerList = new JComboBox(layerStrings);
layerList.setSelectedIndex(2); //cyan layer
layerList.setActionCommand(LAYER_COMMAND);
layerList.addActionListener(this);
JPanel controls = new JPanel();
controls.add(layerList);
controls.add(onTop);
controls.setBorder(BorderFactory.createTitledBorder("Choose Duke's Layer and Position"));
return controls;
}
//Make Duke follow the cursor.
public void mouseMoved(MouseEvent e) {
dukeLabel.setLocation(e.getX()-XFUDGE, e.getY()-YFUDGE);
}
public void mouseDragged(MouseEvent e) {} //do nothing
//Handle user interaction with the check box and combo box.
public void actionPerformed(ActionEvent e) {
String cmd = e.getActionCommand();
if (ON_TOP_COMMAND.equals(cmd)) {
if (onTop.isSelected())
layeredPane.moveToFront(dukeLabel);
else
layeredPane.moveToBack(dukeLabel);
}
else if (LAYER_COMMAND.equals(cmd)) {
int position = onTop.isSelected() ? 0 : 1;
layeredPane.setLayer(dukeLabel,layerList.getSelectedIndex(),position);
}
}
/**
* Create the GUI and show it. For thread safety,
* this method should be invoked from the
* event-dispatching thread.
*/
private static void createAndShowGUI() {
//Create and set up the window.
JFrame frame = new JFrame("LayeredPaneDemo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Create and set up the content pane.
JComponent newContentPane = new Demo();
newContentPane.setOpaque(true); //content panes must be opaque
frame.setContentPane(newContentPane);
//Display the window.
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
}
This is the result :
It looks to run, but I can not put JLabel into JLabel (will have i to create my own object ? with a JLabel and with sons ?
And finally when i put an addMouseListener to a JLabel , if an other JLabel is above it, i can click it through the other :-/
Use JavaFX with Java 8.
It is a bit slower in development until learned. Due to lambdas and component complexity.
The styling can be done with CSS.
There are animated effects.
Since the question targets Swing, I'll add a Swing-oriented answer anyway for the people who find this question and really must use Swing for any reason.
The trick is to use a fitting look & feel to do it for you in Swing.
Swing tutorial documentation on the subject.
That alone doesn't answer the question as this is about make it pretty and the default look & feel selections are not exactly all that great to look at / didn't stand the test of time. But there are also third party look & feels available for download, you're not necessarily limited to what is bundled with the runtime by default.
As an example, one can use Insubstantial (formerly known as Substance) to pretty up Swing applications. It is too naive to think that you can just plop this look & feel into an existing program and make it look good in an instant, but when you design your application with one of these look & feels from the beginning, the application can look very slick indeed.
But one should really use Swing only when it is a must. Swing is an aging technology and whatever extensions were available for download for it in its glory days are slowly disappearing from the internet / no longer maintained. On top of that it is basically the difference between choosing a pre-designed look & feel or having flexibility to do styling yourself, which JavaFX allows you to do with quite some flexibility.
When I use a JComboBox on Windows 7, the four corners each have a pixel that doesn't match the background colour of the parent component.
In Windows 8 this problem doesn't happen (although that could be because in Windows 8, the JComboBox is rendered as a perfect rectangle). Nor does it happen on OS X.
What can I do to make the corner pixels let the background colour of the parent component through?
Here's an image showing the problem:
Here's a self-contained code example I'm using:
import com.sun.java.swing.plaf.windows.WindowsLookAndFeel;
import javax.swing.*;
import java.awt.*;
public class Main {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
try {
UIManager.setLookAndFeel(new WindowsLookAndFeel());
} catch (Exception e) {
e.printStackTrace();
}
JPanel contentPane = new JPanel();
contentPane.setBackground(Color.WHITE);
JComboBox<String> comboBox = new JComboBox<String>(new String[]{"One", "Two"});
contentPane.add(comboBox);
JFrame frame = new JFrame("JComboBox Test");
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setContentPane(contentPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
Try removing the border...
comboBox.setBorder(null);
The next choice would be to design a specialised look and feel delegate that achieved what you wanted on Windows...
For example...
public static class MyComboBoxUI extends WindowsComboBoxUI {
#Override
protected void installDefaults() {
super.installDefaults();
LookAndFeel.uninstallBorder(comboBox);
}
public static ComponentUI createUI(JComponent c) {
return new MyComboBoxUI();
}
}
And then install it using...
UIManager.put("ComboBoxUI", MyComboBoxUI.class.getName());
This will mean you won't need to remove the borders from every combo box you create
Or, you could simply override the default border property in the UIManager...
UIManager.put("ComboBox.border", new EmptyBorder(0, 0, 0, 0));
Either way, it will effect all combo boxes created after you apply it...
First thing I would try is setOpaque(false) on the JComboBox.
Also you should not set the WindowLookAndFeel directly. Instead set the System default L&F:
// force platform native look & feel
try {
final String className = UIManager.getSystemLookAndFeelClassName();
UIManager.setLookAndFeel(className);
} catch (final Exception e) {
// ignore
}
That will always set the OS's default look and feel, regardless of what OS you're running on.
I'm creating a text field in java using swing components. I want to make a search text field like one appears in Mozilla or other browsers.
I have added a button in text field. I have set border layout of JTextField. everything is working fine but whenever large text is written in text field (as it reaches the given size of text field) it goes behind the button. As everyone of you must have seen, this does not occur in search bars. Text must not go behind the button rather there must be some gap between button and text.
Does anyone know how to do that?
Maybe start with something like this:
The blinking cursor is positioned at the far right of the text field.
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
class ButtonsInTextField {
JPanel gui = new JPanel(new GridBagLayout());
JTextField textField;
ButtonsInTextField(int cols) {
JPanel textFieldWithButtonsPanel = new JPanel(new FlowLayout(
SwingConstants.LEADING, 5, 1));
textField = new JTextField(cols);
textFieldWithButtonsPanel.add(textField);
addButtonToPanel(textFieldWithButtonsPanel, 8);
addButtonToPanel(textFieldWithButtonsPanel, 16);
addButtonToPanel(textFieldWithButtonsPanel, 24);
// WARNING: Not sensitive to PLAF change!
textFieldWithButtonsPanel.setBackground(textField.getBackground());
textFieldWithButtonsPanel.setBorder(textField.getBorder());
textField.setBorder(null);
// END WARNING:
gui.add(textFieldWithButtonsPanel);
}
private final void addButtonToPanel(JPanel panel, int height) {
BufferedImage bi = new BufferedImage(
// find the size of an icon from the system,
// this is just a guess
24, height, BufferedImage.TYPE_INT_RGB);
JButton b = new JButton(new ImageIcon(bi));
b.setContentAreaFilled(false);
//b.setBorderPainted(false);
b.setMargin(new Insets(0,0,0,0));
panel.add(b);
}
public final JComponent getGui() {
return gui;
}
public final JTextField getField() {
return textField;
}
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
ButtonsInTextField bitf = new ButtonsInTextField(20);
JOptionPane.showMessageDialog(null, bitf.getGui());
}
};
// Swing GUIs should be created and updated on the EDT
// http://docs.oracle.com/javase/tutorial/uiswing/concurrency
SwingUtilities.invokeLater(r);
}
}
As people have noted above, it might have helped to see the code, especially the Layout manager.
However, you might try the following (if you haven't yet):
Call setColumns
http://docs.oracle.com/javase/7/docs/api/javax/swing/JTextField.html#setColumns(int)
Call setPreferredSize /setMaximumSize/setMinimumSize depending on your layout manager.
But I'd try to avoid this solution because it's pixel-level maintenance.
Regards
As an alternative solution you can use a Component Border, which allows you to use the button as a Border so it appears within the text field.
How to change Look and Feel for the ToolBar, the top menu (where the buttons to close, minimize, maximize)
Is it possible to like something change? (Add, delete button, assign a background)
What is import is required to create it?
you can set the background image of a JButton you could have a look at this: Swing Tutorial: JButton which shows the use of the new JButton(String text,ImageIcon imgIco) to create a JButton with an ImageIcon and String.
To set the colour of the background and text you could use setBackground(Color c) and setForeground(Color c)
or
Alternatively just customize Look and Feel color scheme by setting an appropriate supported Look and Feel and then change the color scheme/size etc of its components thier are hundreds of things you can change for every component see this for them all.
To customize the Exit, Minimize and Maximize Toolbar buttons this can also be using the Look and Feel ( Custom design for Close/Minimize buttons on JFrame ):
import java.awt.BorderLayout;
import javax.swing.*;
public class FrameCloseButtonsByLookAndFeel {
FrameCloseButtonsByLookAndFeel() {
String[] names = {
UIManager.getSystemLookAndFeelClassName(),
UIManager.getCrossPlatformLookAndFeelClassName()
};
for (String name : names) {
try {
UIManager.setLookAndFeel(name);
} catch (Exception e) {
e.printStackTrace();
}
// very important to get the window decorations.
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame f = new JFrame(UIManager.getLookAndFeel().getName());
f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
JPanel gui = new JPanel(new BorderLayout());
f.setContentPane(gui);
JTree tree = new JTree();
tree.setVisibleRowCount(4);
gui.add(tree, BorderLayout.LINE_START);
gui.add(new JScrollPane(new JTextArea(3,15)));
JToolBar toolbar = new JToolBar();
gui.add(toolbar, BorderLayout.PAGE_START);
for (int ii=1; ii<5; ii++) {
toolbar.add(new JButton("Button " + ii));
if (ii%2==0) {
toolbar.addSeparator();
}
}
f.pack();
f.setLocationByPlatform(true);
f.setVisible(true);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new FrameCloseButtonsByLookAndFeel();
}
});
}
}
Well the easiest way to change frame titlebar look is to set LookAndFeel before you create your frame.
Probably this is what you are looking for - http://www.jtattoo.net/ScreenShots.html