Giving a JPanel priority focus - java

I have a JPanel that is using a KeyListener as the content pane as the window; however, there are buttons and text fields in a grid layout on top of the JPanel.
How do I prioritize the focus of the JPanel that it retains focus after editing text or clicking the buttons so I can read the key input?

You just need to add a FocusListener on the focusLost event and then request focus back again. Something like this:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class JPanelFocus {
public static void main(String... argv) throws Exception {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame f = new JFrame("FocusTest");
JButton b = new JButton("Button");
final JPanel p = new JPanel();
p.add(b);
// Here is the KeyListener installed on our JPanel
p.addKeyListener(new KeyAdapter() {
public void keyTyped(KeyEvent ev) {
System.out.println(ev.getKeyChar());
}
});
// This is the bit that does the magic - make sure
// that our JPanel is always focussed
p.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent ev) {
p.requestFocus();
}
});
f.getContentPane().add(p);
f.pack();
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
// Make sure JPanel starts with the focus
p.requestFocus();
}
});
}
}
This won't work if you have fields that need to keep the focus though (you mentioned an editable text field). When should key events go to the text field and when should they go to the JPanel?

As an alternative, you could also just make the child components non-focusable.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyPanel extends JPanel implements KeyListener {
public MyPanel() {
this.setFocusable(true);
this.addKeyListener(this);
// for each component
JComboBox<String> comboBox = new JComboBox<String>();
comboBox.addItem("Item1");
this.add(comboBox);
// this is what keeps each child from intercepting KeyEvents
comboBox.setFocusable(false);
}
public void keyPressed(KeyEvent e) { ... }
public void keyTyped(KeyEvent e) { ... }
public void keyReleased(KeyEvent e) { ... }
public static void main(String[] args) {
// create a frame
JFrame frame = new JFrame();
frame.setSize(640, 480);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// add MyPanel to frame
MyPanel panel = new MyPanel();
frame.add(panel);
frame.setVisible(true);
}
}

Related

Mouse Coordinates keep getting on top of one another -Java

I am trying to get the mouse coordinates display in the panel but each time I move the cursor the message and new coordinates are being displayed on the previous one.I am using MouseMotionListener with JPanel. I can't figure out the problem.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.awt.event.MouseMotionListener;
public class Main extends JPanel implements MouseMotionListener {
public JLabel label;
public static void main(String[] args) {
new Main();
JFrame frame = new JFrame();
frame.setTitle("MouseCoordinates");
frame.setSize(400, 400);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
Container contentPane = frame.getContentPane();
contentPane.add(new Main());
frame.setVisible(true);
}
public Main() {
setSize(400, 400);
label = new JLabel("No Mouse Event Captured", JLabel.CENTER);
add(label);
addMouseMotionListener(this);
}
public void mouseMoved(MouseEvent e) {
label.setText("Mouse Cursor Coordinates => X:" + e.getX() + " |Y:" + e.getY());
}
public void mouseDragged(MouseEvent e) {}
}
You're creating Main twice.
public class Main extends JPanel implements MouseMotionListener {
public JLabel label;
public static void main(String[] args) {
Main m = new Main();// create an object and reference it
JFrame frame = new JFrame();
frame.setTitle("MouseCoordinates");
frame.setSize(400, 400);
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
System.exit(0);
}
});
Container contentPane = frame.getContentPane();
contentPane.add(m);
frame.setVisible(true);
}
//...
your problem was creating the Main object twice (which is a jpanel) and then the writing appeared twice. if you give the Main object a reference, then your problem should be fixed.

CardLayout with MouseListener not working

I am dealing with CardLayout. The JPanel I added as a contentpane to my JFrame has a CardLayout, and I want to swap between different panes. I have a working pane with buttons and five other image panes for the tutorial that are to be displayed only if a certain boolean value is true. I mean, every time this boolean is set true, five swaps should be done using next() method. My problem is that, after the first swap, the screen becomes blank. why does this happen?
Second question. I am using a MouseListener to swap, but I would like the program to do it automatically after some time. I tried to use Thread.sleep(5000), but I get a black screen.
This is my code, where card is a class variable in order to use it in the Mouselistener, parent is the working panel, already created, and ImagePanel is a class to create tutorialPanels, which adds to them the MouseListener below. Also, rootPane is a class pane.
card = new CardLayout();
rootPane = new JPanel(card);
this.getContentPane().add(rootPane);
//create panels to add
ImagePanel inputTutorial = new ImagePanel("backgroundIn.png");
ImagePanel numericTutorial = new ImagePanel("backgroundNum");
ImagePanel outputTutorial = new ImagePanel("backgroundOut");
ImagePanel commandTutorial = new ImagePanel("backgroundCom");
ImagePanel errorTutorial = new ImagePanel("backgroundErr");
ImagePanel finalTutorial = new ImagePanel("backgroundFinal");
//add the panels
rootPane.add(parent);
rootPane.add(inputTutorial);
rootPane.add(numericTutorial);
rootPane.add(outputTutorial);
rootPane.add(commandTutorial);
rootPane.add(errorTutorial);
rootPane.add(finalTutorial);
//set rootPane content panel
this.getContentPane().add(rootPane);
//if the boolean is true
if (firstTime == true) {
card.next(rootPane);
//other swaps done by mouselisteners
}
This is the mouselistener:
//mouse click listener
private class MouseActionListener implements MouseListener {
public void mousePressed (MouseEvent e) {
}
#Override
public void mouseClicked(MouseEvent arg0) {
card.next(rootPane);
}
#Override
public void mouseEntered(MouseEvent arg0) {
}
#Override
public void mouseExited(MouseEvent arg0) {
}
#Override
public void mouseReleased(MouseEvent arg0) {
}
}
I know that the listener is executed because I checked it.
Any help would be appreciated, thank you in advance.
"but I would like the program to do it automatically after some time. I tried to use Thread.sleep(5000)"
Don't use Thread.sleep. Instead use a javax.swing.Timer. You can learn more at How to Use Swing Timers
Here's a simple example, using some of your app format.
import java.awt.CardLayout;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class SlideShow {
public SlideShow() {
final CardLayout layout = new CardLayout();
final JPanel mainPanel = createMainPanel(layout);
Timer timer = new Timer(1000, new ActionListener(){
public void actionPerformed(ActionEvent e) {
layout.next(mainPanel);
}
});
timer.start();
JFrame frame = new JFrame();
frame.add(mainPanel);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private JPanel createMainPanel(CardLayout layout) {
JPanel panel = new JPanel(layout);
panel.add(new ImagePanel("mario.png"));
panel.add(new ImagePanel("bowser.png"));
panel.add(new ImagePanel("luigi.png"));
panel.add(new ImagePanel("koopa.png"));
panel.add(new ImagePanel("princess.png"));
return panel;
}
private class ImagePanel extends JPanel {
BufferedImage image;
public ImagePanel(String fileName) {
try {
image = ImageIO.read(getClass().getResource("/marioblobs/" + fileName));
} catch (IOException ex) {
ex.printStackTrace();
}
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(image, 0, 0, this);
}
#Override
public Dimension getPreferredSize() {
return image == null ? new Dimension(200, 200)
: new Dimension(image.getWidth(), image.getHeight());
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
new SlideShow();
}
});
}
}

Lose Focus on JTextField when clicking on the panel

I want to lose the focus on a JTextField when the user is clicking on the main panel.
setFocusable(true) doens't work for me.
If I am clicking on the main panel, the JTextField has still the focus and you can enter stuff.
Note: My JFrame is set to focusable (true).
I think since you want to get the focus on clicking the main panel, you should implement a simple MouseListener to do the job for you. Again since the panel (main panel) is added to the JFrame or rather it's set as the content pane, that is the place where setFocusable(true); should be called. The code below should sort out the problem :
mainPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
super.mouseReleased(e);
Focus.this.grabFocus();
}
});
Please note that Focus is the name of my class and am extending the JPanel before adding it to the JFrame.
Note: My JFrame is set to focusable (true).
for example
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
public class JPanelAndFocus {
private JFrame frm = new JFrame("JPanel_And_Focus");
private JPanel panel = new JPanel();
private JTextField one = new JTextField(10);
private JTextField two = new JTextField(10);
private JTextField three = new JTextField(10);
public JPanelAndFocus() {
//panel.setLayout(new FlowLayout());
panel.add(one);
panel.add(two);
panel.add(three);
panel.setFocusable(true);
panel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
//delayed should be important for events from DocumentListener / InputMask
#Override
public void run() {
//panel.requestFocus();
panel.requestFocusInWindow();
}
});
}
});
panel.setPreferredSize(new Dimension(400, 100));
frm.add(panel);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frm.setLocation(400, 300);
frm.pack();
frm.setVisible(true);
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
//one.requestFocus();
one.requestFocusInWindow();
}
});
}
public static void main(String[] args) {
javax.swing.SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
JPanelAndFocus jpaf = new JPanelAndFocus();
}
});
}
}
Whereas the different methods cited above didn't work for me, meaning that the focus remained on the JButton, I find e.getSource() works to set the component focus right
YourContainerPanel.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(MouseEvent e) {
JComponent clicked = (JComponent)e.getSource();
clicked.requestFocusInWindow();
}
});
Try this
this.getParent().requestFocus()

Change the textfield location of a JSpinner

I'd like to custom a little bit the basic JSpinner of swing java API.
Basically, I want to move the textfield component initially located on the left of the arrow buttons. Instead, the texfield would be lcoated between the two arrows of the spinner, so that there's one arrow on top of the textfield and one arrow below the texfield.
But I don't know how to proceed...
Anyone would have an idea?
You might be able to override the setLayout(LayoutManager) method of JSpinner to use a custom LayoutManager.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class SpinnerLayoutTest {
public JComponent makeUI() {
SpinnerNumberModel m = new SpinnerNumberModel(10, 0, 1000, 1);
JSpinner spinner = new JSpinner(m) {
#Override public void setLayout(LayoutManager mgr) {
super.setLayout(new SpinnerLayout());
}
};
JPanel p = new JPanel(new BorderLayout(5,5));
p.add(new JSpinner(m), BorderLayout.NORTH);
p.add(spinner, BorderLayout.SOUTH);
p.setBorder(BorderFactory.createEmptyBorder(16,16,16,16));
return p;
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override public void run() {
createAndShowGUI();
}
});
}
public static void createAndShowGUI() {
JFrame f = new JFrame();
f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
f.getContentPane().add(new SpinnerLayoutTest().makeUI());
f.setSize(320, 160);
f.setLocationRelativeTo(null);
f.setVisible(true);
}
}
class SpinnerLayout extends BorderLayout {
#Override public void addLayoutComponent(Component comp, Object constraints) {
if("Editor".equals(constraints)) {
constraints = "Center";
} else if("Next".equals(constraints)) {
constraints = "North";
} else if("Previous".equals(constraints)) {
constraints = "South";
}
super.addLayoutComponent(comp, constraints);
}
}
You could make an JPanel and put a JTextField and the JButtons inside it. That's was soulution, when I had the same problem.
EDIT:
Arrowbuttons can you create with:
new javax.swing.plaf.basic.BasicArrowButton(SwingConstants.NORTH);
Where SwingConstants.NORTH says that the arrow in the button is pointing upwards

Mouse events from JTextField do not get propagated

I am trying to listen to mouse events coming from both a JLabel and a JTextField. However, I am only able to listen to mouse events from JLabel, but not JTextField.
Consider this code:
class FieldPanel extends JPanel{
JLabel label;
JTextField text;
public FieldPanel(){
label = new JLabel("This is a test label");
text = new JTextField("This is a test field");
add(label);
add(text);
}
}
class OuterPanel extends JPanel{
FieldPanel fieldPanel;
public OuterPanel(){
fieldPanel = new FieldPanel();
fieldPanel.addMouseListener(new MouseAdapter(){
#Override
public void mousePressed(MouseEvent event) {
System.out.println("Mouse pressed !!");
}
});
add(fieldPanel);
}
}
public class UITest{
public static void main (String args[]){
JFrame frame = new JFrame();
OuterPanel outerPanel = new OuterPanel();
frame.getContentPane().add(outerPanel);
frame.pack();
frame.setVisible(true);
}
}
The 'Mouse Pressed !!' message is displayed when I click on the JLabel. However, it does not get displayed when I click on the JTextField. Why is this the case?
Thanks!
I think this is an interesting question which kinda stomp on the finding accidentally. I will explain using the snippet code below.
class FieldPanel extends JPanel
{
//JLabel label;
JTextField text;
public FieldPanel()
{
//label = new JLabel("This is a test label");
text = new JTextField("This is a test field");
//add(label);
add(text);
}
}
when you run the code with the changes above, what we expect the output only the text field right? Then if you click on the area near to the textfield outside region, check in your console output, it actually print out Mouse pressed !!
So I went a little deeper to study into JTextField, it actually consist of the JTextField and JTextComponent. When you called the constructor new JTextField("This is a test field");, the text is actually set into the JTextComponent and not JTextField and I guess that is why when you click the text, it does not trigger the mousePressed event but it trigger only the JTextField only.
Below is my full code. If you want the text field to aware of the mouse pressed, consider implements MouseAdapter() in your FieldPanel class and add addMouseListener(this) for text and label.
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
public class MyMouseEvent extends JPanel
{
public MyMouseEvent()
{
FieldPanel fieldPanel;
fieldPanel = new FieldPanel();
fieldPanel.addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent event)
{
System.out.println("Mouse pressed !!");
}
});
add(fieldPanel);
}
class FieldPanel extends JPanel
{
//JLabel label;
JTextField text;
public FieldPanel()
{
//label = new JLabel("This is a test label");
text = new JTextField("This is a test field");
//add(label);
add(text);
}
}
private static void createAndShowGUI()
{
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyMouseEvent evt = new MyMouseEvent();
evt.setOpaque(true);
frame.setContentPane(evt);
frame.pack();
frame.setVisible(true);
}
public static void main (String args[])
{
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run()
{
createAndShowGUI();
}
});
}
}
Thanks for all the answers.
I found some sort of workaround. I am changing my code so that I listen directly to the JTextField component, as opposed to listening to the panel.

Categories