I have problem with KeyListener, I've been searching solution but it should be working.
Unfortunately, it doesn't and i have no idea why. When i type up arrow, nothing happens.
I was reading about "Focus", but I don't know how this works, maybe you can give me some example, unnecessary to my problem.
public class Trawa extends JPanel implements KeyListener {
int wysokosc = 200;
public Trawa(){
addKeyListener(this);
setSize(200,600);
setBackground(Color.GREEN);
}
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
Color c1 = new Color(36,217,36);
g2d.setColor(c1);
g2d.fillRect(10, wysokosc, 100, 100);
c1 = new Color(0,0,0);
g2d.setColor(c1);
g2d.fillRect(10, wysokosc, 30, 30);
g2d.fillRect(80, wysokosc, 30, 30);
c1 = new Color(252,3,0);
g2d.setColor(c1);
g2d.fillRect(40, wysokosc+60 ,30,30);
}
#Override
public void keyPressed(KeyEvent arg0) {
int key = arg0.getKeyCode();
if(key == KeyEvent.VK_UP)
wysokosc-=100;
repaint();
}
#Override
public void keyReleased(KeyEvent arg0) {
}
#Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
Here is my main class with frame. Maybe the problem is here.
public class GUI extends JFrame{
public GUI(){
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
add(new Trawa());
setLayout(new GridLayout(1,5));
pack();
setSize(1300, 600);
setLocation(40, 100);
setVisible(true);
}
public static void main(String[] args) {
new GUI();
}
}
You have to understand how focus works before using a KeyListener.
Try calling setFocusable(true) from your JPanel's constructor.
You have done everything correctly, but you forgot to bind the key listener with your frame.
try this version of you GUI class
class GUI extends JFrame {
public GUI() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
Trawa t = new Trawa();//this is a JPanel as well as a KeyListner
add(t);
this.addKeyListener(t);
setLayout(new GridLayout(1, 5));
pack();
setSize(500, 400);
setLocation(40, 100);
setVisible(true);
}
}
as pointed by Kevin: the minimal change required is to set focus on the panel
public Trawa() {
addKeyListener(this);
setSize(200, 600);
setBackground(Color.GREEN);
setFocusable(true);
}
Related
So, I want to draw a ball whenever the user presses JButton. My problem is that the ball is not visible after I call revalidate() and repaint(). Am I forgetting something?
Here is my code, I have another class for the queue and stack that's why I extended Queueue. My buttons are visible and I know they work when I press them, it's jst that the ball doesn't show up on the screen. Earlier I tried to have my void paintComponent in my ActionListener but it would not work. I then wanted to just call the method but because of the Graphics g parameter it would not work as well. So I saw similar issue where someone suggested to use boolean
public class Main extends Queueue {
static boolean clicked = false;
public void paintComponent(Graphics g) {
if(clicked) {
g.setColor(Color.BLACK);
g.fillOval(60, 60, 15, 15);
}
}
public static void main (String[] args) {
Queueue qq = new Queueue();
JFrame f = new JFrame();
JPanel p = new JPanel();
JButton b1 = new JButton("Queue");
JButton b2 = new JButton("Stack");
JButton b3 = new JButton("Ball");
f.setSize(700, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
p.setBackground(Color.RED);
p.add(b1);
p.add(b2);
p.add(b3);
f.add(p);
f.setVisible(true);
b1.addActionListener(new ActionListener(){
#Override
public void actionPerformed(ActionEvent arg0) {
qq.Q();
}
});
b2.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
qq.S();
}
});
b3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clicked = true;
f.revalidate();
f.repaint();
}
});
You had some syntax errors which I corrected. I also trimmed it down to more clearly demonstrate the procedure. Here is a working version that just paints the ball.
public class Main extends JPanel {
static boolean clicked = false;
public static void main(String[] args) {
JFrame f = new JFrame();
Main m = new Main();
JButton b3 = new JButton("Ball");
f.setSize(700, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(m);
m.add(b3);
f.setVisible(true);
b3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clicked = true;
f.repaint();
}
});
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (clicked) {
g.setColor(Color.BLACK);
g.fillOval(60, 60, 15, 15);
}
}
}
Your class should extend JPanel
Add it to the JFrame.
Add the JButton to Main instance
and in paintComponent call super.paintComponent(g) first.
Check out The Java Tutorials for more information on how to paint.
In response to your comments, the following should work. The main issue is that you need to have the paintComponent inside a JPanel, not as a method in Queueue.
public class Main extends Queueue {
static boolean clicked = false;
public static void main(String[] args) {
JFrame f = new JFrame();
Main m = new Main();
JPanel panel = new JPanel() {
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
if (clicked) {
g.setColor(Color.BLACK);
g.fillOval(60, 60, 15, 15);
}
}
};
JButton b3 = new JButton("Ball");
f.setSize(700, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(panel);
panel.add(b3);
f.setVisible(true);
b3.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
clicked = true;
f.repaint();
}
});
}
}
How would I change the contents of a JFrame by dynamically clicking keys, in this example I want to change the contents through two JPanels I have created, when i click up I want to change to Panel2, and when I click down I want to change to Panel3, but I want the JFrames contents only to change (I want to stay in the same JFrame) there is no errors with the code, I am just a bit confused on how to solve this issue.
class Drawing extends JFrame implements KeyListener{
int num = 1;
public Drawing() {
Panel2 jPanel2 = new Panel2();
Panel3 jPanel3 = new Panel3();
if(num == 1){
add(jPanel2);
remove(jPanel3);
pack();
}
if(num == 2){
add(jPanel3);
remove(jPanel2);
pack();
}
// be nice to testers..
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
addKeyListener(this);
}
and then i have the keypressed method to change num to either 1 or 2 depending on what key is pressed (i also implemented keyReleased and keyTyped but I didn't include them to add space)
public void keyPressed(KeyEvent e){
if(e.getKeyCode() == e.VK_UP){
num = 1;
}
if(e.getKeyCode() == e.VK_DOWN){
num = 2;
}
}
public static void main(String args[]) {
new Drawing();
}
and here is the two panels that change the graphics of the page
class Panel2 extends JPanel {
Panel2() {
setPreferredSize(new Dimension(500,500));
}
public void paint(Graphics g) {
g.drawString("BLAH", 20, 20);
g.drawRect(200, 200, 200, 200);
repaint();
}
}
class Panel3 extends JPanel {
Panel3() {
// set a preferred size for the custom panel.
setPreferredSize(new Dimension(500,500));
}
public void paint(Graphics g) {
g.drawString("BURP", 20, 20);
g.drawRect(200, 200, 200, 200);
repaint();
}
}
Firstly, in your use case, don't use keyTyped event because it is only triggered
when the unicode character represented by this key is sent by the
keyboard to system input
. There is no system input in your UI. Checkout this for more details: KeyListener, keyPressed versus keyTyped
Instead, use keyPressed or keyReleased event.
Secondly, you need explicitly invoke add(jPanel2);remove(jPanel3); when you are handling the event. Set num = 1 doesn't do anything.
Thirdly, you need to call jPanel2.repaint(); after add(jPanel2);remove(jPanel3); to make sure the panel paint the content you want.
Fourthly, always call super.paint(g); to initialize the painting canvas correctly!
So, to put them all together, you have:
public class Drawing extends JFrame implements KeyListener {
int num = 1;
Panel2 jPanel2 = new Panel2();
Panel3 jPanel3 = new Panel3();
public Drawing() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setVisible(true);
addKeyListener(this);
setSize(300, 300);
}
#Override
public void keyTyped(KeyEvent e) {
}
private void changePanel() {
if (num == 1) {
remove(jPanel3);
add(jPanel2);
jPanel2.repaint();
pack();
}
if (num == 2) {
remove(jPanel2);
add(jPanel3);
jPanel3.repaint();
pack();
}
}
#Override
public void keyPressed(KeyEvent e) {
}
#Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == e.VK_UP) {
num = 1;
}
if (e.getKeyCode() == e.VK_DOWN) {
num = 2;
}
changePanel(); // do the actual swap of the panels
}
public static void main(String args[]) {
new Drawing();
}
}
class Panel2 extends JPanel {
Panel2() {
setPreferredSize(new Dimension(500, 500));
}
public void paint(Graphics g) {
super.paint(g); //always call!
g.drawString("BLAH", 20, 20);
g.drawRect(200, 200, 200, 200);
}
}
class Panel3 extends JPanel {
Panel3() {
setPreferredSize(new Dimension(500, 500));
}
public void paint(Graphics g) {
super.paint(g); //always call!
g.drawString("BURP", 20, 20);
g.drawOval(200, 200, 200, 200);
}
}
I was drawing my game on Canvas, all was god, but I changed it into a JPanel, but now its not working correctly, here are the codes, you can just copy them and you'll see where is the problem (I have a menu and after clicking on the button it should create new thread and there i want to draw, the problem in JPanel is that the button is able to see, its blinking and i can press it, in canvas it was fine, there wasn't any button). I solved it, that after clicking on the button I setted him unvisible (button.setVisible(false)), but these codes are just examples and in my game I have more buttons, so its not practical because I need them to see after the game ends. I think I just forgot an important method in JPanel, thx for help, codes:
//Main class representing menu
public class Sandbox extends JFrame{
Panel p = new Panel();
public static void main(String[] args) {
new Sandbox();
}
public Sandbox() {
setLayout(null);
setPreferredSize(new Dimension(200, 200));
setDefaultCloseOperation(EXIT_ON_CLOSE);
setResizable(false);
final JButton but = new JButton("Button");
but.setBounds(0, 0, 50, 50);
but.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
p.start();
}
});
add(p);
add(but);
pack();
setVisible(true);
}
}
//Drawing on Canvas -> working well
public class Panel extends Canvas implements Runnable {
Thread t;
public Panel() {
setSize(new Dimension(200, 200));
setVisible(false);
}
public void start() {
t = new Thread(this);
t.start();
setVisible(true);
}
public void draw() {
BufferStrategy b = getBufferStrategy();
if(b == null) {
createBufferStrategy(3);
return;
}
Graphics g = b.getDrawGraphics();
g.setColor(Color.red);
g.fillRect(0, 0, 200, 200);
g.dispose();
b.show();
}
#Override
public void run() {
while(!t.isInterrupted()) {
try {
draw();
t.sleep(200);
} catch (InterruptedException ex) {}
}
}
}
//Drawing on JPanel -> here i can press the button after first click on it
public class Panel extends JPanel implements Runnable {
Thread t;
public Panel() {
setSize(new Dimension(200, 200));
setVisible(false);
}
public void start() {
t = new Thread(this);
t.start();
setVisible(true);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.red);
g.fillRect(0, 0, 200, 200);
}
#Override
public void run() {
while(!t.isInterrupted()) {
try {
repaint();
t.sleep(200);
} catch (InterruptedException ex) {}
}
}
}
Not sure I understand exactly what you are trying to do but you do have a couple of problems:
the setVisible(true) method should be invoked AFTER you have added all the components to the frame and packed the frame.
by default the content pane of a JFrame uses a BorderLayout. You code is adding two components to the CENTER of the BorderLayout, but a BorderLayout only allows you to add one component to the CENTER, so only the last component added will be displayed.
I am trying to set background color of my screen to green.
My code so far:
package game;
import java.awt.*;
import javax.swing.JFrame;
public class Game extends JFrame {
public static void main(String[] args) {
DisplayMode dm = new DisplayMode(800, 600, 16, DisplayMode.REFRESH_RATE_UNKNOWN);
Game g = new Game();
g.run(dm);
}
public void run(DisplayMode dm) {
setBackground(Color.GREEN);
setForeground(Color.WHITE);
setFont(new Font("arial", Font.PLAIN, 24));
Screen s = new Screen();
try {
s.setFullScreen(dm, this);
try {
Thread.sleep(5000);
} catch (Exception E) {
}
} finally {
s.restoreScreen();
}
}
#Override
public void paint(Graphics g){
g.drawString("Check Screen", 200, 200);
}
}
When I run the program, I get this:
Screen should be green according to line:
setBackground(Color.GREEN);
Why does the background is not being set to green when I run the program?
You need to add a call to super.paint (g); in your paint () method.
#Override
public void paint(Graphics g){
super.paint (g);
g.drawString("Check Screen", 200, 200);
}
This will ensure that the component will draw itself correctly, including the background color, then draw your text.
Generally, whole approach is very bad. Even if it works with getContentPane().setBackground(Color.GREEN) it won't probably work because you are calling a Thread.sleep(5000) on EDT (or you will have issues soon or later). Use proper component for repetitive task's (refreshing of your screen): Swing Timer.
Instead of overriding JFrame's paint method, it's far better to use JPanel and to override it's paintComponent method. So, something like this:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class Game extends JFrame {
JFrame frame = new JFrame();
public Game() {
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new Panel());
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
#Override
public void run() {
new Game();
}
});
}
class Panel extends JPanel {
Timer timer;
Panel() {
setBackground(Color.BLACK);
setForeground(Color.WHITE);
refreshScreen();
}
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setFont(new Font("arial", Font.PLAIN, 24));
g.drawString("Check Screen", 200, 200);
}
public void refreshScreen() {
timer = new Timer(0, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
repaint();
}
});
timer.setRepeats(true);
//Aprox. 60 FPS
timer.setDelay(17);
timer.start();
}
#Override
public Dimension getPreferredSize() {
return new Dimension(650, 480);
}
}
}
This simple code is supposed to draw rectangle after hitting button, but it doesn't work.I didn't know how to do it and the only thing came to my mind was a boolean variable trigger but it doesn't seem to work.Any suggestions? Thank you.
public class testing extends JFrame implements ActionListener{
public JButton button;
public boolean check;
public void paint(Graphics g){
if(check==true){
g.setColor(Color.red);
g.fillRect(30, 50, 50, 50);
}
}
public void start(){
setLayout(new BorderLayout());
button=new JButton();
button.setPreferredSize(new Dimension(200,20));
button.setText("ClickMe");
button.addActionListener(this);
add(button, BorderLayout.SOUTH);
setSize(500,500);
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
check=true;
}
public static void main(String args[]){
testing x=new testing();
x.start();
}
}
You can call repaint inside actionPerformed.
public void actionPerformed(ActionEvent e) {
check=true;
repaint();
}