How can I modify the window menu of a JFrame in Java ? That's the one (in Windows) at the top left, behind the application icon, that has items such as 'Restore', 'Move', 'Minimize', 'Resize'...
Unfortunately I've only found a way to do this with the "metal decoration" (with that I mean doing JFrame.setDefaultLookAndFeelDecorated(true);). I will of course update the answer if I find one with the system LaF, but I think this is still worth an answer.
Output:
Code:
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.BufferedReader;
import java.io.UnsupportedEncodingException;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
public class Example {
public Example() {
JFrame.setDefaultLookAndFeelDecorated(true);
JFrame frame = new JFrame();
JMenu systemMenu = getSystemMenu(frame);
systemMenu.add(new JMenuItem("New JMenuItem"), 0);
for (Component component : systemMenu.getPopupMenu().getComponents()) {
if (component.toString().contains("JMenu")) {
((JMenuItem) component).setForeground(Color.RED);
}
}
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(300, 200);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JMenu getSystemMenu(JFrame frame) {
for (Component c1 : frame.getLayeredPane().getComponents()) {
if (c1.toString().contains("MetalTitlePane")) {
for (Component c2 : ((Container) c1).getComponents()) {
if (c2.toString().contains("SystemMenuBar")) {
return (JMenu) ((Container) c2).getComponent(0);
}
}
}
}
return null;
}
public static void main(String args[]) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new Example();
}
});
}
}
Related
I am developing Automated tests on Selenium Java and following is the configuration of my laptop.
Operating System:Windows 7 Ultimate.
Java Version:Java Version details
Eclipse Version:Eclipse IDE details
I am facing a problem with awt Choice component in java, as
when I open the choice drop down and click on 1st item, then it is not selected
then i select any other item from the list, and that item selected,
now when I select the first item again it is being selected.
Why it is not being selected on first click.
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.Image;
import java.awt.Label;
import java.awt.Menu;
import java.awt.MenuBar;
import java.awt.MenuItem;
import java.awt.Button;
import java.awt.Checkbox;
import java.awt.Choice;
import java.awt.Color;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.Image;
public class MainMenu1 extends Frame implements ItemListener{
Choice bl;
String[][] userselect = new String[5][4];
MainMenu1() {
setTitle("Automation Test");
setLayout(null);setBackground(Color.pink);setSize(800,400); setLocation(200,200);setVisible(true);
setResizable(false);
bl = new Choice();bl.add("IE");bl.add("Chrome");bl.add("FireFox");bl.add("Safari");bl.add("Opera");bl.setSize(90, 21);bl.setLocation(180, 90);
add(bl);
bl.addItemListener(this);
addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
public void itemStateChanged(ItemEvent i){
if(i.getSource()==bl)
{
System.out.println(bl.getSelectedItem());
userselect[0][1]=bl.getSelectedItem();
}
}
public static void main(String[] args){
new MainMenu1();
}
}
I used 'Thread' and 'TimeUnit' but not know how to use in the following program. I want when WIN+E execute then after some delay of 1 or 2 second next statement run. As, next statement is in for loop so it should run after 2 seconds infinite time (because of infinite for loop). You can see ActionListener line only.
package v;
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class V extends JPanel{
private JButton V;
public V() throws AWTException{
Robot r = new Robot();
setBackground(Color.yellow);
setPreferredSize(new Dimension(800,500));
V = new JButton("PUSH");
add(V);
V.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {
for (int i=0; i>0; i++) {r.keyPress(KeyEvent.VK_WINDOWS); r.keyPress(KeyEvent.VK_E); r.keyRelease(KeyEvent.VK_WINDOWS); r.keyRelease(KeyEvent.VK_E);}
}
});
}
public static void main(String[] args) throws AWTException {
V panel = new V();
JFrame frame = new JFrame ("V");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
i would go for something like this:
import java.awt.AWTException;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Robot;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class V extends JPanel{
private JButton V;
private boolean notstarted=true;
public V() throws AWTException{
Robot r = new Robot();
setBackground(Color.yellow);
setPreferredSize(new Dimension(800,500));
V = new JButton("PUSH");
add(V);
V.addActionListener(new ActionListener() {public void actionPerformed(ActionEvent e) {
if(notstarted){
notstarted=false;
new Thread(new Runnable() {
#Override
public void run() {
while (true) {r.keyPress(KeyEvent.VK_WINDOWS);
r.keyPress(KeyEvent.VK_E);
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
Logger.getLogger(StreamServer.class.getName()).log(Level.SEVERE, null, ex);
}
r.keyRelease(KeyEvent.VK_WINDOWS);
r.keyRelease(KeyEvent.VK_E);}
}
}).start();
}
}
});
}
public static void main(String[] args) throws AWTException {
V panel = new V();
JFrame frame = new JFrame ("V");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(panel);
frame.pack();
frame.setVisible(true);
}
}
As you can see i have added a boolean notstarted to control if the function have been accessed previously, so, this way you cant run that more than one and finally i have added a Thread to mitigate the impact the ActionListener could have on the thread that call it.
Anyway there should be beeter ways to achieve what you are looking for.
You can use javafx.animation.PauseTransition
PauseTransition happen = new PauseTransition(Duration.seconds(2));
happen.setOnFinished(e -> {
System.out.println("hello");
happen.playFromStart();
});
happen.play();
Like that. It will print hello every 2 seconds. That however requires you to extend javafx.application.Application and I see that you don't use javafx in your program.
You can use Thread.sleep as the other answer suggests - to sleep each 2000 miliseconds (in your loop).
There is also java.util.Timer and java.util.TimerTask. It allows you to do code every milisecond given in time. There is an excellent video of that here https://www.youtube.com/watch?v=36jbBSQd3eU
I have this program, Where the JLabel is suppose to change its text to "Welcome" and then to "Register" and then back to "Welcome
Program:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.event.ItemListener;
import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.geom.*;
import java.util.*;
public class optionsDineIn extends JPanel {
JLabel lab1 = new JLabel("Welcome");
JPanel p = new JPanel();
public void construct() {
if(lab1.getText().equals("Welcome")) {
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
//for(int i=0; i<=100; i++){
lab1.setText("Register");
//}
}
},
2000
);
}
p.add(lab1);
}
You can try using a repeating task:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.event.ItemListener;
import javax.imageio.ImageIO;
import java.awt.Graphics;
import java.awt.geom.*;
import java.util.*;
public class optionsDineIn extends JPanel {
JLabel lab1 = new JLabel("Welcome");
boolean lab1state = false;
JPanel p = new JPanel();
public void construct() {
new java.util.Timer().schedule(
new java.util.TimerTask() {
#Override
public void run() {
if(lab1state){
lab1.setText("Welcome");
}else{
lab1.setText("Register");
}
lab1state = !lab1state;
}
},
2000,
2000
);
}
p.add(lab1);
}
I have a Swing application with multiple panes. Some of the panes are text ones (JTextPane), some are dialog-like (with buttons and sliders) and some are graphical (custom painted ). I have a few actions defined in the main menu with simple accelerators like K, P or O.
I would like those accelerators to be processed by the menu actions only if the currently focused pane is not processing them. Specifically, I do not want them to be processed by the menu when the user is just typing in a text pane.
I am creating actions and menu items using:
action = new javax.swing.AbstractAction
new MenuItem(action)
I am registering accelerators with:
action.putValue(javax.swing.Action.ACCELERATOR_KEY, keyStroke)
Is it possible to "eat" (suppress) the key press event for the keys which are processed in the text panes so that they are not passed to the main menu for the global processing?
If not, are there some alternatives to do something similar, like to register the accelerators I know should not be processed when in a text pane for some panes only?
I am adding a code based on an answer to make the question clearer (and to make developing alternate solutions easier):
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here I want no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here I want accelerators working"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
Here is the example. In text area no key bindings working. In text field work all key bindings. Also all the menu items are accessible (enabled) from the menu.
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
menu.add(new PrintAction("O", KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)));
menu.add(new PrintAction("K", KeyStroke.getKeyStroke(KeyEvent.VK_K, 0)));
menu.add(new PrintAction("P", KeyStroke.getKeyStroke(KeyEvent.VK_P, 0)));
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
area.addFocusListener(new FocusListener() {
#Override
public void focusLost(FocusEvent e) {
setItemStatus(menu, true);
}
#Override
public void focusGained(FocusEvent e) {
setItemStatus(menu, false);
}
});
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static void setItemStatus(JMenu aMenu, boolean aStatus) {
for (Component item : aMenu.getMenuComponents()) {
((JMenuItem) item).getAction().setEnabled(aStatus);
}
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
Here is a solution using KeyBindinds, as suggested by camickr. It is shorter than the one provided by Sergiy Medvynskyy, and I find it more straightforward, but it has a drawback the shortcut is not displayed in the menu, which is a result of the shortcut not being defined in the action itself.
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.KeyStroke;
import javax.swing.WindowConstants;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O");
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators") {
{
getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0), "command_O");
getActionMap().put("command_O", oAction);
}
}, BorderLayout.SOUTH);
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr) {
super("Print: " + aPrintStr);
str = aPrintStr;
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
It is possible to use KeyEventDispatcher to filter key events.
(Credit: I have adapted the code from answer to Application wide keyboard shortcut)
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class TestMenuBindings {
public static void main(String[] args) {
JMenuBar menuBar = new JMenuBar();
final JMenu menu = new JMenu("Print");
final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0));
menu.add(oAction);
menuBar.add(menu);
JFrame frm = new JFrame("Frame");
frm.setJMenuBar(menuBar);
final JTextArea area = new JTextArea("Here working no accelerators", 10, 40);
frm.add(new JScrollPane(area));
frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH);
KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager();
kfm.addKeyEventDispatcher( new KeyEventDispatcher() {
#Override
public boolean dispatchKeyEvent(KeyEvent e) {
KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e);
// pass only KEY_TYPED for letters with no modifiers in the editing area, suppress KEY_PRESSED, KEY_RELEASED
return area.isFocusOwner() && keyStroke.getModifiers()==0 && e.getID()!=KeyEvent.KEY_TYPED && Character.isLetter(e.getKeyChar());
}
});
frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frm.pack();
frm.setVisible(true);
}
private static class PrintAction extends AbstractAction {
private String str;
public PrintAction(String aPrintStr, KeyStroke aMnemonic) {
super("Print: " + aPrintStr);
str = aPrintStr;
putValue(Action.ACCELERATOR_KEY, aMnemonic);
}
#Override
public void actionPerformed(ActionEvent e) {
System.out.println(str);
}
}
}
How to Disable/Enable JFrame components when JInternalFrame isVisible inside JFrame/JDesktopPane? For example, make every JInternalFrame1 visible on the JDesktopPane (desktop pane set on the JFrame) all frame components like JMenuBar/JButton/etc. set disabled.
Have a solution?
If you have a reference to all your components, the best shot is to write a simple method that would disable everything (more or less like a state machine).
If you don't have a reference to all of them (like a GUI that uses reflection) you will need to get a root panel and iterate over it finding every component and disabling it.
Take a look at the Jemmy tool that is used to test Netbeans, they have a GUIBrowser that can give you an idea.
That makes use of JXLayer and JHLabs filters, basically, it creates a custom frame that wraps the JRootPane in a JXLayer, which allows you to "disable" the entire frame...
import com.jhlabs.image.BlurFilter;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagLayout;
import java.awt.HeadlessException;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JRootPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import org.jdesktop.jxlayer.JXLayer;
import org.jdesktop.jxlayer.plaf.effect.BufferedImageOpEffect;
import org.jdesktop.jxlayer.plaf.ext.LockableUI;
public class EnabledFrame {
public static void main(String[] args) {
new EnabledFrame();
}
public EnabledFrame() {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
final LayeredFrame frame = new LayeredFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new GridBagLayout());
JMenuBar mb = new JMenuBar();
JMenu mFile = new JMenu("File");
mFile.add("Exit");
frame.setJMenuBar(mb);
mb.add(mFile);
JButton btn = new JButton("Click me");
btn.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
frame.setEnabled(false);
}
});
frame.add(btn);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class LayeredFrame extends JFrame {
private BlurableLockedUI lockUI;
private JXLayer<JRootPane> rootLayer;
public LayeredFrame(String title) throws HeadlessException {
super(title);
}
#Override
protected void setRootPane(JRootPane root) {
if (rootLayer != null) {
remove(rootLayer);
}
super.setRootPane(root);
JRootPane rootPane = getRootPane();
rootLayer = new JXLayer<>(root);
rootLayer.setUI(getLockUI());
add(rootLayer, BorderLayout.CENTER);
}
protected BlurableLockedUI getLockUI() {
if (lockUI == null) {
lockUI = new BlurableLockedUI();
}
return lockUI;
}
#Override
public void setEnabled(boolean b) {
getLockUI().setLocked(!b);
super.setEnabled(b);
}
}
public class BlurableLockedUI extends LockableUI {
public BlurableLockedUI() {
super(new BufferedImageOpEffect(new BlurFilter()));
}
public void repaint() {
setDirty(true);
}
public void invalidate() {
setDirty(true);
}
public void revalidate() {
setDirty(true);
}
}
}