i was studying event handling and performed the following:
Created a JFrame without any component in it
i overridden the keyPressed() method in such a way that whenever a key is pressed from the keyboard,A button should appear in the frame(by using add() and then calling repaint()).
Now the thing i want to ask is that at the time of key press from the keyboard,nothing was being added to the frame,however after pressing the key when i resized the frame WINDOW,the button came out from nowhere in the frame....
what's happening?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
class MyFrame extends JFrame implements KeyListener
{
private JButton bt=new JButton();
MyFrame()
{
addKeyListener(this);
}
public void keyPressed(KeyEvent ke)
{
this.add(bt);
repaint();
}
public void keyTyped(KeyEvent ke)
{
}
public void keyReleased(KeyEvent ke)
{
}
}
public class MyClass /*class containing the main method*/
{
public static void main(String args[])
{
MyFrame frm=new MyFrame();
frm.setVisible(true);
frm.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
}
,nothing was being added to the frame,
The component was added to the frame. The problem is it has a size of (0, 0) so there is nothing to paint
however after pressing the key when i resized the frame WINDOW,the button came out from nowwhere in the frame
The layout manager gets invoked and the component is given a size and location based on the rules of the layout manager. So now you see the component.
When you add a component to a visible GUI the code is:
panel.add(...);
panel.revalidate();
panel.repaint();
You need to call revalidate after adding a component to the JFrame
this.add(bt);
revalidate();
repaint();
revalidate revalidates the component hierarchy to account for any new components that may have been added.
KeyListeners don't work well for Swing applications as KeyEvents require focus to work.
This is why in Swing it is better to use Key Bindings which allow you to map an Action to a KeyStroke even when a component doesn't have focus.
Related
I have a simple GUI with two components: a JTextField, and a custom component (MyComponent).
Initially the text field has focus, and clicking on the custom component causes that to have focus.
Currently I am manually setting the focus using requestFocusInWindow, but the focusLost event happens after the mousePressed event has finished. Is there any way to get the focusLost event to happen before the mousePressed event finishes?
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
public class Example {
public static void main(String[] args) {
JFrame frame = new JFrame("Example");
frame.setLayout(new FlowLayout());
JTextField textField = new JTextField(10);
textField.addFocusListener(new FocusAdapter() {
public void focusLost(FocusEvent event) {
System.out.println("focusLost");
}
});
frame.add(textField);
frame.add(new MyComponent());
frame.pack();
frame.setVisible(true);
}
private static class MyComponent extends JComponent {
public MyComponent() {
setFocusable(true);
addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent event) {
requestFocusInWindow();
System.out.println("mousePressed");
}
});
}
public Dimension getPreferredSize() {
return new Dimension(400, 300);
}
}
}
It also needs to be validated (and stored)
You can use an InputVerifier on the JTextField. It will validate the text in the text field before focus is transferred. If the data is not valid focus will stay on the text field.
Edit:
Can I remove this behaviour and instead revert the text field to the previous value if the data is not valid when losing focus?
Instead of using a JTextField use a JFormattedTextField it will revert the data to the previous value. You don't need to use an InputVerifier. Read the section from the Swing tutorial on How to Use Formatted Text Fields for more information and examples.
I'm having the following bug/problem and I havent been able to found solution yet on web or example of someone with similar issue.Basicaly I have a main frame that contains a panel of the same size(acting as the main panel) and When you press "Enter" an internal frame pop up(on top of where the playersprite is) acting as the inventory and then the control is passed to it and if you press "Enter" again the inventory is destroyed and control is passed back to the main panel.
the repaint function is called and the character and the map is then redrawn and this work about 90% of the time.The other 10% or less of time whenever the inventory is destroyed it seems the repaint is called(and work) except nothing is drawn its as if it draw on the destroyed panel because if I add a debug keypress that call repaint on the mainpanel(thescreen) everything is back to normal.
of course I could just repaint the character every loop in the run() method but thats terrible since I will only repaint if something changed(ie I moved)
I removed all the move and other code since they arent useful and still get the problem with the below code.You can think of the Character class as a plain drawn square.Anyone as any insight on why this is happening?
public class main extends JFrame implements Runnable{
private boolean gameRunning=true;
private Character Link;
private MainScreen theScreen;
public final int ScreenHeight=500;
public final int ScreenWidth=500;
public boolean inMenu=false;
Block ablock=new Block(200,200);
public class Inventory extends JInternalFrame{
public Inventory(){
setBounds(25,25,300,300);
setDefaultCloseOperation(HIDE_ON_CLOSE);
setVisible(true);
addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
int key=e.getKeyCode();
if(key==KeyEvent.VK_ENTER){
try{
setClosed(true);
theScreen.requestFocusInWindow();
theScreen.repaint();
inMenu=false;
}
catch(Exception ex){}
}
}});
}
}
class MainScreen extends JPanel{
MainScreen(){
super();
setIgnoreRepaint(true);
setFocusable(true);
setBounds(0,0,ScreenWidth,ScreenHeight);
setVisible(true);
setBackground(Color.white);
}
public void paintComponent(Graphics g){
super.paintComponent(g);
Link.draw(g);
g.drawImage(ablock.getImg(),ablock.getX(), ablock.getY(),null);
}
}
main(){
super();
final JDesktopPane desk = new JDesktopPane();
theScreen=new MainScreen();
add(theScreen);
theScreen.addKeyListener(new KeyAdapter() {
public void keyPressed(KeyEvent e){
int key=e.getKeyCode();
if(key==KeyEvent.VK_ENTER){
inMenu=true;
Inventory myInventory=new Inventory();
desk.add(myInventory);
myInventory.requestFocusInWindow();
}
}
});
add(desk);
try {
UIManager.setLookAndFeel(
UIManager.getSystemLookAndFeelClassName());
}
catch (Exception e) {}
setTitle("Project X");
setResizable(false);
Link=new Character();
setSize(500,500);
setVisible(true);
setDefaultCloseOperation(EXIT_ON_CLOSE);
}
public static void main(String[] args) {
main Game=new main();
new Thread(Game).start();
}
public void run(){
//omitted/irrelevant only contains a FPS count
}
}
}
Don't use KeyListeners. Use Key Bindings.
Don't use a Thread. Use a Swing Timer for animation so updates will be done on the EDT.
Don't use an Internal Frame for a popup window. Use a JDialog.
Do custom painting on a JPanel, not a JDesktopPane.
Don't use setIgnoreRepaints(). That is used for active rendering.
Don't use empty catch clauses.
Use standard Java naming conventions. Classes start with upper cases characters, variable names do not.
Don't use setBounds(). Use a Layout Manager.
I want to display a TextField only when user has entered a value in Input field
Here is my code:
import java.awt.BorderLayout;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JTextField;
public class PlayingAround {
JFrame frame;
JTextField display;
JTextField input;
public static void main(String[] args) {
PlayingAround obj = new PlayingAround();
obj.create();
}
private void create() {
frame = new JFrame();
display = new JTextField();
input = new JTextField();
display.setEditable(false);
display.setVisible(false);
input.addKeyListener(new Listener());
frame.add(BorderLayout.NORTH, display);
frame.add(BorderLayout.SOUTH, input);
frame.setSize(300, 300);
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
class Listener implements KeyListener {
#Override
public void keyTyped(KeyEvent e) {
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
display.setVisible(true);
display.setText(input.getText());
}
}
}
But my problem is that the Display JTextField doesn't becomes visible until there are some events like Resizing the Window, Minimizing and maximizing the Window.
I tried calling frame.repaint() in the keyReleased Method but even it has not helped.
You should call revalidate() and repaint() on the container that holds the JTextField after placing the text field component in the container. The revalidate() call sends a request to the container's layout managers to re-layout its components. The repaint() then requests that the JVM request of the paint manager to redraw the newly laid out container and its child components. The repaint() is not always needed but is usually a good idea.
Also, don't use a KeyListener for this, but rather a DocumentListener on the first text component's Document. This way, if the user empties the first text component, you can make the second text component disappear if desired. Also, text can be entered without key presses, and you want to allow for that.
I have a subclass of JFrame that uses a class extended from JPanel
public class HelloWorld extends JPanel implements KeyListener
I add an object of HelloWorld to the frame - app.add(helloWorld);. Now, when I press any keyboard key non of the KeyListener methods gets called and it seems that helloWorld doesn't have window focus. I have tried also to invoke helloWorld.requestFocusInWindow(); but still doesn't respond.
How can I make it respond to key press?
Did you set that KeyListener for your HelloWorld panel would be that panel itself? Also you probably need to set that panel focusable. I tested it by this code and it seems to work as it should
class HelloWorld extends JPanel implements KeyListener{
public void keyTyped(KeyEvent e) {
System.out.println("keyTyped: "+e);
}
public void keyPressed(KeyEvent e) {
System.out.println("keyPressed: "+e);
}
public void keyReleased(KeyEvent e) {
System.out.println("keyReleased: "+e);
}
}
class MyFrame extends JFrame {
public MyFrame() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(200,200);
HelloWorld helloWorld=new HelloWorld();
helloWorld.addKeyListener(helloWorld);
helloWorld.setFocusable(true);
add(helloWorld);
setVisible(true);
}
public static void main(String[] args) {
new MyFrame();
}
}
JPanel is not Focusable by default. That is, it can not respond to focus related events, meaning that it can not respond to the keyevents.
I would suggest trying to setFocusable on the pane to true and trying again. Make sure you click the panel first to make sure it receives focus.
Understand though, you WILL get strange focus traversal issues, as the panel will now receive input focus as the user navigates through your forms, making it seem like the focus has been lost some where.
Also, KeyListeners tend to be unreliable in this kind of situation (due to the way that the focus manager works).
simple you have to add
addKeylistener(new HelloWorld());
add this in MyFrame method;
HelloWorld() helloWorld = new HelloWorld();
this.addKeyListener(helloWorld);
Following is a program that displays a black screen with a messgage ALARM ! :
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;
public class displayFullScreen extends Window {
private JLabel alarmMessage = new JLabel("Alarm !");
public displayFullScreen() {
super(new JFrame());
setLayout(new FlowLayout(FlowLayout.CENTER));
alarmMessage.setFont(new Font("Cambria",Font.BOLD,100));
alarmMessage.setForeground(Color.CYAN);
add(alarmMessage);
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
setBounds(0,0,screenSize.width,screenSize.height);
setBackground(Color.black);
addKeyListener(new KeyAdapter() {
#Override
public void keyPressed(KeyEvent ke) {
escapeHandler(ke);
}
});
}
public void escapeHandler(KeyEvent ke) {
if(ke.getKeyCode() == ke.VK_ESCAPE) {
System.out.println("escaped !");
} else {
System.out.println("Not escaped !");
}
}
public static void main(String args[]) {
new displayFullScreen().setVisible(true);
}
}
I have set a key handler in this program . The handler catches the keys pressed when the focus is on window.
When the escape key will be pressed escaped ! should be displayed otherwise !escaped.
But nothing gets displayed,when i press a key. What is the problem ?
Maybe you want a window but you have two problems:
You should extend JWindow, not Window when using a Swing application
Even extending JWindow won't work because a JWindow won't receive KeyEvent unless it is parent JFrame is visible.
So you should be using a JFrame. If you don't want the title bar and borders, then you can use an undecorated JFrame.
Also, you should NOT be using a KeyListener because even on a JFrame key events are only dispatched to the focused component. Instead you should be using Key Bindings. In this case it seems you should be adding the binding to the root pane of the frame.
Extend JFrame instead and get rid of the super call.