I'm trying to design a game like BeJeweled using java language
This is where I've reached so far :
public class Game {
public static void main(String[] args) throws InterruptedException {
final JFrame window = new JFrame();
window.setSize(508,669);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
final Grid g=new Grid();
Game.obj(g);
window.add(g);
window.setVisible(true);
window.setResizable(false);
window.repaint(2);
window.addMouseListener(new MouseListener(){
#Override
public void mouseClicked(MouseEvent e) {
int x=e.getX();
int y=e.getY();
for(int i=0;i<10;i++) {
for(int j=0;j<16;j++){
if(x>i*50+5 && x<i*50+54 && y>j*40+26 && y<j*40+26+39){
g.b[i][j]=g.a[i][j];
int q = x;
int w=y;
int r =x;
int t =y;
q-=50;
w-=40;
if( i>0&&g.a[i-1][j]==g.b[i][j]){
g.a[i][j]=0;
g.a[i-1][j]=0;
}
if( j>0&&g.a[i][j-1]==g.b[i][j]){
g.a[i][j]=0;
g.a[i][j-1]=0;
}
r+=50;
t+=40;
if(i<9&&g.a[i+1][j]==g.b[i][j]){
g.a[i][j]=0;
g.a[i+1][j]=0;
}
if(j<15&&g.a[i][j+1]==g.b[i][j]){
g.a[i][j]=0;
g.a[i][j+1]=0;
}
}
}
}
SwingUtilities.updateComponentTreeUI(window);
}
#Override
public void mousePressed(MouseEvent e) {
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
});
}
public static void obj(Grid g){
Random r =new Random();
for(int k=0;k<10;k++)
for(int l=0;l<16;l++)
g.a[k][l]=1+r.nextInt(4);
}
}
class Grid extends JPanel {
private Graphics Graphics;
#Override
public void paint(Graphics g) {
final Graphics g1 = g ;
this.setGraphics(g);
for(int i=0;i<600;i+=50)
for(int j=0;j<400;j+=40)
g.drawRect(i, j, i+50, j+40);
for(int i=0;i<10;i++)
for(int j=0;j<16;j++){
if(a[i][j]== 0) g.setColor(Color.WHITE);
if(a[i][j] == 1) g.setColor(Color.ORANGE);
if(a[i][j] == 2) g.setColor(Color.red);
if(a[i][j] == 3) g.setColor(Color.GREEN);
if(a[i][j] == 4) g.setColor(Color.cyan);
g.fillRect(i*50+1, j*40+1, 49, 39);
}
// Mouselis mouseptr = new Mouselis(g);
// this.addMouseListener(mouseptr);
// this.addMouseMotionListener(mouseptr);
}
public void setGraphics(Graphics Graphics) {
this.Graphics = Graphics;
}
int [][] a= new int[10][16];
int [][] b= new int[10][16];
}
In this design only the up down left right of rectangles are being checked for same color in the method mouse clicked. How can i make it check all the near rectangles for the one having same color ?
Please help Thanks
You have four if statements that check the adjacent rectangles for the same color as the one that was clicked. Here is the last one:
if(j<15&&g.a[i][j+1]==g.b[i][j]){
g.a[i][j]=0;
g.a[i][j+1]=0;
}
j, the vertical grid coordinate, is compared with 15 to be sure that j+1 is within bounds. Also, a rectangle in the 2d-array a is checked to see if it is equal to the rectangle in the 2d-array b that got clicked. If it is, you set it to 0 for Color.WHITE. Because the indices are i and j+1 this checks the rectangle directly below the clicked one.
To check a rectangle that is diagonally adjacent, change both indices by one.
The rectangle to the bottom right is g.a[i+1][j+1]. To access this rectangle without an error you need to be sure that both i+1 and j+1 are within the bounds of the array to avoid an error.
So, the if statement is
if(j<15 && i < 9 && g.a[i+1][j+1]==g.b[i][j]){ ...
You can figure out the rest.
Java is a strong Object-Oriented programming language - especially before Java8: I think that you should really work with more Objects that would hold their own responsibilities and behaviours.
Once you'll have a class that represents a Jewel, just implement some recursive method to know if it's part of some "Jewel streak". For example:
public class Jewel {
private final JewelType type; // Could be an Enum for example
// Many other stuff to add (like a constructor at least!)
public Collection<Jewel> getStreak() {
final Set<Jewel> res = new HashSet<>();
this._getStreak(res);
return res;
}
private void _getStreak(final Set<Jewel> streak) {
// Just leave the method if we've already visited this Jewel
if(!streak.add(this)) {
return;
}
// Assuming that this method returns a Collection of the Jewels that are stored West, North, South and East from this
for(final Jewel neighbour : Grid.getInstance().getJewelsAround(this)) {
if(neighbour.getJewelType().equals(this.getJewelType())) {
neighbour._getStreak(streak);
}
}
}
}
When trying to see if some Jewel is part of a streak that is long enough to be "destroyed", just check something like this:
Jewel b = Grid.getInstance().getJewelForCoordinates(x, y);
final Collection<Jewel> streak = b.getStreak();
if(streak.size() >= Game.MINIMUM_STREAK_SIZE) {
Grid.getInstance().destroyJewels(streak);
}
I just don't even have access to any Java editor/compiler right now so please excuse me, would my code present any mistyping. Even though I recommend to do many changes, I hope it can help you :)
By the way, if you don't want to override all the methods described by the MouseListener interface, use the following:
window.addMouseListener(new MouseAdapter() {
#Override
public void mouseClicked(final MouseEvent event) {
// Code to be executed on mouseClicked().
}
});
MouseAdapter is an abstract class that implements MouseListener and does nothing when receiving any event. You just have to override the methods that handle the events you're interested in ;)
Related
I am trying to make a chess program where I have an 8x8 array of JPanels which all require an addMouseListener but in this addMouseListener I need to make use of the index of that array for it to work, like this:
panels[0][0].addMouseListener(new MouseAdapter() {
public void mousePressed(MouseEvent e) {
panels[0][0].setBorder(BorderFactory.createEtchedBorder(EtchedBorder.RAISED));
}
public void mouseReleased(MouseEvent e) {
}
});
Since I have 64 JPanels that means I need to copy this 63 times and possible changes need to be copied as well. Is there any better, more efficient way to achieve this?
Since I have 64 JPanels that means I need to copy this 63 times
You can write a generic listener
MouseListener ml = new MouseAdapter()
{
#Override
public void mousePressed(MouseEvent e)
{
JPanel panel = (JPanel)e.getSource();
panel.setBorder(...);
}
};
Then in your looping code you just do:
panels[?][?].addMouseListener( ml );
You should always attempt to write generic listeners so the code can be reused.
You should use a loop for this:
for (int r = 0; r < panels.length; ++r) {
for (int c = 0; c < panels[r].length; ++c) {
// Do this to fix the "must be final" error:
final int row = r;
final int col = c;
panels[row][col].addMouseListener(new MouseAdapter() {
#Override
public void mousePressed(MouseEvent e) {
panels[row][col].setBorder(.....);
}
// ..... more
});
}
}
However, there are a few other additional ways to go about this. One is that you could write a class which saves the location of the panel:
class MyMouseListener extends MouseAdapter {
int panelRow;
int panelCol;
MyMouseListener(int panelRow, int panelCol) {
this.panelRow = panelRow;
this.panelCol = panelCol;
}
//.....
}
That is basically what the example using an anonymous class does behind the scenes. You could also save a reference to the panel itself.
Or you can use the getSource() method on the MouseEvent:
#Override
public void mousePressed(MouseEvent e) {
JPanel panelWhichWasClicked = (JPanel) e.getSource();
// .....
}
In that case, you only need 1 mouse listener which you can add to every panel.
When you have an array you must take different approach.
First your class should implement MouseListener which has 5 abstract methods but you are probably interested in mouseClicked:
public class Example implements MouseListener{
#Override
public void mouseClicked(MouseEvent e) {
JPanel panel = (JPanel) e.getSource(); // finding which panel is clicked on
}
#Override
public void mousePressed(MouseEvent e) {}
#Override
public void mouseReleased(MouseEvent e) {}
#Override
public void mouseEntered(MouseEvent e) {}
#Override
public void mouseExited(MouseEvent e) {}
}
Then somewhere inside your class you will do:
for(int i = 0; i < panels.length; i++){
for(int j = 0; j < panels[0].length; j++){
panels[0][0].addMouseListener(this);
}
}
the Code is below. right now what it does is it constantly moves the letter and I only want it to move a over one character when I press the next letter instead of going over more. Also the x+=2 is another method I used and It also didn't work.. This is basically supposed to be a typing class... Please help.It also places all the letters in the same place.. I need it to place them one space apart and I can't press the same letter twice or it just moves the letter
public class Type_Client extends Applet implements KeyListener,Runnable
{
boolean pickA,pickB,pickC,pickD,pickE,pickF,pickG,pickH,pickI,pickJ,pickK=false;
boolean pickL,pickM,pickN,pickO,pickP,pickQ,pickR,pickS,pickT,pickU,pickV=false;
boolean pickW,pickX,pickY,pickZ=false;
boolean space=false;
boolean run=true;
int x=10;
Type t1;
Thread thr;
public void init()
{
t1 = new Type();
thr=new Thread(this);
thr.start();
addKeyListener(this);
}
public void keyTyped(KeyEvent k)
{
}
public void keyReleased(KeyEvent k)
{
}
public void keyPressed(KeyEvent k)
{
if(k.getKeyCode()==KeyEvent.VK_A)
{
pickA=true;
k.consume();
}
if(k.getKeyCode()==KeyEvent.VK_B)
{
pickB=true;
k.consume();
}
if(k.getKeyCode()==KeyEvent.VK_C)
{
pickC=true;
k.consume();
}
if(k.getKeyCode()==KeyEvent.VK_SPACE)
{
space=true;
k.consume();
//Spce++;
}
}
public void run()
{
while(run==true)
{
try{
Thread.sleep(20);
}
catch(Exception e){};
repaint();
}
}
public void paint(Graphics g)
{
if(pickA)
{
g.drawString(" a",x,10);
}
if(pickB)
{
g.drawString(" b",x,10);
x++;
x++;
}
if(pickC)
{
g.drawString(" c",x,10);
x++;
x++;
}
}
}
public void stop()
{
}
public void start()
{
}
}
There are many problems with your code.
First, the infinite repaint loop:
public void run() {
while(run==true) {
try {
Thread.sleep(20);
}
catch(Exception e) { };
repaint();
}
}
This is bad. Remove it and the thread that starts it!
You only need to repaint the JFrame/JPanel/Applet when something changes in how the application will draw itself (or when the window geometry changes or the window is exposed, but the toolkit already handles all of those cases).
Ok, so when does something change? Possibly any time you press a key.
public void keyPressed(KeyEvent k) {
// Your existing code here
repaint();
}
Instead of repainting every 20ms you are now only repainting after a key is pressed. This is probably still too often. Shift, Alt, Ctrl, Meta, Caps Lock are all keys; if you press any of those, a repaint will be triggered despite your application not processing any of those keys. But at least is a minor inefficiency.
Second, x is a field instead of a local paint variable. It is initialized to 10 when the application starts, and incremented when paint is called.
g.drawString(" b",x,10);
Will draw the string " b" at (10,10) when the application is started and VK_B is pressed. But the next time redraw is called (20ms later with your existing code), it will draw it at (12,10), and then (14, 10), and then (16, 10), and so on.
Instead, you probably want:
public void paint(Graphics g) {
int x = 10;
// Remainder of paint code ...
}
So that each time paint is called, it draws the same way (unless something changes in the applications state which causes paint to intentionally draw differently).
drawString uses pixel coordinates. The letter "A" is more than 2 pixels wide in any legible font. For example, in this ASCII art, the letters "A" and "B" are 5 "pixels" wide. To leave a gap between the letters, "B" would need to be drawn at least 6 pixels to the right of "A".
* ****
* * * *
* * ****
***** * *
* * * *
* * ****
<-7px->
You can use Graphics#getFontMetrics to determine how much to advance the position of each character based on the preceding characters, with a given font.
Or, you could use a constant advance of (say) 16 pixels.
private final static int ADVANCE = 16;
public void paint(Graphics g) {
int x = 10;
if (pickA) {
g.drawString("a", x, 10);
x += ADVANCE;
}
if (pickB) {
g.drawString("b", x, 10);
x += ADVANCE;
}
// ...
}
Or you could let the toolkit do the work for you, and draw a String.
public void paint(Graphics g) {
StringBuilder sb = new StringBuilder(27);
if (pickA) {
sb.append("a ");
}
if (pickB) {
sb.append("b ");
}
// ... remainder cases ...
g.drawString(sb.toString(), 10, 10);
}
Finally, your 26 pick(Letter) variables are just plain awful. Consider a different method of recording which keys have been pressed.
Some options:
boolean picked [] = new boolean[26]; // boolean array (1 per letter)
Set<Integer> picked = new HashSet<>(); // A set of VK_ codes
Set<Character> picked = new HashSet<>(); // A set of characters
BitSet picked = new BitSet(26); // A set of bits (1 per letter)
Here is the smallest working example I can make for you. Adapt as needed.
#SuppressWarnings("serial")
public class Type_Client extends Applet {
private String typed = "";
private KeyAdapter adapter = new KeyAdapter() {
#Override
public void keyPressed(KeyEvent e) {
char ch = e.getKeyChar();
if (ch >= ' ' && ch <= '~') {
typed += ch;
repaint();
}
}
};
#Override
public void start() {
addKeyListener(adapter);
}
#Override
public void stop() {
removeKeyListener(adapter);
}
#Override
public void paint(Graphics g) {
super.paint(g);
g.drawString(typed, 10, 10);
}
}
Beginner Java developer. Trying to make a Tetris applet as part of my personal projects.
I'm at the point were I can draw tetris blocks onto the screen but I cannot make it vertically go downwards every second.
Code:
public class InitialScreen extends JApplet implements ActionListener {
public JPanel cards = new JPanel();
private JPanel introPanel = new JPanel();
public CardLayout c1 = new CardLayout();
public void init() {
initiateIntroScreen();
//game();
add(cards, BorderLayout.NORTH);
setSize(500, 100);
}
private void initiateIntroScreen() {
Frame title = (Frame)this.getParent().getParent();
cards.setLayout(c1);
JLabel centralWords = new JLabel("Click the following button options: 'Play' or 'Instructions'.");
JButton playBtn = new JButton("Play!");
JButton instructionsBtn = new JButton("Instructions!");
introPanel.add(centralWords);
introPanel.add(playBtn);
introPanel.add(instructionsBtn);
cards.add(introPanel,"1");
playBtn.addActionListener(this);
playBtn.addActionListener(new MainGame(cards,c1));
}
#Override
public void actionPerformed(ActionEvent e) {
setSize(300,410);
getContentPane().setBackground(Color.BLACK);
}
So this is the initial screen for the JApplet. Has two buttons. When you press the 'Play' button it goes to the Main Game Screen.
public class MainGame extends JApplet implements ActionListener {
private JPanel cards;
private CardLayout c1;
private JPanel gamePanel = new JPanel();
public MainGame(JPanel cards, CardLayout c1) {
this.c1 = c1;
this.cards = cards;
gamePanel.add(new Tetris_Block(new int[10][20]));
}
#Override
public void actionPerformed(ActionEvent e) {
JLabel scoreLbl = new JLabel("Score:");
gamePanel.add(scoreLbl);
cards.add(gamePanel,"game");
c1.show(cards,"game");
}
This is the game screen were Tetris is played. In the constructor it calls a Tetris Block.
public class Tetris_Block extends JComponent implements ActionListener {
static Color[] colors =
{darkGray, green, blue, red,
yellow, magenta, pink, cyan};
int[][] a;
int w, h;
static int horizontalPos, verticalPos = 0;
static int size = 20;
private int verticalPos1 = 1;
public Tetris_Block(int[][] a) {
this.a = a;
w = a.length;
h = a[0].length;
square_Block();
startTimer();
}
private void nextMove() {
verticalPos++;
verticalPos1++;
}
public void square_Block(){ //Horizontal || Vertical || Colour
//Horizontal never changes for this as I just want the blocks to go down.
a[0][verticalPos] = 3;
a[0][verticalPos1] = 3;
a[1][verticalPos] = 3;
a[1][verticalPos1] = 3;
}
#Override
public void actionPerformed(ActionEvent e) {
nextMove();
square_Block();
System.out.println(verticalPos);
}
public void startTimer(){
Timer timer = new Timer(1000,this);
timer.start();
}
public void paintComponent(Graphics g) {
for (int i = 0; i < w; i++) {
for (int j = 0; j < h; j++) {
g.setColor(colors[a[i][j]]);
g.fill3DRect(i * size, j * size,
size, size, true);
}
}
}
public Dimension getPreferredSize() {
return new Dimension(w * size, h * size);
}
My aim is to make the vertical position increment by 1 every second (So it goes down the window in second intervals.
I don't think the Timer function is the problem. When I print verticalPos it prints out the incremented value every second, however it's just displaying the new location onto the screen- that is the problem.
Image of window right now.
[img]http://i.imgur.com/au5fceO.png?1[/img]
Start by adding a call to repaint in you actionPerformed method of your Tetris_Block
#Override
public void actionPerformed(ActionEvent e) {
nextMove();
square_Block();
System.out.println(verticalPos);
// This is important
repaint();
}
This will schedule a paint event on the event queue which will eventually call your paintComponent method (indirectly)
This will get the block to start moving. The next problem you will have is you're not actually "removing" the block from it's previous position, so it will continue to bleed/grow down the screen
You could solve this by passing in the color of the block to square_Block, for example...
public void square_Block(int color) { //Horizontal || Vertical || Colour
//Horizontal never changes for this as I just want the blocks to go down.
a[0][verticalPos] = color;
a[0][verticalPos1] = color;
a[1][verticalPos] = color;
a[1][verticalPos1] = color;
}
And then "rest" the blocks of the current position, update the position and then set the new block colors;
#Override
public void actionPerformed(ActionEvent e) {
square_Block(0);
nextMove();
square_Block(3);
System.out.println(verticalPos);
repaint();
}
Your design here may be faulty. You need to have a game loop that runs in a separate thread. It has to be a separate thread from the main thread so the user can still click buttons. Once you have a loop in the separate thread you need to have a method that you call for every game tick. It's in that method that you update the coordinates of the blocks.
Game loop works like this:
1. Read state of the game and draw the blocks
2. Process user input.
3. Update game state
I know this is abstract but I hope it helps. Google about java games and game loops.
Im trying to make a game in java. My problem is that I dont have a initialized method or when I try to create one, my repaint() method substitute my initialized method. I need an initialized to generate my map. Because my map is a list of polygons and I want to set the background when clicked. So, if it is generating every time in a loop called by repaint() I cant do that.
My code:
Run Method:
#Override
public void run()
{
while (isRunning)
{
backPanel.repaint();
}
}
My backpanel class
int jogadas = 1;
Paint method:
#Override
public void paint(Graphics canvasOriginal)
{
super.paint(canvasOriginal);
canvas = (Graphics2D) canvasOriginal;
canvas.setColor(Color.BLACK);
mapa = new Mapa(canvas);
mapa.DrawMapa(100, 50, 5);
getJogada();
}
int getVez() {
if(jogadas % 2 == 0) {
return 1;
}
return 0;
}
void getJogada() {
Hexagono hex = mapa.selecionarHex(x, y);
if(!hex.getPrenchido()) {
if(jogador1.getNumero() == getVez()) {
hex.Preencher(jogador1.getColor());
} else {
hex.Preencher(jogador2.getColor());
}
jogadas++;
}
}
Obs: the mapa.selectHex selects the hex in a list. The hex.preencher() fill the hex polygon.
Result:
I am trying to to set up a KeyListener to respond to my keystrokes. I have already setup a mouselistener but for some reason I am un-able to get the keylistener to respond to any keystrokes.
I have created a class that implements KeyListener and overridden the functions. I then created an instance of the new class and added the handler to the JPanel and JFrame. Still no dice
public class main_program extends JFrame {
private int mX_cord, mY_cord,prior_selected_vertex, current_selected_vertex;
private int verticies_to_edge1, verticies_to_edge2;
private int radius =10;
private boolean vertex_selected1 = false, vertex_selected2 = false, edge_ready = false,delete_vertex_ready = false;
private Edge tempEdge = null;
private ArrayList<Integer> vertex_xcord = new ArrayList<Integer>();
private ArrayList<Integer> vertex_ycord = new ArrayList<Integer>();
private ArrayList<Edge> edge = new ArrayList<Edge>();
HandlerMouse handler = new HandlerMouse();
HandlerKey keyhand = new HandlerKey();
private JPanel masterPanel;
private JTextArea masterTextArea;
private JScrollPane masterScrollPane;
private Point point1, point2;
Graphics g;
public main_program(){
setTitle("Graph");
setSize(600, 400);
setDefaultCloseOperation(new JFrame().EXIT_ON_CLOSE);
//this must be set for custom layout of components
setLayout(null);
masterPanel = new JPanel();
masterPanel.setSize(600,300);
masterPanel.setLocation(0, 0);
masterPanel.setBackground(Color.WHITE);
masterPanel.addMouseListener(handler);
masterPanel.addMouseMotionListener(handler);
masterPanel.addKeyListener(keyhand);
masterTextArea = new JTextArea();
masterTextArea.setBackground(Color.green);
masterScrollPane = new JScrollPane();
masterScrollPane.add(masterTextArea);
masterScrollPane.setSize(600, 100);
masterScrollPane.setLocation(0, 300);
masterScrollPane.addMouseListener(handler);
masterScrollPane.addMouseListener(handler);
masterScrollPane.addKeyListener(keyhand);
add(masterPanel);
add(masterScrollPane);
setLocationRelativeTo(null);
setVisible(true);
}
public void paint(Graphics g){
super.paint(g);
for(int i = 0 ; i < vertex_xcord.size(); i++){
g.fillOval(vertex_xcord.get(i), vertex_ycord.get(i), radius, radius);
}
for(int i = 0 ; i<edge.size(); i++){
tempEdge = edge.get(i);
g.drawLine(vertex_xcord.get(tempEdge.vertex1), vertex_ycord.get(tempEdge.vertex1), vertex_xcord.get(tempEdge.vertex2), vertex_ycord.get(tempEdge.vertex2));
}
//g.fillOval(mX_cord, mY_cord, radius, radius);
//repaint();
}
private class HandlerKey implements KeyListener{
public void keyPressed(KeyEvent evt){
System.out.println("key pressed");
if(evt.getKeyCode() == KeyEvent.VK_ENTER && edge_ready){
edge.add(new Edge(prior_selected_vertex, current_selected_vertex));
edge_ready = false;
repaint();
}
}
public void keyReleased(KeyEvent evt){
System.out.println("key rel");
}
public void keyTyped(KeyEvent evt){
System.out.println("key type");
}
}
private class HandlerMouse implements MouseListener, MouseMotionListener{
public void mouseClicked(MouseEvent evt){
mX_cord = evt.getX()-5;
mY_cord = evt.getY()+15;
if( evt.getClickCount() == 1){
//mX_cord = evt.getX();
//mY_cord = evt.getY();
vertex_xcord.add(mX_cord);
vertex_ycord.add(mY_cord);
repaint();
}
else{
for(int i = 0 ; i < vertex_xcord.size(); i++){
if(Math.abs(vertex_xcord.get(i) - mX_cord ) < 15 && Math.abs(vertex_ycord.get(i) - mY_cord ) < 15 ){
if(vertex_selected1 == false){
prior_selected_vertex = i;
vertex_selected1 = true;
}
else{
current_selected_vertex = i;
vertex_selected2 = true;
}
System.out.println("YOU HAVE SELECTED A VERTEX: " + i);
break;
}
}
}
if(vertex_selected2 == true){
edge_ready = true;
verticies_to_edge1 = prior_selected_vertex;
verticies_to_edge2 = current_selected_vertex ;
vertex_selected1 = vertex_selected2 = false;
System.out.println("Ready for edge!");
}
else{
delete_vertex_ready = true;
}
}
public void mouseEntered(MouseEvent arg0)
{
}
public void mouseExited(MouseEvent arg0)
{
}
public void mousePressed(MouseEvent evt)
{
}
public void mouseReleased(MouseEvent arg0)
{
}
public void mouseDragged(MouseEvent e)
{
}
public void mouseMoved(MouseEvent e)
{
}
}
class Edge {
int vertex1, vertex2;
public Edge(int v1, int v2){
vertex1 = v1;
vertex2 = v2;
}
}
public static void main(String[] args){
main_program circle = new main_program();
}
}
You've got several problems with that program, and it suggests that you'd do well to read many of the Swing Q&A's on this site, because these problems (and your main problem) are quite common, and solutions are often posted.
As to your main problem, the problem again is very common: KeyListeners only work if the listened to component has focus. If it loses focus or is not focusable, then you're out of luck. The best solution is often not to use a KeyListener but rather the higher level and more flexible Key Bindings. Google will find the tutorials for you for this.
As for other problems with your code:
You're using null layout, a layout that leads to inflexible GUI's that are very difficult to upgrade and enhance, and that look terrible on all but your current platform and screen resolution. Solution: study and use the layout managers.
You're drawing directly into a JFrame's paint(Graphics g) method, which has risks as you risk messing up the painting of any and all of the JFrame's constituents by doing this. Much better to draw in a JPanel's paintComponent(Graphics g) method, and gain the benefit of Swing (rather than AWT) graphics including automatic double buffering.
Your class has a Graphics variable, g, which suggests that you're contemplating using a stored Graphics object either from a component or from the JVM. This increases the risk of your program throwing a NullPointerException when that Graphics object no longer exists, either that or drawing with it and but not seeing any effect. Solution: draw inside the painting method (again better with a JComponent's paintComponent method) only, or with the Graphics object from a BufferedImage.
You're adding a MouseListener directly to a JPanel but are drawing in a different component, the JFrame, and by doing so without taking insets into account, are placing points in the wrong location. Use the MouseListener on the same component that you're drawing on.
Again, please have a look around here, as I think you'll find a lot of treasures on this site that can be used to enhance your program.