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