The property margin of a JButton isn't respected when the nimbus look and feel is installed. .
I need some "little" buttons, but nimbus forces the space around button text to be large, so I only get "very large" buttons.
I discovered in nimbus defaults page that there is a property called:
Button.contentMargins
that is preset with large values.
I've tryed to override it with the following code:
UIManager.getDefaults().put("Button.contentMargins", new InsetsUIResource(0,0,0,0));
in the main, just after setting the nimbus look and feel.
But nothing happens, the empty space around buttons text still remains large.
Any idea?
Altering the value of the JComponent.sizeVariant may also be effective, as discussed in Resizing a Component.
on base of thread How to change the background color for JPanels with Nimbus Look and Feel? is possible to change and assign one value for something from Nimbus Defaults,
but are you sure that you needed this output to the GUI, nothing nice
v.s. basic JButton with Nimbus L&F
from code
import java.awt.*;
import javax.swing.*;
import javax.swing.plaf.InsetsUIResource;
public class NimbusJPanelBackGround {
public NimbusJPanelBackGround() {
JButton btn = new JButton(" Whatever ");
JButton btn1 = new JButton(" Whatever ");
JPanel p = new JPanel();
p.add(btn);
p.add(btn1);
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.add(p, BorderLayout.CENTER);
f.setSize(200, 100);
f.setLocation(150, 150);
f.setVisible(true);
}
public static void main(String[] args) {
try {
for (UIManager.LookAndFeelInfo laf : UIManager.getInstalledLookAndFeels()) {
if ("Nimbus".equals(laf.getName())) {
UIManager.setLookAndFeel(laf.getClassName());
UIManager.getLookAndFeelDefaults().put("Panel.background", Color.white);
UIManager.getLookAndFeelDefaults().put("Button.contentMargins", new InsetsUIResource(0,0,0,0));
}
}
} catch (Exception e) {
e.printStackTrace();
}
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
NimbusJPanelBackGround nimbusJPanelBackGround = new NimbusJPanelBackGround();
}
});
}
}
previously +1 for interesting question
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 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).
I am currently working on a project in which users are allowed to choose a Look and Feel.
However, when users choose another Look and Feel and change it back to the original CrossPlatformLookAndFeel, the borders of buttons disappear.
code:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;
public class SSCCE {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
final JFrame frame = new JFrame();
final JButton button = new JButton("Button");
button.setBorder(LineBorder.createBlackLineBorder());
button.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent ev) {
try{
UIManager.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
SwingUtilities.updateComponentTreeUI(frame);
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
SwingUtilities.updateComponentTreeUI(frame);
} catch (Exception ex) {
System.out.println(ex.getMessage());
}
}
});
//
frame.setLayout(new FlowLayout(FlowLayout.CENTER));
frame.add(button);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
As you see, the border disappears after you click the button.
So the question is: can the border be retained after changing the Look and Feel? I know the border will not appear in WindowsLookAndFeel, but is it possible to "reappear" after the Look and Feel is changed back to the default one?
Last time I checked, there were a variety of bugs in PLAFs that caused these types of odd behavior. Especially when changing from the MetaL LAF (but a good swathe are related to Nimbus as well).
The only reliable way to get the app. to change PLAFs is:
Serialize the user's choice of new PLAF (i.e. as a String of the fully qualified class name).
Launch a new process that calls the main(String[]), which would check for the serialized string of the new PLAF to use, and use it.
(Possibly pass the state of the current GUI to the new GUI.)
Close the current GUI.
As you can see, quite a hassle to get an 'absolutely rock solid reliable' PLAF change.
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.
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