Double icons with JMenuItem setHorizontalTextPosition on Win - java

Two icons are rendered when using JMenuItem setHorizontalTextPosition(SwingConstants.LEFT) with Windows Look and Feel. It works fine with the default Java Look and Feel.
I just filed a Java bug report, posting here for anyone else having the same problem.
Does anyone have another workaround to suggest?
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
public class WinMenuItemIcon {
public static void main(String[] args) {
//NOTE: Bug happens with Windows L&F
String name = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel( name );
} catch (Exception e) {
e.printStackTrace();
}
JFrame frame = new JFrame();
frame.setTitle("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JMenuBar menuBar = new JMenuBar();
JMenu menu = new JMenu("Menu");
ImageIcon icon = createIcon();
JMenuItem menuItem = new JMenuItem("Command", icon);
menuItem.setHorizontalTextPosition(SwingConstants.LEFT);
menu.add(menuItem);
menuBar.add(menu);
frame.setJMenuBar(menuBar);
frame.setPreferredSize(new Dimension(500, 500));
frame.pack();
frame.setVisible(true);
}
protected static ImageIcon createIcon() {
BufferedImage bi = new BufferedImage(25,25,BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.setColor(Color.RED);
g.fillOval(0,0, 25, 25);
return new ImageIcon(bi);
}
}

Delete the line
menuItem.setHorizontalTextPosition(SwingConstants.LEFT);
and you will have only 1 icon
or use an if statement to exclude that line for windows look and feel as follows
if(!UIManager.getLookAndFeel().equals("com.sun.java.swing.plaf.windows.WindowsLookAndFeel"))
{
menuItem.setHorizontalTextPosition(SwingConstants.LEFT);
}
here is an alternative to #aterai's code that will work better if tweaked a bit more according to your needs, probably it is some bug but here this does it i am not sure how #aterai needs center to look like but here is what i assumed :-
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class WinMenuItemIconTest {
private static JMenuBar makeManuBar() {
JMenuItem menuItem0 = new JMenuItem("Command", createIcon());
JMenuItem menuItem1 = new JMenuItem("LEFT bug?", createIcon()); // always left by defaulr
JMenuItem menuItem2 = new JMenuItem("CENTER bug?", createIcon());
menuItem2.setMargin(new Insets(5, 50, 5, 5)); // using set margin to centerise
JMenuItem menuItem3 = new JMenuItem("RIGHT_TO_LEFT", createIcon());
menuItem3.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT); // Right to left seems to work
JMenu menu = new JMenu("Menu");
menu.add(menuItem0);
menu.add(menuItem1);
menu.add(menuItem2);
menu.add(menuItem3);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
return menuBar;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
//NOTE: Bug happens with Windows L&F
String name = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(name);
} catch (Exception e) {
e.printStackTrace();
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(makeManuBar());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
protected static ImageIcon createIcon() {
BufferedImage bi = new BufferedImage(25, 25, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.setColor(Color.RED);
g.fillOval(0, 0, 25, 25);
return new ImageIcon(bi);
}
}
Note:- I am on Windows 10 too

My envirment: Windows 10 64bit + JDK 1.8.0_72
I'm not sure if this is a bug... Now this bug seems fixed: JDK-8152981 Double icons with JMenuItem setHorizontalTextPosition on Win 10 - Java Bug System
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
public class WinMenuItemIconTest {
private static JMenuBar makeManuBar() {
JMenuItem menuItem0 = new JMenuItem("Command", createIcon());
JMenuItem menuItem1 = new JMenuItem("LEFT bug?", createIcon());
menuItem1.setHorizontalTextPosition(SwingConstants.LEFT);
//menuItem1.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
JMenuItem menuItem2 = new JMenuItem("CENTER bug?", createIcon());
menuItem2.setHorizontalTextPosition(SwingConstants.CENTER);
JMenuItem menuItem3 = new JMenuItem("RIGHT_TO_LEFT", createIcon());
menuItem3.setComponentOrientation(ComponentOrientation.RIGHT_TO_LEFT);
JMenu menu = new JMenu("Menu");
menu.add(menuItem0);
menu.add(menuItem1);
menu.add(menuItem2);
menu.add(menuItem3);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
return menuBar;
}
public static void main(String[] args) {
EventQueue.invokeLater(() -> {
//NOTE: Bug happens with Windows L&F
String name = UIManager.getSystemLookAndFeelClassName();
try {
UIManager.setLookAndFeel(name);
} catch (Exception e) {
e.printStackTrace();
}
JFrame frame = new JFrame("Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(makeManuBar());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
});
}
protected static ImageIcon createIcon() {
BufferedImage bi = new BufferedImage(25, 25, BufferedImage.TYPE_INT_ARGB);
Graphics g = bi.createGraphics();
g.setColor(Color.RED);
g.fillOval(0, 0, 25, 25);
g.dispose();
return new ImageIcon(bi);
}
}

For aligning icon and label text from left to right:
JMenuItem menuItem3 = new JMenuItem("LEFT_TO_RIGHT", createIcon());
menuItem3.setHorizontalTextPosition(JMenuItem.RIGHT);
menuItem3.setComponentOrientation(ComponentOrientation.LEFT_TO_RIGHT);
The above code worked for me.

Related

Swing - last JMenuItem occupy the rest of space on JMenuBar

I find that if I have a JMenuBar, and the last element of it (the rightmost one) is a JMenuItem, it will occupy all the rest blank space on the JMenuBar, which is definitely not what we want.
Imagine an "About" JMenuItem as the rightmost item on a JMenuBar. It should only occupy the same space as the other menus.
See my SSCCE: (click the menu and hover over the menuitem on the right to see the effect)
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
public class JMenuItemLastOnMenuBar {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createGUI();
}
});
}
private static void createGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 300);
JMenuBar bar = new JMenuBar();
JMenu menu = new JMenu("Menu 1");
JMenuItem item1 = new JMenuItem("Item 1");
menu.add(item1);
bar.add(menu);
JMenuItem item2 = new JMenuItem("Item 2") {
#Override
public Dimension getPreferredSize() {
return new Dimension(120, 25);
}
};
bar.add(item2);
frame.setJMenuBar(bar);
frame.pack();
frame.setVisible(true);
}
}
You should override the method getMaximumSize
import java.awt.Dimension;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
public class JMenuItemLastOnMenuBar {
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
createGUI();
}
});
}
private static void createGUI() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setBounds(0, 0, 300, 300);
JMenuBar bar = new JMenuBar();
JMenu menu = new JMenu("Menu 1");
JMenuItem item1 = new JMenuItem("Item 1");
menu.add(item1);
bar.add(menu);
JMenuItem item2 = new JMenuItem("Item 2") {
#Override
public Dimension getMaximumSize() {
Dimension d1 = super.getPreferredSize();
Dimension d2 = super.getMaximumSize();
d2.width = d1.width;
return d2;
}
};
bar.add(item2);
frame.setJMenuBar(bar);
frame.pack();
frame.setVisible(true);
}
}

Drawing on JPanel with JButton, JSpinner, etc

So i am trying to make a graphical interface for school, which involves a JMenuBar, JSpinner, and 2 JButtons. Below these objects I'm trying to draw a simple rectangle. I've already tried using the paintComponent method in the class which extends JPanel but it stil doesn't appear.
import java.awt.Dimension;
import java.awt.FlowLayout;
import javax.swing.JFrame;
public class A1 {
public final static int DEFAULT_WIDTH = 640;
public final static int DEFAULT_HEIGHT = DEFAULT_WIDTH /12*9;
public static void main(String[] args) {
JFrame frame = new JFrame("A1");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(DEFAULT_WIDTH,DEFAULT_HEIGHT));
frame.requestFocus();
frame.setLayout(new FlowLayout());
frame.setLocationRelativeTo(null);
frame.setResizable(false);
lePanel panel = new lePanel();
frame.add(panel);
frame.setJMenuBar(panel.getMenuBar());
frame.setVisible(true);
}
}
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.SpinnerNumberModel;
public class lePanel extends JPanel {
JMenuBar menuBar;
JButton submit;
JButton check;
JSpinner spinner;
public String test;
public lePanel() {
menuBar = new JMenuBar();
menuBar.add(createFileMenu(new JMenu("File")));
menuBar.add(createHelpMenu(new JMenu("Help")));
spinner = new JSpinner(new SpinnerNumberModel(1, 1, 10, 1));
add(spinner);
submit = new JButton("Submit");
add(submit);
check = new JButton("Check");
add(check);
submit.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == submit)
{
test = spinner.getValue().toString();
System.out.println("Spinner Submitted");
}
}
});
check.addActionListener(new ActionListener()
{
#Override
public void actionPerformed(ActionEvent e) {
if(e.getSource() == check)
{
JOptionPane.showMessageDialog(lePanel.this, test, "Information",JOptionPane.INFORMATION_MESSAGE);
}
}
});
}
private JMenu createHelpMenu(JMenu jMenu) {
JMenu menu = jMenu;
JMenuItem helpItem = new JMenuItem("Help");
menu.add(helpItem);
return menu;
}
private JMenu createFileMenu(JMenu jMenu) {
JMenu menu = jMenu;
JMenuItem newItem = new JMenuItem("New");
JMenuItem clearItem = new JMenuItem("Clear");
JMenuItem chooseFileItem = new JMenuItem("Open");
JMenuItem saveItem = new JMenuItem("Save");
JMenuItem exitItem = new JMenuItem("Exit");
exitItem.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
menu.add(newItem);
menu.add(clearItem);
menu.add(chooseFileItem);
menu.add(saveItem);
menu.add(exitItem);
return menu;
}
public void paintComponent(Graphics g)
{
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.red);
g2.drawRect(200, 200, 50, 50);
}
public JMenuBar getMenuBar() {
return menuBar;
}
}
Your problem is here:
frame.setLayout(new FlowLayout());
By doing this, your lePanel JPanel sizes to its preferred size, a size much too small to show the rectangle. Delete this line and your JFrame's contentPane will use its default BorderLayout, and the drawing JPanel will fill the lower part of your GUI, as per the BordrLayout rules, and you'll see the drawing.
Note a useful debugging technique is to add a border around a component of interest to see where it is and how big it is. For example, I placed this in your lepanel constructor
setBorder(BorderFactory.createTitledBorder("le panel"));
and it visually showed me your problem.
Other unrelated issues:
You will want to learn and use Java naming conventions. Variable names should all begin with a lower letter while class names with an upper case letter. Learning this and following this will allow us to better understand your code, and would allow you to better understand the code of others.
Remember to use the #Override annotation above any methods that you think might be overriding another, such as your paintComponent method. This will allow the compiler to notify you if you are in fact overriding things incorrectly.

How to change icon for JmenuItem on rollover

I want to put a rollover effect in my JMenu this is my code:
Icon firstPicAcc= new ImageIcon(Welcome.class.getResource("/app/resources/user1.jpg"));
Icon secPicAcc= new ImageIcon(Welcome.class.getResource("/app/resources/user2.jpg"));
JMenu mnAccountSettings = new JMenu("Account Settings");
mnAccountSettings.addMouseWheelListener(new MouseWheelListener() {
public void mouseWheelMoved(MouseWheelEvent arg0) {
}
});
mnAccountSettings.setFont(new Font("Dialog", Font.PLAIN, 20));
mnAccountSettings.setForeground(new Color(0, 153, 0));
mnAccountSettings.setBackground(new Color(255, 204, 255));
mnAccountSettings.setRolloverEnabled(true);
mnAccountSettings.setIcon(firstPicAcc);
mnAccountSettings.setRolloverIcon(secPicAcc);
mnAccount.add(mnAccountSettings);
how can i do that? thanks!
What should happen is when I rolled my mouse over the JMenu bar the original icon should change into another icon.
What you want to do is add a ChangeListener to the JMenuItem and check if it's selected or armed and change the icon accordingly. The ChangeListener works for both keyboard and mouse.
See this good read by #kleopatra
private JMenuItem createMenuItem(final ImageIcon icon, String title) {
JMenuItem item = new JMenuItem(title);
item.setIcon(icon);
ChangeListener cl = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() instanceof JMenuItem) {
JMenuItem item = (JMenuItem) e.getSource();
if (item.isSelected() || item.isArmed()) {
item.setIcon(stackIcon);
} else {
item.setIcon(icon);
}
}
}
};
item.addChangeListener(cl);
return item;
}
Here is running example. Just replace images with yours
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.SwingUtilities;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class RolloverMenuItem {
ImageIcon stackIcon = new ImageIcon(getClass().getResource("/resources/stackoverflow2.png"));
public RolloverMenuItem() {
ImageIcon newIcon = new ImageIcon(getClass().getResource("/resources/image/new.gif"));
ImageIcon saveIcon = new ImageIcon(getClass().getResource("/resources/image/open.gif"));
ImageIcon openIcon = new ImageIcon(getClass().getResource("/resources/image/save.gif"));
JMenu menu = new JMenu("File");
menu.setMnemonic(KeyEvent.VK_F);
JMenuItem item1 = createMenuItem(newIcon, "New");
JMenuItem item2 = createMenuItem(openIcon, "Open");
JMenuItem item3 = createMenuItem(saveIcon, "Save");
menu.add(item1);
menu.add(item2);
menu.add(item3);
JMenuBar menuBar = new JMenuBar();
menuBar.add(menu);
JFrame frame = new JFrame("Rollover MenuItem");
frame.setJMenuBar(menuBar);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(400, 250);
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
private JMenuItem createMenuItem(final ImageIcon icon, String title) {
JMenuItem item = new JMenuItem(title);
item.setIcon(icon);
ChangeListener cl = new ChangeListener() {
#Override
public void stateChanged(ChangeEvent e) {
if (e.getSource() instanceof JMenuItem) {
JMenuItem item = (JMenuItem) e.getSource();
if (item.isSelected() || item.isArmed()) {
item.setIcon(stackIcon);
} else {
item.setIcon(icon);
}
}
}
};
item.addChangeListener(cl);
return item;
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new RolloverMenuItem();
}
});
}
}

multiple 'imageviews' in jframe

hi all i am trying to add multiple components to my jframe. but i cant seem to get it to work.
private void initGUI() {
setAlwaysOnTop(true);
setUndecorated(true);
AWTUtilities.setWindowOpaque(this, false);
AWTUtilities.setWindowOpacity(this, 0.5f);
setLocation(ini.getButtonsX(), ini.getButtonsY());
setSize(ini.getButtonsW(), ini.getButtonsH());
setLayout(null);
JPanel panel = new JPanel();
panel.setLayout(null);
ImageView baron = new ImageView("image/nashor.png", 50, 50);
baron.setBounds(50, 50, 50, 50);
ImageView test = new ImageView("image/dragon.png", 50, 50);
test.setBounds(50, 150, 50, 50);
panel.add(baron);
panel.add(test);
panel.setBounds(0, 0, ini.getButtonsW(), ini.getButtonsH());
add(panel);
}
my ImageView is a class that extends a JPanel which paints a image.
at this point only nashor is painted
any help is greatly appreciated.
I recommend that you have your JPanel panel use a GridLayout, not a null layout, and that you not set your ImageView sizes but rather make sure that the class has a getPreferredSize() method override that makes sense, that returns a Dimension of the appropriate size. Then if you call pack() on your JFrame after adding components, the layout managers will take care of sizing things for you.
Consider this program:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.awt.*;
import java.awt.event.*;
import javax.imageio.ImageIO;
import javax.swing.*;
public class Init extends JFrame{
JPanel view = new JPanel();
JMenuBar mBar = new JMenuBar();
JMenu menu = new JMenu("File");
JMenuItem mItemOpen = new JMenuItem("Open");
JMenuItem mItemExit = new JMenuItem("Exit");
JFileChooser fc = new JFileChooser();
JTextField txtPath = new JTextField();
BufferedImage myPicture;
File filePath;
String path;
public Init(){
mBar.add(menu);
menu.add(mItemOpen);
menu.addSeparator();
menu.add(mItemExit);
setJMenuBar(mBar);
txtPath.setEditable(false);
mItemOpen.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
fc.showOpenDialog(null);
filePath = fc.getSelectedFile();
path = filePath.getPath();
txtPath.setText(path);
try {
//view.removeAll();
myPicture = ImageIO.read(new File(path));
JLabel picLabel = new JLabel(new ImageIcon(myPicture));
view.add(picLabel);
revalidate();
} catch (IOException ex) {
ex.printStackTrace();
}
}
});
setLayout(new BorderLayout());
getContentPane().add(new JScrollPane(view),BorderLayout.CENTER);
getContentPane().add(txtPath,BorderLayout.SOUTH);
setTitle(".:My Picture Viewer:.");
setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
//pack();
setSize(1024,768);
setVisible(true);
}
public static void main(String [] args){
SwingUtilities.invokeLater(new Runnable(){
public void run(){
new Init();
}
});
}
}

Java Swing OSX Window Menu Icon Alignment

Java Swing seems to place the 'Menu Text' after the icon (if present) on MenuItems. See example below.
It does NOT look very nice.
Is there a way around this?
On OSX the icon fits in the left margin and the text aligns with all other MenuItems.
Do you mean something like this :
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JTextPaneExample
{
private Icon info = UIManager.getIcon("OptionPane.informationIcon");
private Icon error = UIManager.getIcon("OptionPane.errorIcon");
private void createAndDisplayGUI()
{
JFrame frame = new JFrame("JTextPane Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JTextPane tpane = new JTextPane();
tpane.setContentType("text/html");
JScrollPane scroller = new JScrollPane();
scroller.setViewportView(tpane);
try
{
java.net.URL url = new java.net.URL("http://maps.google.es/");
//tpane.setPage(url);
}
catch (Exception e)
{
e.printStackTrace();
}
frame.setJMenuBar(createMenuBar());
frame.getContentPane().add(scroller);
frame.setSize(300, 300);
frame.setVisible(true);
}
private JMenuBar createMenuBar()
{
JMenuBar menuBar = new JMenuBar();
JMenu windowMenu = new JMenu("Window");
JMenuItem minimizeItem = new JMenuItem("Minimize");
minimizeItem.setMargin(new java.awt.Insets(0, 10, 0, 0));
minimizeItem.setIcon(info);
minimizeItem.setIconTextGap(1);
minimizeItem.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
JMenuItem zoomItem = new JMenuItem("Zoom");
zoomItem.setMargin(new java.awt.Insets(0, 10, 0, 0));
zoomItem.setIconTextGap(1);
zoomItem.setHorizontalTextPosition(javax.swing.SwingConstants.RIGHT);
JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem("Check Me", null, true);
cbmi.setMargin(new java.awt.Insets(5, 25, 5, 5));
cbmi.setIconTextGap(17);
cbmi.setHorizontalTextPosition(javax.swing.SwingConstants.LEFT);
windowMenu.add(minimizeItem);
windowMenu.add(zoomItem);
windowMenu.add(cbmi);
menuBar.add(windowMenu);
return menuBar;
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
public void run()
{
new JTextPaneExample().createAndDisplayGUI();
}
});
}
}
Here is the Output :
You could try either of these approaches:
Unicode characters are appealing, but they offer poor alignment in a variable pitch font:
JMenuBar menuBar = new JMenuBar();
JMenu windowMenu = new JMenu("Window");
windowMenu.add(new JMenuItem("♦ Item"));
windowMenu.add(new JMenuItem("✓ Item"));
windowMenu.add(new JMenuItem("• Item"));
menuBar.add(windowMenu);
frame.setJMenuBar(menuBar);
Better, implement the Icon interface, illustrated here and here, using a fixed-size implementation to control geometry. CellTest shows one approach to rendering an arbitrary unicode glyph.

Categories

Resources