I'm looking to do something which may be impossible; in Java (1.6 running on Windows 7, since this is platform-dependent), I want to have a window appear over another window, but not steal focus from the triggering component. In the example attached below, I'd like to be able to be able to click on the text field, have the new pop up appear in front, but maintain focus on the text field. What I instead notice is that I get the panel to the front, but do not get focus on the text field again.
I'm primarily wondering if this is possible (normally the front Window has focus in Windows, so I'm leaning towards probably not). If not, but someone has opinions on a good workaround, I'm open ears.
Example:
public class PopUpExample
{
// Global toolkit listener.
enum PopUp
{
INSTANCE;
private PopUpWindow m_popUp;
private JTextComponent m_textComponent;
public void initialize(PopUpWindow p)
{
m_popUp = p;
Toolkit.getDefaultToolkit().addAWTEventListener( new AWTEventListener()
{
public void eventDispatched(AWTEvent e)
{
// Ensure event is a focus gain event.
if (( e instanceof FocusEvent )
&& ((FocusEvent)e).getID()==FocusEvent.FOCUS_GAINED)
{
// If it is on a text field, make the pop up appear, but maintain focus on the text field
if ( (e.getSource() instanceof JTextComponent) )
{
m_textComponent = (JTextComponent)e.getSource();
// FIXME Code below here should set the button on top, yet leave the text field with focus.
m_popUp.setAlwaysOnTop( true );
m_popUp.setFocusable( false );
m_popUp.setVisible( true );
m_textComponent.requestFocus();
// end FIXME
}
// Otherwise, make the pop up disappear (if it isn't the pop up itself).
else if (((JComponent)e.getSource()).getRootPane().getComponent(0) instanceof PopUpWindow)
{
m_popUp.setVisible( false );
}
}
}
}, AWTEvent.FOCUS_EVENT_MASK);
}
}
// Pop up window that isn't focusable
class PopUpWindow extends JFrame
{
public PopUpWindow()
{
super();
BorderLayout layout = new BorderLayout();
this.setLayout( layout );
this.setMinimumSize( new Dimension( 100, 100 ) );
JButton button = new JButton("WantOnFront");
button.setFocusable( false );
this.add( button, BorderLayout.CENTER );
this.setFocusable( false );
}
}
// Main application window.
class GuiWindow extends JFrame
{
public GuiWindow()
{
super();
BorderLayout layout = new BorderLayout();
this.setLayout( layout );
this.setMinimumSize( new Dimension( 400, 400 ) );
JButton button = new JButton("defaultFocusButton");
this.add( button, BorderLayout.CENTER );
JTextField textField = new JTextField("WantToMaintainFocusWhenClicked");
this.add( textField, BorderLayout.SOUTH );
}
}
// Setup code
public PopUpExample()
{
new GuiWindow().setVisible( true );
PopUp.INSTANCE.initialize( new PopUpWindow() );
}
public static void main( String[] args )
{
new PopUpExample();
}
}
have the new pop up appear in front, but maintain focus on the text field.
JDialog dialog = new JDialog(...);
dialog.setFocusableWindowState( false );
...
dialog.setVisible( true );
Related
Working on a help system, I'd like each component to offer some help when the the mouse is over it and the "?" key is pressed. Sort of like tooltips, except with much more extensive help - essentially a little web browser is intended to pop up and display text, images or more.
What I'm finding is that no matter where the mouse is, the input always goes to the same KeyListener. Is there only supposed to be one active at a time?
For what it's worth, this is the now-working version - thanks for suggestions!
/**
* Main class JavaHelp wants to support a help function so that when
* the user types F1 above a component, it creates a popup explaining
* the component.
* The full version is intended to be a big brother to tooltips, invoking
* an HTML display with clickable links, embedded images, and the like.
*/
import javax.swing.*;
import javax.swing.border.Border;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
class Respond2Key extends AbstractAction
{
Component jrp;
// Contract consructor
public Respond2Key( String text)
{
super( text );
}
// Constructor that makes sure it gets done right
public Respond2Key( String text, Component jrpIn)
{
super( text );
System.out.println( "creating Respond2Key with component " + jrpIn
.toString
() );
jrp = jrpIn;
}
public void setJrp( Component j) {
jrp = j;
}
// Functionality: what is the response to a key
public void actionPerformed(ActionEvent e)
{
// use MouseInfo to get position, convert to pane coords, lookup component
Point sloc = MouseInfo.getPointerInfo().getLocation();
SwingUtilities.convertPointFromScreen( sloc, (Component) jrp );
Component c = jrp.getComponentAt( sloc );
System.out.printf( "Mouse at %5.2f,%5.2f Component under mouse is %s\n",
sloc.getX(), sloc.getY(), c.toString() );
}
}
//----------------------------------------------------------------
// The main class
//----------------------------------------------------------------
public class JavaHelp extends JFrame
{
// The object constructor
public JavaHelp()
{
// Start construction
super( "Help System" );
this.setSize( 640, 480 );
Container contents = getContentPane();
contents.setLayout( new FlowLayout() );
JButton b1 = butt( "button1", 64, 48 );
JButton b2 = butt( "button2", 96, 48 );
JButton b3 = butt( "button3", 128, 48 );
JPanel p1 = pane( "hello", 100, 100 );
JPanel p2 = pane( "world", 200, 100 );
contents.add( b1 );
contents.add( p1 );
contents.add( b2 );
contents.add( p2 );
contents.add( b3 );
JRootPane jrp = this.getRootPane();
jrp.getInputMap( jrp.WHEN_IN_FOCUSED_WINDOW)
.put( KeyStroke.getKeyStroke( "F1" ), "helpAction" );
jrp.getActionMap().put( "helpAction",
new Respond2Key("frame",(Component)contents)
);
this.setVisible( true );
this.requestFocus();
this.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
}
// Inner classes for instantiating and listening to button, and panel.
class ButtonListener implements ActionListener
{
private String label = null;
public void setLabel(String s) {label = s;}
public void actionPerformed(ActionEvent e)
{
System.out.printf( "Dealing with event labeled %s source %s\n\n",
label,
e.getSource().toString() );
}
}
// def butt( from, name, w, h) = new Jbutton (...)
protected JButton butt( String s, int w, int h)
{
JButton b = new JButton( s );
b.setSize( w, h );
ButtonListener oj = new ButtonListener();
oj.setLabel( s );
b.addActionListener( oj );
return (b);
}
// def pane = new Jpanel(...)
protected JPanel pane(String name, int w, int h)
{
JPanel p = new JPanel();
p.setMinimumSize( new Dimension( w, h ) );
p.add( new Label( name ) );
p.setBackground( Color.black );
p.setForeground( Color.red );
return (p);
}
//--------------------------------
public static void main(String[] args)
{
JavaHelp jh = new JavaHelp();
}
}
the input always goes to the same KeyListener.
A KeyEvent is always dispatched to the component with focus, the mouse location has nothing to do with how the key event is generated.
Instead of using a KeyListener, you should be using Key Bindings. When you using Key Bindings you can invoke an Action whenever a KeyStroke is generated by adding the binding to the root pane of the JFrame. Read the section from the Swing tutorial on Key Bindings for more information.
Now in the Action that you create to listen for the "?" KeyStroke you can then:
use the MouseInfo class to get the current mouse location.
use the SwingUtilities.convertPointFromScreen(...) to convert the mouse point to be relative to the root pane
then you can use the Conatiner.getComponentAt(...) to get the actual component the mouse is over
once you know the component you can display your help information.
I'm sure there's a better way, but one quick and dirty solution:
private final class HoverFocusListener extends MouseInputAdapter {
public void mouseEntered(MouseEvent e) {
e.getComponent().requestFocusInWindow();
}
}
Or, if necessary:
public void mouseEntered(MouseEvent e) {
e.getSource().setFocusable(true);
for (Component c : refToParent.getComponents()) c.setFocusable(false);
e.getComponent().requestFocusInWindow();
}
Then just .addMouseListener(new HoverFocusListener()) to all affected components.
the input consistently goes to a similar KeyListener.
A KeyEvent is constantly dispatched to the part with the center, the mouse area steers clear of how the key occasion is created.
Rather than utilizing a KeyListener, you ought to utilize Key Bindings. At the point when you utilizing Key Bindings, you can conjure an Action at whatever point a KeyStroke is produced by adding the limiting to the root sheet of the JFrame. Peruse the part from the Swing instructional exercise on Key Bindings for more data.
Presently in the Action that you make to tune in for the "?" KeyStroke you can then, at that point:
utilize the MouseInfo class to get the current mouse area.
utilize the SwingUtilities.convertPointFromScreen(...) to change over the mouse highlight be comparative with the root sheet
then, at that point, you can utilize the Container.getComponentAt(...) to get the genuine segment the mouse is finished
when you know the part you can show your assistance data.
When you set the icon for a Swing control (say a JButton), a disabled icon with grayed-darker colors automatically generates. I want to be able to imitate the way the icon colors are changed for the disabled state, so I can create my own disabled icon with a little twist, and set it as the disabled button.
Is there a way to achieve this (other then first instantiating the control and retrieving it's icon, I'm looking for more straight-forward less hacky way)?
Is there a way to achieve this (other then first instantiating the control and retrieving it's icon
Well the LAF is responsible for creating the disabled Icon. The getDisabledIcon() method from the AbstractButton button class looks something like this:
Icon disabledIcon = UIManager.getLookAndFeel().getDisabledIcon(this, getIcon());
So in theory the LAF getDisabledIcon() method expects the component to be passed in as a parameter. So the answer to your question would be: "yes, the button needs to be created first".
However in practice it appears (for Metal and Windows at least) that the component is not actually used in the creation of the icon so you could do something like:
ImageIcon original = new ImageIcon( ... );
Icon disabled = UIManager.getLookAndFeel().getDisabledIcon(null, original);
Using this approach is risky because other LAF's may indeed need the component to create the disabled Icon.
However, instead of passing null, I guess you could create a single component and then call this method with multiple different icons, so it would still be a little better than creating a unique component for each Icon.
Here is the SSCCE I used to test this approach:
import javax.swing.*;
import javax.swing.plaf.metal.*;
import java.awt.*;
import java.awt.image.*;
public class ButtonDisabledIcon extends JPanel
{
public ButtonDisabledIcon()
{
ImageIcon original = new ImageIcon( "dukewavered.gif" );
JButton button1 = new JButton( "Original" );
button1.setIcon( original );
add(button1);
JButton button2 = new JButton( "Disabled" );
button2.setIcon(original);
button2.setEnabled(false);
add(button2);
JButton button3 = new JButton( "LAF Disabled" );
button3.setIcon( UIManager.getLookAndFeel().getDisabledIcon(null, original) );
add(button3);
}
private static void createAndShowUI()
{
/*
try
{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) { }
*/
JFrame frame = new JFrame("Button Disabled Icon");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add( new ButtonDisabledIcon() );
frame.pack();
frame.setLocationByPlatform( true );
frame.setVisible( true );
}
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable()
{
public void run()
{
createAndShowUI();
}
});
}
}
Amplifying on #camickr's answer, you can experiment with getGray() and this L&F toolbar.
JToggleButton jtb = new JToggleButton("Plain", icon);
jtb.setEnabled(true);
this.add(jtb);
jtb = new JToggleButton("Disabled", icon);
jtb.setEnabled(false);
this.add(jtb);
jtb = new JToggleButton("Gray enabled", getGray(icon));
jtb.setEnabled(true);
this.add(jtb);
jtb = new JToggleButton("Gray disabled", getGray(icon));
jtb.setDisabledIcon(getGray(icon));
jtb.setEnabled(false);
this.add(jtb);
I'm building an Typing program and i have made an list with exercises to type
public class OefeningenListModel extends AbstractListModel {
private JComboBox time; //time combo box to select time
public OefeningenListModel() {
oefeningen = new ArrayList<Oefening>();
Oefening o1 = new Oefening("1", "Oefening HJ");
Oefening o2 = new Oefening("2", "Oefening KL");
Oefening o3 = new Oefening("3", "Oefening JH");
oefeningen.add(o1);
oefeningen.add(o2);
oefeningen.add(o3);
}
those exercises are shown in an jTable on my frame
public BasisSchermm() {
initComponents();
jList1.setModel(new OefeningenListModel());
and on this frame there is even add an jButton
now is my question:
i want to add a actionperformed on this button when a exercise is selected in the table and you click to button(when the exercise is selected) you move to a new frame to type the exercise but i have no idea how i can do this
to get the selected item in your JList you could do like this:
// Get the index of the selected item
int selectedIndex = jList1.getSelectedIndex();
// Get the selected item from the model
Object sel = jList1.getModel().getElementAt(selectedIndex);
or if needed you could cast it to the type you need:
Oefening selectedItem = (Oefening) list.getModel().getElementAt(selectedIndex);
to add the action listener:
ActionListener actionListener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
if (xItemIsSelected) {
//open 'x' frame
new xFrame().show();
}
if (yItemIsSelected) {
//open 'y' frame
new yFrame().show();
}
}
};
//add the listener to the button
button.addActionListener(actionListener);
To put you in the right direction a small piece of sample code (minus the imports) which creates a JFrame where the contents of the main panel is controlled by the selection in the JList. The example shows how to react on selection changes in the JList, and shows an alternative for constantly opening new windows, which is a terrible user experience.
public class ListSelectionExample {
private static String[] MODEL_CONTENTS = new String[]{"String1","String2","String3"};
public static void main( String[] args ) throws InvocationTargetException, InterruptedException {
EventQueue.invokeAndWait( new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame( "TestFrame" );
//create a JList
final JList list = new JList( );
DefaultListModel listModel = new DefaultListModel();
for ( String modelContents : MODEL_CONTENTS ) {
listModel.addElement( modelContents );
}
list.setModel( listModel );
list.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
//use a CardLayout to switch between different labels
final CardLayout cardLayout = new CardLayout();
final JPanel contentPane = new JPanel( cardLayout );
for ( String label_content : MODEL_CONTENTS ) {
contentPane.add( new JLabel( label_content ), label_content );
}
cardLayout.show( contentPane, MODEL_CONTENTS[0] );
//when the list selection is changed, switch the contents of the JPanel
list.addListSelectionListener( new ListSelectionListener() {
#Override
public void valueChanged( ListSelectionEvent aListSelectionEvent ) {
int selectedIndex = list.getSelectedIndex();
String modelElement = ( String ) list.getModel().getElementAt( selectedIndex );
cardLayout.show( contentPane, modelElement );
}
} );
frame.getContentPane().add( list, BorderLayout.EAST );
frame.getContentPane().add( contentPane, BorderLayout.CENTER );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
frame.pack();
frame.setVisible( true );
}
} );
}
}
I write a program in java and used a several components that takes action(actionListener) in my program.
I want to know when any action happened by this component. For example when I clicked the button or a menu item , call a method.
public class ButtonFrame extends JFrame
{
private JButton plainJButton; // button with just text
private JButton fancyJButton; // button with icons
public ButtonFrame()
{
super( "Testing Buttons" );
setLayout( new FlowLayout() ); // set frame layout
plainJButton = new JButton( "Plain Button" );
add( plainJButton );
fancyJButton = new JButton( "Fancy Button");
add( fancyJButton );
// create new ButtonHandler for button event handling
ButtonHandler handler = new ButtonHandler();
fancyJButton.addActionListener( handler );
plainJButton.addActionListener( handler );
}
private class ButtonHandler implements ActionListener
{
public void actionPerformed( ActionEvent event )
{
JOptionPane.showMessageDialog( ButtonFrame.this, String.format(
"You pressed: %s", event.getActionCommand() ) );
}
}
}
Use event.getSource() to differentiate between registered components.
Example -
if(plainJButton == event.getSource()){
// do stuff (e.g. show message dialog, invoke method, and etc.)
}
else if(fancyJButton == event.getSource()){
// do stuff (e.g. show message dialog, invoke method, and etc.)
}
else{
// ut-oh..time to panic!
}
You can use getSource() on the event.
I have a java program with a JFrame and 3 JButtons in it. I have added a keylistener to jframe. When i run the program a jframe window is opened and the first button is selected by default. My problem is that a KeyEvent is not being generated by this JFrame.
Now, besides adding a KeyListener to the jframe, i also added a KeyListener to the buttons.
Now the keyevent is being generated by the buttons.
How do I make the JFrame generate KeyEvent instead of the JButton generating them ??
Actually, my main purpose is building keyboard shortcuts for the buttons.
Have a look here How to Use Key Bindings.
An alternative to keylistener.
Here is a little Example it has a Button with focus and process a KeyEvent (F2).
On F2-clicked the Key-Binding process a ButtonClick which performed a System.out print.
public class Example {
static public void main( String[] s ) {
EventQueue.invokeLater( new Runnable() {
#Override
public void run() {
JFrame frame = new JFrame();
frame.getContentPane().setLayout( new BorderLayout() );
frame.setBounds( 50, 50, 600, 600 );
frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
final JButton button = new JButton( new AbstractAction("MyButton") {
#Override
public void actionPerformed( ActionEvent e ) {
System.out.println("Button Clicked");
}
});
frame.getContentPane().add( button );
frame.getRootPane().setDefaultButton( button );
KeyStroke f2 = KeyStroke.getKeyStroke("F2");
frame.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(f2, "clickButton");
frame.getRootPane().getActionMap().put("clickButton", new AbstractAction() {
#Override
public void actionPerformed( ActionEvent e ) {
button.doClick();
}
});
frame.setVisible( true );
// the Button has the focus
button.requestFocus();
// generate a KeyEvent 'F2'
KeyboardFocusManager.getCurrentKeyboardFocusManager().dispatchKeyEvent( new KeyEvent( frame, KeyEvent.KEY_PRESSED, 0, f2.getModifiers(), f2.getKeyCode(), f2.getKeyChar() ) );
}
});
}
}
The key event is called on the currently focused component (which is usually not the JFrame)