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.
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 want to show JLabel but want to hide JFrame border and other lower level containers like JPanel.
It just JLabel displayed on the screen.
I tried window transparency but following piece of code hides everything if trying to work with window opacity.
On decreasing windowOpacity , even JLabel becomes blurred. I tried with JPanel as well but couldn't get exact output.
I want this behaviour in jdk1.6 only
I want the JLabel content to be visible properly without any opacity impact but backbround must be purely transparent.
public class TEST {
public static void main(String[] args) {
JFrame frame = new JFrame("Sanjaal Corps - Windows On Top Demo!");
frame.setSize(400, 100);
frame.setLocation(100, 150);
com.sun.awt.AWTUtilities.setWindowOpacity(frame,0.4f);
frame.setUndecorated(true);
frame.add(new JLabel("TESTING"));
frame.setAlwaysOnTop(true);
frame.setVisible(true);
}
}
I tried with solution provided
http://www.dreamincode.net/forums/topic/140041-make-a-jpanel-transparent-to-see-the-desktop-behind/
But the problem here is if we minimize or maximize the window , then a constant color being set, So found its not the best solution or may say the Perfect one.
Assuming I understand your requirements correctly...
I typically add a transparent panel to the Window. This means that, generally, the transparency properties of the Window don't then effect the child components, for example...
Generally speaking, there are now two ways to make a window transparent.
Under Java 7, you simply make it's background color transparent.
Under Java 6 (update 10+), you need to use the unofficial com.sun.AWTUtilities class
...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Window;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.lang.reflect.Method;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.LineBorder;
public class TransparentWindow02 {
public static void main(String[] args) {
new TransparentWindow02();
}
public TransparentWindow02() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setUndecorated(true);
setOpaque(frame, false);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
public TestPane() {
setOpaque(false);
setLayout(new BorderLayout());
setBorder(new LineBorder(Color.RED));
JLabel label = new JLabel("Click me if you can see me");
label.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
SwingUtilities.windowForComponent(TestPane.this).dispose();
}
});
add(label);
}
}
public static void setOpaque(Window window, boolean opaque) {
String version = System.getProperty("java.runtime.version");
if (version.startsWith("1.7")) {
window.setBackground(new Color(0, 0, 0, 0));
} else {
try {
Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
if (awtUtilsClass != null) {
Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
method.invoke(null, window, opaque);
}
} catch (Exception exp) {
exp.printStackTrace();
}
}
}
}
Assuming you want to show the foreground, of the label (nothing else) that is its text/icon, you would set the frame's opacity to false:
com.sun.awt.AWTUtilities.setWindowOpaque(frame, false);
The usual caveat against using com.sun.** classes, which unfortunately is the only way to reach transparent windows prior to java7
I've added an image that I want to use as a background image and I want to put jLabels on top of it. So I use the image icon feature and show the image, but when I try to put a jLabel on it, it gets moved off to the side. I've tried several tutorials and it appears to work on youtube, but when I try to do the same thing on my own they get moved out of position.
field.setIcon(new javax.swing.ImageIcon(getClass().getResource("/wiffleball/resources/field2.png"))); // NOI18N
The JLabel doesn't have a layout manager by default. Label's also have default text positioning, which is normally aligned to the left, you need to change all these default values...
You may want to use a different layout manager other the BorderLayout, but this is just an example...
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Font;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class SimpleLabel {
public static void main(String[] args) {
new SimpleLabel();
}
public SimpleLabel() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JLabel label = new JLabel(new ImageIcon("C:\\hold\\thumbnails\\_cg_836___Tilting_Windmills___by_Serena_Clearwater.png"));
label.setHorizontalAlignment(JLabel.CENTER);
label.setVerticalAlignment(JLabel.CENTER);
label.setLayout(new BorderLayout());
JLabel child = new JLabel("Can you see me?");
child.setForeground(Color.WHITE);
child.setFont(label.getFont().deriveFont(Font.BOLD, 24f));
child.setHorizontalAlignment(JLabel.CENTER);
child.setVerticalAlignment(JLabel.CENTER);
child.setHorizontalTextPosition(JLabel.CENTER);
child.setVerticalTextPosition(JLabel.CENTER);
label.add(child);
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(label);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
}
I put everything on a jPanel and that seemed to do it. It just took some tinkering with. Thanks!
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'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);
}
});
}
}