Search code examples
javaapplet

i want to make an applet display a letter every time i type and then move over a letter every time i press it


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()
{
}
}

Solution

  • 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);
        }
    }