I'm facing a problem when applying a native Look & Feel to my JFrame, all text (except HTML formatted JLabel) have an ugly bold font.
The very simple UI in the following code sum up all the differences I can see with this L&F :
import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.UIManager;
public class HelloWorld extends JFrame {
public HelloWorld() {
Box b = Box.createVerticalBox();
// Labels
JLabel bold = new JLabel("I'm bold !");
JLabel notBold = new JLabel("<html><em>I'm not bold !</em></html>");
b.add(bold);
b.add(notBold);
// Scrollbars example
JPanel scrollViewPort = new JPanel();
scrollViewPort.setPreferredSize(new Dimension(400, 400));
JScrollPane scroll = new JScrollPane(scrollViewPort);
b.add(scroll);
add(b, BorderLayout.CENTER);
// Bold menu
JMenuBar menubar = new JMenuBar();
JMenu menu = new JMenu("Menu");
JMenuItem item = new JMenuItem("Item");
menu.add(item);
menubar.add(menu);
setJMenuBar(menubar);
setPreferredSize(new Dimension(200, 200));
pack();
}
public static void setNativeLAF() {
// Native L&F
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (Exception e) {
System.out.println("Unable to set native look and feel: " + e);
}
}
public static void main(String[] args) {
// setNativeLAF();
HelloWorld app = new HelloWorld();
app.setVisible(true);
}
}
See the difference :
with native L&F (GTK+)
with Metal L&F
by commenting out the setNativeLAF() call.
I'm applying the native look and feel right when my application starts, before any window appears. The UIManager gives me GTK+ (com.sun.java.swing.plaf.gtk.GTKLookAndFeel) as the native look and feel, which is ok since i'm using a Gnome 3 desktop.
I have three problems with this right now :
The GTK+ look and feel doesn't looks like the GTK theme (see the scrollbars)
The JMenuBar seems disabled (not the case with the Metal L&F)
The font is bold ! (same problem with Metal L&F, but fixable)
Any help or explanation about why the GTK+ L&F does that on my system whould be appreciated.
Edit: Here is what a "classic" application looks like on my system in eclipse.
I see several things worth mentioning:
You can apply a derived font to a label, as shown below.
The relevant specification for HTML in a component sys "EM basic emphasis typically rendered in an italic font".
See also Initial Threads.
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.Box;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
public class HelloWorld extends JFrame {
public HelloWorld() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
Box b = Box.createVerticalBox();
// Labels
JLabel bold = new JLabel("I'm bold !");
bold.setFont(bold.getFont().deriveFont(Font.BOLD));
JLabel notBold = new JLabel("<html><em>I'm not bold !</em></html>");
b.add(bold);
b.add(notBold);
// Scrollbars example
JPanel scrollViewPort = new JPanel();
scrollViewPort.setPreferredSize(new Dimension(400, 200));
JScrollPane scroll = new JScrollPane(scrollViewPort);
b.add(scroll);
add(b, BorderLayout.CENTER);
// Bold menu
JMenuBar menubar = new JMenuBar();
JMenu menu = new JMenu("Menu");
JMenuItem item = new JMenuItem("Item");
menu.add(item);
menubar.add(menu);
setJMenuBar(menubar);
pack();
setLocationRelativeTo(null);
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
HelloWorld app = new HelloWorld();
app.setVisible(true);
}
});
}
}
Related
I am working on a Java Swing GUI and am having a minor issue with tool tip text on popup menu items.
Basically when you hover over a JMenuItem it is supposed to leave that JMenuItem selected and display the desired tool tip text.
What actually happens is when the tool tip text is made visible a StateChange event seems to cause the relevant JMenuItem to lose selection status and so the tool tip text very quickly disappears. Note that this only happens the first time, if you move your mouse around you can get the JMenuItem to select again and it will also display the tool tip text properly. I could leave this but I was hoping to set a delay through the ToolTipManager's sharedInstance() which at this point would hurt the user-friendly side of things since the user would have to wait twice as long after realizing the issue themselves.
I built a very simple demo that reflects the problem I am seeing, am I missing something or is this just a Java 8 with Mac issue?
import java.awt.Color;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class TestFrame {
static JFrame jf = new JFrame();
public static void main(String[] args){
jf = new JFrame();
JPanel jp = new JPanel();
jp.setBackground(Color.white);
jp.setForeground(Color.black);
JPopupMenu p = new JPopupMenu();
JMenuItem jmi = new JMenuItem("An option");
jmi.setToolTipText("mouse over text");
jmi.addChangeListener(new ChangeListener(){
#Override
public void stateChanged(ChangeEvent e) {
System.out.println("CHANGED by: "+e.getSource().toString());
}});
p.add(jmi);
jp.setComponentPopupMenu(p);
jf.add(jp);
jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jf.setSize(1000, 500);
jf.setPreferredSize(jf.getSize());
jf.setVisible(true);
}
}
For reference, I tried this modified version that runs on the event dispatch thread. It's seems improved, but it still fails intermittently. It looks like a regression.
Console:
$ javac TestFrame.java ; java TestFrame
1.8.0_31
10.9.5
…
Code:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.event.ChangeEvent;
/** #see http://stackoverflow.com/a/28160300/230513 */
public class TestFrame {
public static void main(String[] args) {
System.out.println(System.getProperty("java.version"));
System.out.println(System.getProperty("os.version"));
EventQueue.invokeLater(() -> {
JFrame jf = new JFrame();
JPanel jp = new JPanel();
JPopupMenu p = new JPopupMenu();
JMenuItem jmi = new JMenuItem("An option");
jmi.setToolTipText("Mouse over text");
jmi.addChangeListener((ChangeEvent e) -> {
System.out.println("Changed by: " + e.getSource().toString());
});
p.add(jmi);
jp.setComponentPopupMenu(p);
jf.add(jp);
jf.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
jf.pack();
jf.setSize(320, 240);
jf.setVisible(true);
});
}
}
I'm trying to populate a sub-menu dynamically, and in case there are no elements in it, I want to add a disabled JMenuItem in it with the text "(empty)". However, since the L&F is set to the System L&F (Windows, in my case), the JMenuItem highlights on mouseover. How do I avoid this? It works exactly as desired without setting L&F, but the fact that the L&F is set to that of the system is not something that I can change (since this is part of something larger).
Here's an SSCCE:
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class HelpMenuItem {
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
}
protected static void createAndShowGUI() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException e) {
e.printStackTrace();
}
JFrame frame = new JFrame();
JMenuBar menuBar = new JMenuBar();
menuBar.setVisible(true);
JMenu menu = new JMenu("Test");
JMenu sub = new JMenu("SubMenu");
JMenuItem empty = new JMenuItem("(empty)");
empty.setEnabled(false);
menuBar.add(menu);
menu.add(sub);
sub.add(empty);
frame.setJMenuBar(menuBar);
JPanel panel = new JPanel();
panel.add(new JLabel("Test"));
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
}
You must set the LAF before you create a component. Your SSCCE incorrectly illustrates your problem.
If you do set the LAF first then you will notice a different behaviour on Windows. All you will see is the "focus border" of the menu item being painted.
To disable the painting of the "focus border" you can use the UIManager. You can use:
UIManager.put("MenuItem.disabledAreNavigable", Boolean.FALSE);
For more information about the UIManager, check out UIManager Defaults.
I have a JFrame with it's content pane. JMenuBar is docked on the north of the pane and JLabel (status bar of sorts) on the south.
In the middle is a JTabbedPane. Each tab is a "document". It contains a JScrollBar and a JPanel in it's viewport.
It goes on and on (JPanel of the viewport has more JPanels, that can have more of them, etc...), but for this example, lets just say that that JPanel (in the viewport) can, or cannot fit into the window space (so it cannot, or can force scrollBars to be represented on the screen).
When it fits the window, everyting is fine, but as soon as I set it's height to be too hight to fit inside a window, JMenuBar gets squished on the top.
I'd like to prevent that (without having to specify the absolute height for the JMenuBar, it'd probably work, but it's kind of cheap), since it shouldn't happen in the first place.
Here's SCCE (It's not really short, but you only need to look at the lines 37 to 117, and I have marked all the lines that have something to do with layout with //TODO). Also, to see when problem occurs or when it doesn't occur, change height value in the line 88 inbetween 2000 and 200. You also need a MiG Layout library, of course.
Here's the code:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.ResourceBundle;
import javax.swing.BorderFactory;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.KeyStroke;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UIManager.LookAndFeelInfo;
import javax.swing.UnsupportedLookAndFeelException;
import net.miginfocom.swing.MigLayout;
class Menu extends JMenuBar
{
private static final long serialVersionUID = 1L;
public Menu()
{
JMenu fileMenu = new JMenu("file");
this.add(fileMenu);
}
}
class DisplayGUI
{
JTabbedPane documentSelector;
void addNewDocument(String name)
{
Document newDocument = new Document();
newDocument.addChapter(new Chapter(), 1);
documentSelector.add(newDocument, name);
}
public DisplayGUI()
{
JFrame masterWindow = new JFrame("name");
masterWindow.setSize(1100, 800);
masterWindow.setMinimumSize(new Dimension(400, 400));
masterWindow.setLocationRelativeTo(null);
masterWindow.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JPanel rootPanel = new JPanel();
rootPanel.setLayout(new MigLayout()); //TODO Here is layout set for the content pane of the main JFrame
Menu menuBar = new Menu();
rootPanel.add(menuBar, "span, north"); //TODO Here is menu bar added to the JFrame, it's docked north
JLabel statusBar = new JLabel("Welcome to PLabScript editor! Press File>New to create a new file or go to File>Open to open an existing one.");
statusBar.setOpaque(true);
statusBar.setBorder(BorderFactory.createLoweredSoftBevelBorder());
rootPanel.add(statusBar, "span, south"); //TODO Here is status bar added to the JFrame, it's docked south
documentSelector = new JTabbedPane(JTabbedPane.NORTH); //TODO JTabbedPane set so the tab chooser is on the top
rootPanel.add(documentSelector, "grow, push"); //TODO setup so it will take up all the remaining space
addNewDocument("Brand new document");
masterWindow.setContentPane(rootPanel);
masterWindow.setVisible(true);
}
}
class Document extends JScrollPane
{
private static final long serialVersionUID = 1L;
JPanel basePanel;
//methods
void addChapter(Chapter chapter, int index)
{
basePanel.add(chapter, "grow, push, h 2000", index-1); //TODO this here adds a chapter to the basePanel of the JScrollPane which is the a representative of a single document
//TODO it height is set to 2000 (and the problem occurs), but if you reduce it enough so it fits the window, problem will dissaper
}
//constructors
public Document()
{
super(ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED, ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
getVerticalScrollBar().setUnitIncrement(20);
basePanel = new JPanel();
basePanel.setBackground(Color.RED);
basePanel.setLayout(new MigLayout("insets 0")); //TODO "insets 0" is so there is no border thingy around all of the child components
setViewportView(basePanel);
}
}
class Chapter extends JPanel
{
private static final long serialVersionUID = 1L;
//constructors
Chapter()
{
setLayout(new MigLayout("insets 0")); //TODO "insets 0" is so there is no border thingy around all of the child components
setBackground(Color.MAGENTA);
}
}
public class Main
{
public static ResourceBundle language;
static boolean setUpLAF()
{
for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels())
{
if ("Nimbus".equals(info.getName()))
{
try
{
UIManager.setLookAndFeel(info.getClassName());
}
catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e)
{
return false;
}
break;
}
}
return true;
}
public static void main(String[] args)
{
//SetUpLookAndFeel
setUpLAF();
//Display actual GUI
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new DisplayGUI();
}
});
}
}
Line 88 should read:
basePanel.add(chapter, "grow, push", index-1); //TODO this here adds a chapter to the basePanel of the JScrollPane which is the a representative of a single document
Line 100 should read:
basePanel.setLayout(new MigLayout("fill,insets 0")); //TODO "insets 0" is so there is no border thingy around all of the child components
Try this.
I've added a JMenu to an undecorated JFrame and the JMenuItem is not painted until I move the mouse over the unpainted area. Has anyone seen this problem and know how to fix/circumvent? Here is a reduced test case showing the problem.
import java.awt.Color;
import java.awt.FlowLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
public class TestCase {
public static void main(String[] args) throws Exception {
new JFrame() {{
setJMenuBar(new JMenuBar() {{
setOpaque(true);
add(new JMenu("ProblemMenu") {{
setOpaque(true);
add(new JMenuItem("NotPainted"){{
setOpaque(true);
}});}});}});
setUndecorated(true);
setBackground(new Color(11,111,222,196));
setSize(300,300);
setLocation(300,300);
getContentPane().setLayout(new FlowLayout());
getContentPane().add(new JButton(" OpaqueButton "));
setVisible(true);
}};
}
}
Click the menu "ProblemMenu" and the menu will open with a white rectangle where the JMenuItem should be located. Move the mouse over that area and the JMenuItem paints.
The per-pixel translucent JFrame menu paint problem was caused by the JRE and fixed by moving to a newer JRE ( 1.7.0_09-b05 ).
It's probably setOpaque() calls in combination with your LAF.
Read this great answer for why setOpaque() is problematic.
setOpaque(true/false); Java
I am creating a Swing Application. I have one main JFrame and a JDesktopPane. I added one button and one label on main frame. But if I open any JInternalFrame on Main Frame button and label covers the internal frame.
(JButtonand JLabel appear foreground of JInternalFrame). If I click internal frame button go to background.
Can you help to solve this?
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Frame;
import java.awt.Point;
import java.awt.Rectangle;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
public class MainFrame {
JFrame frame1 ;
JDesktopPane desktop ;
public MainFrame () {
frame1 = new JFrame("EMPLOYEE LEAVE TRACKER");
frame1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame1.setExtendedState(Frame.MAXIMIZED_BOTH);
frame1.repaint();
desktop = new JDesktopPane(); //Creates a new JDesktopPane.
frame1.setContentPane(desktop);
frame1.setSize(900,700);
frame1.setVisible(true);
desktop.setBackground(Color.DARK_GRAY );
//Creates a JLabel on JDesktopPane.
JLabel label1 = new JLabel("EMPLOYEE LEAVE TRACKER", SwingConstants.CENTER);
label1.setFont(new Font("SansSerif",Font.ITALIC + Font.BOLD,54));
label1.setBounds(new Rectangle(new Point(275, 100),label1.getPreferredSize()));
//Creates a JButon on JDesktopPane.
JButton Leave = new JButton("Leave Management");
Leave.setHorizontalTextPosition(JButton.CENTER);
Leave.setBounds(new Rectangle(new Point(700,200),Leave.getPreferredSize()));
Leave.setSize(300, 300);
Leave.addActionListener(new java.awt.event.ActionListener() {
#Override
public void actionPerformed(java.awt.event.ActionEvent e) {
frame1.add(LeaveManagment());
}
});
//Look and Feel
try {
UIManager.setLookAndFeel("javax.swing.plaf.nimbus.NimbusLookAndFeel");
} catch(Exception e) {
System.out.println("Error setting native LAF: " + e);
}
desktop.add(Leave);
desktop.add(label1);
}
//Creating JInternalFrame
public JInternalFrame LeaveManagment(){
final JInternalFrame employeeFrame = new JInternalFrame("LEAVE M" +
"ANAGEMNT", true, true, true, true);
employeeFrame.getContentPane().setBackground(Color.white);
employeeFrame.setSize(900,700);
employeeFrame.setVisible(true);
employeeFrame.setMaximizable(true);
employeeFrame.setResizable(true);
JComponent c = (JComponent)
employeeFrame.getContentPane();
c.setLayout(new FlowLayout());
return employeeFrame;
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
new MainFrame ();
}
});
}}
From the sound of it, you've added the buttons to the JDesktopPane.
The desktop pane is a type of JLayeredPane, this allows you to place components on, we'll, layers.
While this is a neat feature, IMHO, only JInternalFrames and the occasional special "window" should appear on the desktop (although the desktop manager does use a type of button to represent minimised windows)
Personally, I'd place the buttons also where, not on the desktop.
Take a look at How to Use Internal Frames and How to use Layered Pane
MadProgrammer has it right. One solution is to add your components to the appropriate JLayeredPane layer. i.e.,
// Note name change of JButton to adhere to Java naming standards:
desktop.add(leaveManagementBtn, JLayeredPane.DEFAULT_LAYER);
desktop.add(label1, JLayeredPane.DEFAULT_LAYER); // note layer component being added to
and,
public void actionPerformed(java.awt.event.ActionEvent e) {
// again method name capitalization changed to adhere to standard
// again, component added to appropriate layer
frame1.add(leaveManagment(), JLayeredPane.PALETTE_LAYER);
}
Again, MadProgrammer is right, the buttons should not be on the JDesktopFrame but on a button bar off of the desktop. I recommend that you accept his answer.