Hi guys,
I'm now looking at what seems to be a nice exercise on my java book. Basically, the exercise asks me to build a virtual keyboard GUI - see screenshot - and when you press each key on your real keyboard the key you've pressed will change its background on the virtual keyboard and then return back to normal when released. It's an application to learn touch type effectively.
exercise.png
Now, what I'm planning to do is to have two JLabels at the very top, a JTextArea for the text and JButtons for all the keys. I think I'll group every element into a group and let them have their own JPanel, so say, for example, a JPanel for the JLabel and one for the JTextArea. For the keys instead, I could have one JPanel for each row of keys ad then all of them inside one "parent" JPanel.
The JPanel for the JLabels and the one for the JTextArea will have a borderLayout with each element positioned either NORTH or SOUTH. The JPanels wrapper for the keys will have a flowLayout, whereas the JPanel containing each row of keys will instead have a GridLayout instead so I can decide how many cols I need and apply some horizontal margin among each button.
The JFrame itself will have a borderLayout with the JLabel JPanel positioned NORTH, the JPanel containing the JTextArea will be CENTER and the wrapper JPanel for the keys positioned SOUTH.
So, something like this:

JFrame
    JPanel
        JLabel
        Jlabel
    JPanel
        JTextArea
    Jpanel
        Jpanel
            row of keys GridLayout
        Jpanel
            row of keys GridLayout
        Jpanel
            row of keys GridLayout
        etc

Does that sound reasonable to you guys? I thought I better finalize the structure before starting to code. What do you reckon? (I haven't got to the GridBagLayout as yet that's why I was thinking to use the GridLayout instead)
thanks

Looks reasonable to me - except I don't see why you have a panel (line 5) with only one thing in it - just add the text area directly.

For the event handlers on those keys you will DEFINITELY want to use the parametised handler technique from your previous project.

Looking at the first two rows of keys you do not want to try to do that with just a GridBagLayout!

Thanks JamesCherril. About that panel with the textArea on it, I thought it might help to keep things into their own panels. So when you say "add it directly", do you mean to add it directly to the JFrame with no intermediate panel?
OK will try to take the same approach when it comes to the handler.
Lastly,

Looking at the first two rows of keys you do not want to try to do that with just a GridBagLayout

so rather than GridBagLayout, do you think that GridLayout is a better idea?

What you have there looks like a perfect candidate for a GridLayout for the rows of keys, with each row being a FlowLayout.

so rather than GridBagLayout, do you think that GridLayout is a better idea?

Apart from rows 2/3 the keys do not line up vertically, so the whole thing is not a grid. I would just flow each row along a panel, with the 4 panels stacked vertically (see jwenting above)

when you say "add it directly", do you mean to add it directly to the JFrame with no intermediate panel?

Yes. the intermediate panel gains you nothing execept some unnecessary code and bit of unnecessary run time overhead.

Thinking about this a bit more...
it's a very interesting exercise. As soon as you think about the modifier key(s) it has great scope for good or bad design. It's small enough that a bad design will work OK, but just big enough to be a great learning project for better design.
If you start with laying out the GUI, then add the action listeners, you are almost guaranteed a huge pile of spaghetti code in the end.
If you start with some classes with their responibilities and public interfaces then you could end up with a demonstration-quality design based on principles that scale to larger systems. It's up to you, of course.

thanks guys. One more question: the exercise says the buttons should be JButtons, which is great, but what I'm thinking is to perhaps have 2 arrays, one array of JButtons and one of symbols, rather than declaring and creating 57+ JButton variables. But, there is one problem: the sizes of the buttons are not all the same, so if I do this with arrays, how am I going to set different sizes? Like the shift and the space bar, how do I distinguish those buttons from the other ones?
thanks

I would create a class, something like...

class KeyButton extends JButton implements ActionListener {
  char normalChar, shiftedChar;
  int width;
  static int HEIGHT = 20, DEFAULT_WIDTH=20;
  public KeyButton( char normalChar, char shiftedChar) {
      this(normalChar, shiftedChar, DEFAULT_WIDTH);
   }
  public KeyButton( char normalChar, char shiftedChar, int width) {
      ...
      addActionListener(this);
   }
  public void ActionPerformed( etc ) {
     // tell whoever that the letter was typed (interesting design qiestion)
  }

then I would have a KeyBoard class that extends JPanel and adds all the KeyButtons to itself as discussed earlier. Shift key is a special case, also interesting design decision!

Edited 1 Year Ago by JamesCherrill

Ah OK, that's some different syntax for me, not sure I understand how you envisage that to work, sorry, please bear with me.
Also, I need to clarify a few things about the exercise:
-when you press the buttons on the virtual keyboard, nothing happens, they don't generate any event, the event is generated when you press a key on the physical keyboard; when that happens the button on the GUI changes its background color whih then returns to normal when you release the button.
-the character you press on the physical keyboard will be displayed in the JTextArea;
Here is the actual brief:
"The application should display a virtual keyboard - the attachment I sent at the beginning of the thread - and should allow the user to watch what he is typing on the screen without looking at the actual keyboard. As the uses presses each key the application highlights the corresponding JButton on the GUI and adds the character to the JTextArea that shows what the user has typed so far. When the key is released reset its original background."

Let's see if I understand your code. So KeyButton extend JButton (is there a reason for that?) and implements ActionListener directly, which means that KeyButton will handle all the event handling.
1)You use two chars, but what do they stand for exactly? Maybe normalChar is for a 'normal button' and shiftedChar for a 'bigger one'?
2)You're using an overloaded constructor, the first one takes two parameters but not sure what this does and what "this" is referring to here:
this(normalChar, shiftedChar, DEFAULT_WIDTH);
3)the second constructor takes 3 parameters: so I will have to create two KeyButton objects one for a normal JButton and one for a larger JButton presumably...
4)the "this" parameters here addActionListener(this);, is it referring to the button, and therefore is passing the button?
So the first class KeyButton deals with just distinguishing the two buttons, perhaps?
On to the Keyboard class now. This just adds the buttons, but how does it know whether it's a big or small button? Also, unless of course I've completely misunderstood your code, do I store all the buttons and symbols in an array and then I call KeyButton to determine which button is which?
I've also read your post about the design (sorry it came through after I posted my previous reply), and I wouldn't want to end up with a lot of spaghetti code, but I must admit that the way I was approaching this was to do the GUI first and then the event handlers after

OK - I thought the idea was to be able to type on the screen? If it's not going to respond to touches then why use JButtons? Anyway - to answer your specific questions:

2 chars:
each key can generate 2 possible letters - upper/lower case alpha, or 8 vs asterisk etc - selected by the shift key.

extends JButton implements ActionListener
It's a specialised JButton - all the usual JButton stuff plus stuff specific to typewriter keys, so extending JButton. Implementing the action listener in the same object makes the code easy - no need to test which button was pressed, and all the other info about that key is already present.

Constructors.
Because keys vary in width there's a constructor that has an explicit width parameter in addition to the two chars. Because most keys are the same width there's a convenience constructor that just has the chars and sets the width to a default value. It does that by calling the other constructor, passing a default value for the width. In this context this refers to a constructor of the same class

addActionListener(this)
this is the current object (instance of KeyButton).

The KeyButton class represents a single typewriter key, with all its associated data and event handling. It's a kind of JButton so you can use it directly in a GUI.
You would create them in the Keyboard class's constructor, something like:

...
row2.add(new KeyButton('q', 'Q'));
row2.add(new KeyButton('w'.,'W'));
...
row4.add(new KeyButton(' ', ' ', 120)); // non-standard width

I'm skipping over a lot of stuff about non-character keys like shift or backspace - I would probably subclass KeyButton for those special keys, but that's a separated design question.

Thanks for taking the time to explain it. OK, that's clearer.

OK - I thought the idea was to be able to type on the screen? If it's not going to respond to touches then why use JButtons?

Not sure, that's what the exercise asks, so I'm just following the brief, but I can confirm that there is no functionality attached to the keys in the virtual keyboard, they literally do nothing, they're there only to be highlighted when needed. I guess they want me to use JButtons because it's presumably nice to have buttons that displays characters, I don't know. My understanding of the exercise is that we don't need to worry about shifted characters, in fact if you look at the screenshot you'll notice that numbers are only numbers they don't have the double character. Also about lower case and upper case character, I don't think there is any need for that because for the purpose of touch typing whether it's lower case or upper case it makes no difference (as you press the cap lock button and keep typing) so I don't think I'll include that. What I mean is that, I don't think they want to make it too complicated, considering that I'm not too far ahead in the book.
Good idea with the two constructors though, I can still use it to differentiate between widths.
So, let me code the classes then, and then I'll repost what I produced for feedback.
thanks for your help again.

AH sorry, since the JButtons on the actual keyboard don't generate any event, is it still worth having the KeyButton class implementing ActionListener (it would be now KeyListener though as it's the key in the actual keyboard generating the event) or should I move the event handling into the Keyboard class?
thanks

Given that the buttons don't actually do anything, or have any data associated with them, I can't see any need for anything more than a vanilla JButton. Oh well, I guess the previous discussions were useless for this particular exercise, but maybe added to your understanding of some wider issues?

Responding to the keyboard in the simple way is a surprisingly hazardous thing - in particular watch out for which component has the keyboard focus at any given time.

I don't think anything was useless, quite the contrary, it is valuable information.
So let's get back to the implementation and the best way forward.
I still need two constructors because I have two types of buttons anyway, a larger one and a smaller one, so I can create two separate JButton objects, unless you think it is better to put everything into one class. I mean I suppose when you say valilla JButton you literally mean a new JButton and nothing else (so no width involved)
Another sticky point is the JButtons creations. You showed me how to do that in the previous post, providing we go for two separate classes that it,

...
row2.add(new KeyButton('q', 'Q'));
row2.add(new KeyButton('w'.,'W'));
...
row4.add(new KeyButton(' ', ' ', 120)); // non-standard width

but I'm thinking, isn't this a little tedious (will have to do this 57+ times for each button), would an array be better or you think the above is a better approach?
thanks

Edited 1 Year Ago by Violet_82

A good example of why you shou;dn't start with the GUI details!
Think about the heart of the program. When the user types a key you want to make changes to the corresponding button. That implies you will have some kind of Map with keyboard chars as key and buttons as data. You can use that map to get the button to change its colour or whatever without knowing anything about where it is on the screen.
So there's no need for any other arrays to hold the buttons.
You are going to have to create and place 40-odd buttons one way or another, and because there's no logic to how the keyboard is layed out, there's no way to automate it.
All you can do is use a small method or two to eliminate repeated code. For example

JButton createButton(char letter) {
    create a JButton, set its text to letter, add it to the map with letter as its key
 }

so then you can

 row2.add(createButton('Q'));
 row2.add(createButton('W'));
 etc

ps when I say char I probably mean some kind of Key Code to allow for backspace, shift etc)

I suppose I said arrays because I didn't know any better, and I thought I could have one with chars and one with buttons to fill in with the chars and that would take only a few lines of code. But then I wouldn't know how to set the different sizes for the buttons.
I've never heard of Maps, so I checked them out and they're far ahead in the book, that's why I had no idea what they were :-). I've honestly got no idea how the book wants me to implement this exercise, I thought maybe with arrays, not sure
So you mean something like this I assume:
Map<char, button> myMap = new HashMap<char, button>();
where button would be an object. As far as the progam goes, how about this pseudocode:

create all the buttons
create labels and text area
add everything to the GUI
get keycodes of all keys used in the virtual keyboard
store the buttons in a map with key codes and the buttons
if user press a key on the actual keyboard
    get its keycode
    find that keycode in the map
    find the button corresponding to that keycode in the map and change the background
if user releases the key on the actual keyboard
    get its keycode
    find that keycode in the map
    find the button corresponding to that keycode in the map and change the background

OK cool. I thought I'd post a quick update.
I added a few elements, the labels and the textarea and then I got to the buttons. I followed your advice, well at least I attempted, look a bit more into Maps and hopefully created what you were expecting, a map containing the buttons as data but as for the key I used the integer keydown values, some found here https://msdn.microsoft.com/en-us/library/aa243025(v=vs.60).aspx and some here insteadhttp://www.west-wind.com/WestwindWebToolkit/samples/Ajax/html5andCss3/keycodechecker.aspx (I know it's for javascript but the codes seem to be the same.)
I haven't added anything to the GUI as yet except for the labels and the textArea and I thought let's check that the map is the way it should be before moving on.
If it is, the next thing would be to add the buttons and create the event handling presumably (interestingly if I add the import declarations

import java.awt.KeyListener;
import java.awt.KeyEvent;

without coding the event handling the application doesn't compile)

Code below:

 /*TouchType.java*/
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JLabel;
/* import java.awt.KeyListener;
import java.awt.KeyEvent; */
import javax.swing.JScrollPane;
//for the map
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;   
public class TouchType extends JFrame{
    //private JPanel mainPanel;//wrapping panel
    private JPanel labelPanel;//panel for labels
    private JLabel label1;
    private JLabel label2;
    private JTextArea textArea;
    private BorderLayout bLayout1;
    private BorderLayout bLayout2;
    private GridLayout gridLayout;
    /*button declarations*/
    Map<Integer,Object> mp=new HashMap<Integer,Object>();//declaring a map object



    public TouchType(){//constructor
        super("Typing application");
        //mainPanel = new JPanel();//wrapping panel
        //adding elements to Map
        mp.put(new Integer(222), new JButton("~"));
        mp.put(new Integer(48), new JButton("1"));
        mp.put(new Integer(49), new JButton("2"));
        mp.put(new Integer(50), new JButton("3"));
        mp.put(new Integer(51), new JButton("4"));
        mp.put(new Integer(52), new JButton("5"));
        mp.put(new Integer(53), new JButton("5"));
        mp.put(new Integer(54), new JButton("6"));
        mp.put(new Integer(55), new JButton("7"));
        mp.put(new Integer(56), new JButton("8"));
        mp.put(new Integer(57), new JButton("9"));
        mp.put(new Integer(109), new JButton("-"));
        mp.put(new Integer(107), new JButton("+"));
        mp.put(new Integer(8), new JButton("Backspace"));
        mp.put(new Integer(9), new JButton("Tab"));
        mp.put(new Integer(81), new JButton("q"));
        mp.put(new Integer(87), new JButton("w"));
        mp.put(new Integer(69), new JButton("e"));
        mp.put(new Integer(82), new JButton("r"));
        mp.put(new Integer(84), new JButton("t"));
        mp.put(new Integer(89), new JButton("y"));
        mp.put(new Integer(85), new JButton("u"));
        mp.put(new Integer(73), new JButton("i"));
        mp.put(new Integer(79), new JButton("o"));
        mp.put(new Integer(80), new JButton("p"));
        mp.put(new Integer(221), new JButton("["));
        mp.put(new Integer(219), new JButton("]"));
        mp.put(new Integer(220), new JButton("\\"));
        mp.put(new Integer(20), new JButton("Caps"));
        mp.put(new Integer(65), new JButton("a"));
        mp.put(new Integer(83), new JButton("s"));
        mp.put(new Integer(68), new JButton("d"));
        mp.put(new Integer(70), new JButton("f"));
        mp.put(new Integer(71), new JButton("g"));
        mp.put(new Integer(72), new JButton("h"));
        mp.put(new Integer(74), new JButton("j"));
        mp.put(new Integer(75), new JButton("k"));
        mp.put(new Integer(76), new JButton("l"));
        mp.put(new Integer(186), new JButton(";"));
        mp.put(new Integer(187), new JButton("="));
        mp.put(new Integer(13), new JButton("Enter"));
        mp.put(new Integer(16), new JButton("Shift"));
        mp.put(new Integer(90), new JButton("z"));
        mp.put(new Integer(88), new JButton("x"));
        mp.put(new Integer(67), new JButton("c"));
        mp.put(new Integer(86), new JButton("v"));
        mp.put(new Integer(66), new JButton("b"));
        mp.put(new Integer(78), new JButton("n"));
        mp.put(new Integer(77), new JButton("m"));
        mp.put(new Integer(188), new JButton(","));
        mp.put(new Integer(190), new JButton("."));
        mp.put(new Integer(191), new JButton("?"));
        mp.put(new Integer(38), new JButton("up"));
        mp.put(new Integer(32), new JButton("Spacebar"));
        mp.put(new Integer(37), new JButton("Left"));
        mp.put(new Integer(40), new JButton("Bottom"));
        mp.put(new Integer(39), new JButton("Right"));


        labelPanel = new JPanel(); //panel for labels
        bLayout1 = new BorderLayout();//for JFrame
        bLayout2 = new BorderLayout();//for labelPanel
        textArea = new JTextArea(5,15);
        label1 = new JLabel("Type some text using your keyboard. The keys you press will be highlighted and the text will be displayed");
        label2 = new JLabel("Note: clicking the button with your mouse will not perform any action");

        setLayout(bLayout1);//set layout of JFrame
        labelPanel.setLayout(bLayout2);//layout of labelPanel

        //add(mainPanel);//add the main panel to the JFrame
        labelPanel.add(label1, BorderLayout.NORTH);//add label to labelPanel
        labelPanel.add(label2, BorderLayout.CENTER);//add label to labelPanel
        add(labelPanel, BorderLayout.NORTH);//add labelPanel to JFrame;
        add(new JScrollPane(textArea), BorderLayout.CENTER);//add textArea to the JFrame

    }//end of constructor
}//end of TouchType class

Well, I had a look at it earlier on but I wasn't sure how that works, if this is what you're referring to http://docs.oracle.com/javase/7/docs/api/java/awt/event/KeyEvent.html
Reading that again now, you mean like numbers should be from VK_0 to VK_9 and letters from VK_A to VK_Z ?

Once I sort that out, is it possible to add the buttons to the row panels (assuming I have something like this

private JPanel row1;
private Jpanel row2;
private Jpanel row3;
private Jpanel row4;
private Jpanel row5;

) directly from within the Map declaration? SO, say, something like this:

mp.put(new Integer(xxx), row1.add(new JButton("~")));
...

thanks

Yes, the VK_ constants are the ones that refer to buttons on a keyboard. They're the ones you need.
mp.put(new Integer(xxx), row1.add(new JButton("~")));
You don't need the new Integer because Java "boxing" will automatically convert an int to an Integer.
You can't use row1.add in there because add does not return a value, and anyway you don't want another new button there because you want to use the one you already created in your map.
Plese go back a couple of posts and perhaps now it will be clearer why I suggested a little method to create the button, add it to the map, amd return it ready for adding to a row. Only now you will want to use the key code as well so it looks more like
row2.add(createButton(VK_Q, '"Q");

Very good point JamesCherrill. I thought it would have been quicker to add it my way if that was possible, sorry.
OK, I think I'm slowly getting closer, but I must have done something silly as it's not compiling anymore and I'm getting errors due to the int constants I'm using. OK one step at a time.
First,I think I've implemented what you suggested, put loads of comments so that it should be easy to read as well, if there is any need to do so.
-I've added the method to create a button and insert it into the Map, but I created it with a void return as I didn't think I'd need it to return the button or anything for that matter, is that OK? Yours in the older post has a return type of JButton, I wasn't sure if mine had to do that too

private void createButton(int keyCode, String name){
        newButton = new JButton(name);
        mp.put(keyCode, newButton);
    }

and this is how I call it:

...
row5.add(createButton(VK_LEFT, "Left"));        
row5.add(createButton(VK_DOWN, "Bottom"));      
row5.add(createButton(VK_RIGHT, "Right"));
...

I've also created 5 JPanels for the rows with a GidLayout (5 different GridLayout objects) and added, as above, the buttons to the relevant
Here is the full code (I've found a mistake in the import KeyListener and KeyEvent, now amended

import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;




 /*TouchType.java*/
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JTextArea;
import javax.swing.JButton;
import javax.swing.JLabel;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import javax.swing.JScrollPane;
//for the map
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;   
public class TouchType extends JFrame{
    //private JPanel mainPanel;//wrapping panel
    private JPanel labelPanel;//panel for labels
    private JLabel label1;//first label
    private JLabel label2;//second label
    private JPanel keysPanel;//holding the keys
    private JButton newButton;
    //rows panels for keys. 5 rows.
    private JPanel row1;
    private JPanel row2;
    private JPanel row3;
    private JPanel row4;
    private JPanel row5;
    private JTextArea textArea;//text area
    private BorderLayout bLayout1;
    private BorderLayout bLayout2;
    private GridLayout gridLayoutRow1;
    private GridLayout gridLayoutRow2;
    private GridLayout gridLayoutRow3;
    private GridLayout gridLayoutRow4;
    private GridLayout gridLayoutRow5;

    Map<Integer,Object> mp=new HashMap<Integer,Object>();//declaring a map object 

    public TouchType(){//constructor
        super("Typing application");    

        //creating JPanels
        labelPanel = new JPanel(); //panel for labels
        keysPanel = new JPanel();//panel wrapper for key rows
        row1 = new JPanel();//panel for row1
        row2 = new JPanel();//panel for row2
        row3 = new JPanel();//panel for row3
        row4 = new JPanel();//panel for row4
        row5 = new JPanel();//panel for row5

        //creating a button and adding it to the appropriate JPanel
        row1.add(createButton(VK_DEAD_TILDE, "~"));     
        row1.add(createButton(VK_1, "1"));      
        row1.add(createButton(VK_2, "2"));
        row1.add(createButton(VK_3, "3"));      
        row1.add(createButton(VK_4, "4"));      
        row1.add(createButton(VK_5, "5"));
        row1.add(createButton(VK_6, "6"));
        row1.add(createButton(VK_7, "7"));      
        row1.add(createButton(VK_8, "8"));      
        row1.add(createButton(VK_9, "9"));      
        row1.add(createButton(VK_MINUS, "-"));      
        row1.add(createButton(VK_PLUS, "+"));       
        row1.add(createButton(VK_BACK_SPACE, "Backspace"));
        row2.add(createButton(VK_TAB, "Tab"));      
        row2.add(createButton(VK_Q, "q"));      
        row2.add(createButton(VK_W, "w"));      
        row2.add(createButton(VK_E, "e"));      
        row2.add(createButton(VK_R, "r"));      
        row2.add(createButton(VK_T, "t"));      
        row2.add(createButton(VK_Y, "y"));      
        row2.add(createButton(VK_U, "u"));      
        row2.add(createButton(VK_I, "i"));      
        row2.add(createButton(VK_O, "o"));
        row2.add(createButton(VK_P, "p"));      
        row2.add(createButton(VK_OPEN_BRACKET, "["));       
        row2.add(createButton(VK_CLOSE_BRACKET, "]"));      
        row2.add(createButton(VK_BACK_SLASH, "\\"));        
        row3.add(createButton(VK_CAPS_LOCK, "Caps"));
        row3.add(createButton(VK_A, "a"));      
        row3.add(createButton(VK_S, "s"));      
        row3.add(createButton(VK_D, "d"));      
        row3.add(createButton(VK_F, "f"));      
        row3.add(createButton(VK_G, "g"));      
        row3.add(createButton(VK_H, "h"));      
        row3.add(createButton(VK_J, "j"));      
        row3.add(createButton(VK_K, "k"));      
        row3.add(createButton(VK_L, "l"));      
        row3.add(createButton(VK_SEMICOLON, ";"));      
        row3.add(createButton(VK_EQUALS, "="));     
        row3.add(createButton(VK_ENTER, "Enter"));      
        row4.add(createButton(VK_SHIFT, "Shift"));      
        row4.add(createButton(VK_Z, "z"));      
        row4.add(createButton(VK_X, "x"));      
        row4.add(createButton(VK_C, "c"));      
        row4.add(createButton(VK_V, "v"));      
        row4.add(createButton(VK_B, "b"));      
        row4.add(createButton(VK_N, "n"));      
        row4.add(createButton(VK_M, "m"));      
        row4.add(createButton(VK_COMMA, ","));      
        row4.add(createButton(VK_PERIOD, "."));     
        row4.add(createButton(VK_SLASH, "/"));      
        row4.add(createButton(VK_UP, "up"));        
        row5.add(createButton(VK_SPACE, ""));       
        row5.add(createButton(VK_LEFT, "Left"));        
        row5.add(createButton(VK_DOWN, "Bottom"));      
        row5.add(createButton(VK_RIGHT, "Right"));  

        //SORT OUT THE LAYOUTS
        //border layouts
        bLayout1 = new BorderLayout();//for JFrame
        bLayout2 = new BorderLayout();//for labelPanel
        //creating gridLayout objects for rows
        gridLayoutRow1 = new GridLayout(1,14);
        gridLayoutRow2 = new GridLayout(1,14);
        gridLayoutRow3 = new GridLayout(1,13);
        gridLayoutRow4 = new GridLayout(1,12);
        gridLayoutRow5 = new GridLayout(1,4);
        //creeating elements
        textArea = new JTextArea(5,15);
        label1 = new JLabel("Type some text using your keyboard. The keys you press will be highlighted and the text will be displayed");
        label2 = new JLabel("Note: clicking the button with your mouse will not perform any action");

        //set layouts
        setLayout(bLayout1);//set layout of JFrame
        labelPanel.setLayout(bLayout2);//layout of labelPanel
        row1.setLayout(gridLayoutRow1);//set layout of row1
        row2.setLayout(gridLayoutRow2);//set layout of row2
        row3.setLayout(gridLayoutRow3);//set layout of row3
        row4.setLayout(gridLayoutRow4);//set layout of row4
        row5.setLayout(gridLayoutRow5);//set layout of row5

        //add elements to their panels
        labelPanel.add(label1, BorderLayout.NORTH);//add label to labelPanel, top
        labelPanel.add(label2, BorderLayout.CENTER);//add label to labelPanel, middle
        add(labelPanel, BorderLayout.NORTH);//add labelPanel to JFrame, top
        add(new JScrollPane(textArea), BorderLayout.CENTER);//add textArea to the JFrame, middle
        add(keysPanel, BorderLayout.SOUTH);//add the keysPanel wrapper to the JFrame, bottom

    }//end of constructor
    //creates a button and adds it to the Map
    private void createButton(int keyCode, String name){
        newButton = new JButton(name);
        mp.put(keyCode, newButton);
    }
}//end of TouchType class

And here is the nasty errors I get, 56 to be precise

G:\JAVA\GUI\2015\createFrames\keyboard>javac *.java
TouchType.java:54: error: cannot find symbol
                row1.add(createButton(VK_DEAD_TILDE, "~"));
                                      ^
  symbol:   variable VK_DEAD_TILDE
  location: class TouchType
TouchType.java:55: error: cannot find symbol
                row1.add(createButton(VK_1, "1"));
                                      ^
  symbol:   variable VK_1
  location: class TouchType
TouchType.java:56: error: cannot find symbol
                row1.add(createButton(VK_2, "2"));
                                      ^
  symbol:   variable VK_2
  location: class TouchType
TouchType.java:57: error: cannot find symbol
                row1.add(createButton(VK_3, "3"));
                                      ^
  symbol:   variable VK_3
  location: class TouchType
TouchType.java:58: error: cannot find symbol
                row1.add(createButton(VK_4, "4"));
                                      ^
  symbol:   variable VK_4
  location: class TouchType
TouchType.java:59: error: cannot find symbol
                row1.add(createButton(VK_5, "5"));
                                      ^
  symbol:   variable VK_5
  location: class TouchType
TouchType.java:60: error: cannot find symbol
                row1.add(createButton(VK_6, "6"));
                                      ^
  symbol:   variable VK_6
  location: class TouchType
TouchType.java:61: error: cannot find symbol
                row1.add(createButton(VK_7, "7"));
                                      ^
  symbol:   variable VK_7
  location: class TouchType
TouchType.java:62: error: cannot find symbol
                row1.add(createButton(VK_8, "8"));
                                      ^
  symbol:   variable VK_8
  location: class TouchType
TouchType.java:63: error: cannot find symbol
                row1.add(createButton(VK_9, "9"));
                                      ^
  symbol:   variable VK_9
  location: class TouchType
TouchType.java:64: error: cannot find symbol
                row1.add(createButton(VK_MINUS, "-"));
                                      ^
  symbol:   variable VK_MINUS
  location: class TouchType
TouchType.java:65: error: cannot find symbol
                row1.add(createButton(VK_PLUS, "+"));
                                      ^
  symbol:   variable VK_PLUS
  location: class TouchType
TouchType.java:66: error: cannot find symbol
                row1.add(createButton(VK_BACK_SPACE, "Backspace"));
                                      ^
  symbol:   variable VK_BACK_SPACE
  location: class TouchType
TouchType.java:67: error: cannot find symbol
                row2.add(createButton(VK_TAB, "Tab"));
                                      ^
  symbol:   variable VK_TAB
  location: class TouchType
TouchType.java:68: error: cannot find symbol
                row2.add(createButton(VK_Q, "q"));
                                      ^
  symbol:   variable VK_Q
  location: class TouchType
TouchType.java:69: error: cannot find symbol
                row2.add(createButton(VK_W, "w"));
                                      ^
  symbol:   variable VK_W
  location: class TouchType
TouchType.java:70: error: cannot find symbol
                row2.add(createButton(VK_E, "e"));
                                      ^
  symbol:   variable VK_E
  location: class TouchType
TouchType.java:71: error: cannot find symbol
                row2.add(createButton(VK_R, "r"));
                                      ^
  symbol:   variable VK_R
  location: class TouchType
TouchType.java:72: error: cannot find symbol
                row2.add(createButton(VK_T, "t"));
                                      ^
  symbol:   variable VK_T
  location: class TouchType
TouchType.java:73: error: cannot find symbol
                row2.add(createButton(VK_Y, "y"));
                                      ^
  symbol:   variable VK_Y
  location: class TouchType
TouchType.java:74: error: cannot find symbol
                row2.add(createButton(VK_U, "u"));
                                      ^
  symbol:   variable VK_U
  location: class TouchType
TouchType.java:75: error: cannot find symbol
                row2.add(createButton(VK_I, "i"));
                                      ^
  symbol:   variable VK_I
  location: class TouchType
TouchType.java:76: error: cannot find symbol
                row2.add(createButton(VK_O, "o"));
                                      ^
  symbol:   variable VK_O
  location: class TouchType
TouchType.java:77: error: cannot find symbol
                row2.add(createButton(VK_P, "p"));
                                      ^
  symbol:   variable VK_P
  location: class TouchType
TouchType.java:78: error: cannot find symbol
                row2.add(createButton(VK_OPEN_BRACKET, "["));
                                      ^
  symbol:   variable VK_OPEN_BRACKET
  location: class TouchType
TouchType.java:79: error: cannot find symbol
                row2.add(createButton(VK_CLOSE_BRACKET, "]"));
                                      ^
  symbol:   variable VK_CLOSE_BRACKET
  location: class TouchType
TouchType.java:80: error: cannot find symbol
                row2.add(createButton(VK_BACK_SLASH, "\\"));
                                      ^
  symbol:   variable VK_BACK_SLASH
  location: class TouchType
TouchType.java:81: error: cannot find symbol
                row3.add(createButton(VK_CAPS_LOCK, "Caps"));
                                      ^
  symbol:   variable VK_CAPS_LOCK
  location: class TouchType
TouchType.java:82: error: cannot find symbol
                row3.add(createButton(VK_A, "a"));
                                      ^
  symbol:   variable VK_A
  location: class TouchType
TouchType.java:83: error: cannot find symbol
                row3.add(createButton(VK_S, "s"));
                                      ^
  symbol:   variable VK_S
  location: class TouchType
TouchType.java:84: error: cannot find symbol
                row3.add(createButton(VK_D, "d"));
                                      ^
  symbol:   variable VK_D
  location: class TouchType
TouchType.java:85: error: cannot find symbol
                row3.add(createButton(VK_F, "f"));
                                      ^
  symbol:   variable VK_F
  location: class TouchType
TouchType.java:86: error: cannot find symbol
                row3.add(createButton(VK_G, "g"));
                                      ^
  symbol:   variable VK_G
  location: class TouchType
TouchType.java:87: error: cannot find symbol
                row3.add(createButton(VK_H, "h"));
                                      ^
  symbol:   variable VK_H
  location: class TouchType
TouchType.java:88: error: cannot find symbol
                row3.add(createButton(VK_J, "j"));
                                      ^
  symbol:   variable VK_J
  location: class TouchType
TouchType.java:89: error: cannot find symbol
                row3.add(createButton(VK_K, "k"));
                                      ^
  symbol:   variable VK_K
  location: class TouchType
TouchType.java:90: error: cannot find symbol
                row3.add(createButton(VK_L, "l"));
                                      ^
  symbol:   variable VK_L
  location: class TouchType
TouchType.java:91: error: cannot find symbol
                row3.add(createButton(VK_SEMICOLON, ";"));
                                      ^
  symbol:   variable VK_SEMICOLON
  location: class TouchType
TouchType.java:92: error: cannot find symbol
                row3.add(createButton(VK_EQUALS, "="));
                                      ^
  symbol:   variable VK_EQUALS
  location: class TouchType
TouchType.java:93: error: cannot find symbol
                row3.add(createButton(VK_ENTER, "Enter"));
                                      ^
  symbol:   variable VK_ENTER
  location: class TouchType
TouchType.java:94: error: cannot find symbol
                row4.add(createButton(VK_SHIFT, "Shift"));
                                      ^
  symbol:   variable VK_SHIFT
  location: class TouchType
TouchType.java:95: error: cannot find symbol
                row4.add(createButton(VK_Z, "z"));
                                      ^
  symbol:   variable VK_Z
  location: class TouchType
TouchType.java:96: error: cannot find symbol
                row4.add(createButton(VK_X, "x"));
                                      ^
  symbol:   variable VK_X
  location: class TouchType
TouchType.java:97: error: cannot find symbol
                row4.add(createButton(VK_C, "c"));
                                      ^
  symbol:   variable VK_C
  location: class TouchType
TouchType.java:98: error: cannot find symbol
                row4.add(createButton(VK_V, "v"));
                                      ^
  symbol:   variable VK_V
  location: class TouchType
TouchType.java:99: error: cannot find symbol
                row4.add(createButton(VK_B, "b"));
                                      ^
  symbol:   variable VK_B
  location: class TouchType
TouchType.java:100: error: cannot find symbol
                row4.add(createButton(VK_N, "n"));
                                      ^
  symbol:   variable VK_N
  location: class TouchType
TouchType.java:101: error: cannot find symbol
                row4.add(createButton(VK_M, "m"));
                                      ^
  symbol:   variable VK_M
  location: class TouchType
TouchType.java:102: error: cannot find symbol
                row4.add(createButton(VK_COMMA, ","));
                                      ^
  symbol:   variable VK_COMMA
  location: class TouchType
TouchType.java:103: error: cannot find symbol
                row4.add(createButton(VK_PERIOD, "."));
                                      ^
  symbol:   variable VK_PERIOD
  location: class TouchType
TouchType.java:104: error: cannot find symbol
                row4.add(createButton(VK_SLASH, "/"));
                                      ^
  symbol:   variable VK_SLASH
  location: class TouchType
TouchType.java:105: error: cannot find symbol
                row4.add(createButton(VK_UP, "up"));
                                      ^
  symbol:   variable VK_UP
  location: class TouchType
TouchType.java:106: error: cannot find symbol
                row5.add(createButton(VK_SPACE, ""));
                                      ^
  symbol:   variable VK_SPACE
  location: class TouchType
TouchType.java:107: error: cannot find symbol
                row5.add(createButton(VK_LEFT, "Left"));
                                      ^
  symbol:   variable VK_LEFT
  location: class TouchType
TouchType.java:108: error: cannot find symbol
                row5.add(createButton(VK_DOWN, "Bottom"));
                                      ^
  symbol:   variable VK_DOWN
  location: class TouchType
TouchType.java:109: error: cannot find symbol
                row5.add(createButton(VK_RIGHT, "Right"));
                                      ^
  symbol:   variable VK_RIGHT
  location: class TouchType
56 errors

G:\JAVA\GUI\2015\createFrames\keyboard>

You can't use the VK constants from another class without either
fully qualifying them:
java.awt.event.KeyEvent.VK_1
or (better) by importing all the static public names from that class
import static java.awt.event.KeyEvent.*;
then you can just use VK_1 etc

Your little method has to return the button it creates if you want to add that to a panel.
If the method is void then
row1.add(createButton(VK_DEAD_TILDE, "~"));
wil fail because createButton(VK_DEAD_TILDE, "~") doesn;t return anything to add

Ah OK, sorry I thought this was enough import java.awt.event.KeyEvent; but clearly it isn't importing the static ones.
OK, understood about the method, I'll amend.
After the amendments I'll go ahead and if it all compiles, I'll add the event handling (I know you said it shouldn't be done as last thing but I can't think any other way to go with this).
Now, a couple of questions I'm thinking about now: for the event handling I need to capture the KeyEvent constant generated by the key press - I'm referring to the actual keyboard - then save that in a variable, say clickedKeyVal or something, then iterate through the map looking for that clickedKeyValand if I find it change the background of the button that contains that value. Does it sound OK?
thanks

No need to search the map - that's what maps do - lookup values by their keys.
You can just get the button directly from the map given the key code

JButton buttonToHighlight = myMap.get(clickedKeyVal);

ps: Better to declare the map as <Integer, JButton> rather than <Integer, Object> so the compiler knows you don't need to cast the retrieved obj to JButton

Hi thanks, sorry for the slow reply but i've been trying to resolve a GUI rendering issue with this, in vain apparently, and I'm not sure I can move on before fixing it.
Basicallt, I don't seem to be able to properly display all the keys.
The JText area seems excessively big, and I don't seem to be able to change it even if I tweak the rows and columns values. I presume that the sheer size of the textArea is pushing down all the buttons, and when I say push down I mean get them to display outside the visible area? Is that possible?
Also, it seems like only the buttons in the last rows get added (I'm not even getting into the issue of the sizes of the button, I'll figure out how to resolve that later), and this is what I get:
keyboard_app.png

This is the situation, in peseudocode, that I believe I have:

JFrame                          //borderLayout
    JPanel labelPanel           //borderLayout NORTH
        JLabel                  //NORTH
        Jlabel                  //CENTER
    JTextArea                   //directly added to JFrame, CENTER
    JPanel keysPanel            //borderLayout SOUTH
        JPanel row1             //GridLayout            
            key 
            key 
            key 
        JPanel row2             //GridLayout            
            key 
            key 
            key 
        JPanel row3             //GridLayout            
            key 
            key 
            key 
        ...

And here is the updated code:

 /*TouchType.java*/
import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.GridLayout;
import javax.swing.JTextArea;
import javax.swing.JButton;
//import java.awt.FlowLayout;
import javax.swing.JLabel;
import java.awt.event.KeyListener;
import java.awt.event.KeyEvent;
import static java.awt.event.KeyEvent.*;//needed for the key constants
import javax.swing.JScrollPane;
//for the map
import java.util.Map;
import java.util.HashMap;
import java.util.Set;
import java.util.TreeSet;   
public class TouchType extends JFrame{
    //private JPanel mainPanel;//wrapping panel
    private JPanel labelPanel;//panel for labels
    private JLabel label1;//first label
    private JLabel label2;//second label
    private JPanel keysPanel;//holding the keys
    private JButton newButton;
    //rows panels for keys. 5 rows.
    private JPanel row1;
    private JPanel row2;
    private JPanel row3;
    private JPanel row4;
    private JPanel row5;
    private JTextArea textArea;//text area
    private BorderLayout bLayout1;
    private BorderLayout bLayout2;
    private BorderLayout keysPanelLayout;
    private GridLayout gridLayoutRow1;
    private GridLayout gridLayoutRow2;
    private GridLayout gridLayoutRow3;
    private GridLayout gridLayoutRow4;
    private GridLayout gridLayoutRow5;

    Map<Integer,JButton> mp = new HashMap<Integer,JButton>();//declaring a map object 

    public TouchType(){//constructor
        super("Typing application");    

        //creating JPanels
        labelPanel = new JPanel(); //panel for labels
        keysPanel = new JPanel();//panel wrapper for key rows
        row1 = new JPanel();//panel for row1
        row2 = new JPanel();//panel for row2
        row3 = new JPanel();//panel for row3
        row4 = new JPanel();//panel for row4
        row5 = new JPanel();//panel for row5

        //creating a button and adding it to the appropriate JPanel
        row1.add(createButton(VK_DEAD_TILDE, "~"));     
        row1.add(createButton(VK_1, "1"));      
        row1.add(createButton(VK_2, "2"));
        row1.add(createButton(VK_3, "3"));      
        row1.add(createButton(VK_4, "4"));      
        row1.add(createButton(VK_5, "5"));
        row1.add(createButton(VK_6, "6"));
        row1.add(createButton(VK_7, "7"));      
        row1.add(createButton(VK_8, "8"));      
        row1.add(createButton(VK_9, "9"));      
        row1.add(createButton(VK_MINUS, "-"));      
        row1.add(createButton(VK_PLUS, "+"));       
        row1.add(createButton(VK_BACK_SPACE, "Backspace"));
        row2.add(createButton(VK_TAB, "Tab"));      
        row2.add(createButton(VK_Q, "q"));      
        row2.add(createButton(VK_W, "w"));
        row2.add(createButton(VK_E, "e"));      
        row2.add(createButton(VK_R, "r"));      
        row2.add(createButton(VK_T, "t"));      
        row2.add(createButton(VK_Y, "y"));      
        row2.add(createButton(VK_U, "u"));      
        row2.add(createButton(VK_I, "i"));      
        row2.add(createButton(VK_O, "o"));
        row2.add(createButton(VK_P, "p"));      
        row2.add(createButton(VK_OPEN_BRACKET, "["));       
        row2.add(createButton(VK_CLOSE_BRACKET, "]"));      
        row2.add(createButton(VK_BACK_SLASH, "\\"));        
        row3.add(createButton(VK_CAPS_LOCK, "Caps"));
        row3.add(createButton(VK_A, "a"));      
        row3.add(createButton(VK_S, "s"));      
        row3.add(createButton(VK_D, "d"));      
        row3.add(createButton(VK_F, "f"));      
        row3.add(createButton(VK_G, "g"));      
        row3.add(createButton(VK_H, "h"));      
        row3.add(createButton(VK_J, "j"));      
        row3.add(createButton(VK_K, "k"));      
        row3.add(createButton(VK_L, "l"));      
        row3.add(createButton(VK_SEMICOLON, ";"));      
        row3.add(createButton(VK_EQUALS, "="));     
        row3.add(createButton(VK_ENTER, "Enter"));      
        row4.add(createButton(VK_SHIFT, "Shift"));      
        row4.add(createButton(VK_Z, "z"));      
        row4.add(createButton(VK_X, "x"));      
        row4.add(createButton(VK_C, "c"));      
        row4.add(createButton(VK_V, "v"));      
        row4.add(createButton(VK_B, "b"));      
        row4.add(createButton(VK_N, "n"));      
        row4.add(createButton(VK_M, "m"));      
        row4.add(createButton(VK_COMMA, ","));      
        row4.add(createButton(VK_PERIOD, "."));     
        row4.add(createButton(VK_SLASH, "/"));      
        row4.add(createButton(VK_UP, "up"));        
        row5.add(createButton(VK_SPACE, ""));       
        row5.add(createButton(VK_LEFT, "Left"));        
        row5.add(createButton(VK_DOWN, "Bottom"));      
        row5.add(createButton(VK_RIGHT, "Right"));  

        //SORT OUT THE LAYOUTS
        //border layouts
        bLayout1 = new BorderLayout();//for JFrame
        bLayout2 = new BorderLayout();//for labelPanel
        keysPanelLayout = new BorderLayout();//for keysPanel
        //creating gridLayout objects for rows
        gridLayoutRow1 = new GridLayout(1,14);
        gridLayoutRow2 = new GridLayout(1,14);
        gridLayoutRow3 = new GridLayout(1,13);
        gridLayoutRow4 = new GridLayout(1,12);
        gridLayoutRow5 = new GridLayout(1,4);
        //creeating elements
        textArea = new JTextArea(3,15);
        label1 = new JLabel("Type some text using your keyboard. The keys you press will be highlighted and the text will be displayed");
        label2 = new JLabel("Note: clicking the button with your mouse will not perform any action");

        //set layouts
        setLayout(bLayout1);//set layout of JFrame
        keysPanel.setLayout(keysPanelLayout);//set layout of keysPanel
        labelPanel.setLayout(bLayout2);//layout of labelPanel
        row1.setLayout(gridLayoutRow1);//set layout of row1
        row2.setLayout(gridLayoutRow2);//set layout of row2
        row3.setLayout(gridLayoutRow3);//set layout of row3
        row4.setLayout(gridLayoutRow4);//set layout of row4
        row5.setLayout(gridLayoutRow5);//set layout of row5

        //add elements to their panels
        labelPanel.add(label1, BorderLayout.NORTH);//add label to labelPanel, top
        labelPanel.add(label2, BorderLayout.CENTER);//add label to labelPanel, middle

        keysPanel.add(row1);//add row to keysPanel
        keysPanel.add(row2);//add row to keysPanel
        keysPanel.add(row3);//add row to keysPanel
        keysPanel.add(row4);//add row to keysPanel
        keysPanel.add(row5);//add row to keysPanel
        add(labelPanel, BorderLayout.NORTH);//add labelPanel to JFrame, top
        add(new JScrollPane(textArea), BorderLayout.CENTER);//add textArea to the JFrame, middle
        add(keysPanel, BorderLayout.SOUTH);//add the keysPanel wrapper to the JFrame, bottom

    }//end of constructor
    //creates a button and adds it to the Map
    private JButton createButton(int keyCode, String name){
        newButton = new JButton(name);
        mp.put(keyCode, newButton);
        return newButton;
    }
}//end of TouchType class

Your keys panel has a border layout, so you are adding all the rows in the same place, but you want the rows inside it stacked vertically.
I can't see where you pack()the frame after adding everything.

er...pack() admittedly isn't there. Now that you mentioned that, I seem to remember having this conversation with you a few years back - before my gap with Java - just about the pack() and how important it was - can't remember why but I do remember you saying that, so I'll add it in on the test class (not attached to the thread), if I'm not mistaken that was the last thing to add after setVisible(true), something like this from memory:

/*TouchTypeTest.java*/
import javax.swing.JFrame;
public class TouchTypeTest{
    public static void main(String[] args){
        TouchType touchType = new TouchType();
        touchType.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        touchType.setSize(1900, 600);
        touchType.setVisible(true);
        touchType.pack();
    }
}

Now, about the layout of the keysPanel. I thought that keysPanel being just a panel could have had a BorderLayout so that it was easy to position it, it's currently positioned south in the JFrame, sorry for that. So, would then a GridLayout instead be better for keysPanel? Considering that there are 5 rows I could create another GridLayout of 1 row and 5 columns, but then how am I going to position the keysPanel inside the JFrame? If I just add it like soadd(keysPanel) where is it going to end up?
thanks

pack() before making visible to avoid a flickery repaint.

You are confusing parent and child layouts. Every container has a layout that controls how its contents are layed out, but has nothing to do with how that containier is placed in its parent.

So its the frame's layout that positions the panel at the bottom, and the panel's layout that positions the rows insde that panel. Border layout for the frame is OK, grid layout for the panel is OK.

Understood, thanks. It works now, at least the keys are displayed (although I will have to retweak the way the whole thing is displayed later on.)
On to event handling. I thought it would be nice to loop through the map and add a listener with a few lines of code, rather than doing it manually for all the buttons, but I'm not too sure that has worked (or that it is even acceptable. I had a look online and there were various way to do that, either with an iterator or with a for loop). Here I have coded in only one method to start with, haven't got to the other two as yet :

public TouchType(){//constructor
    ...
        KeyHandler handler = new KeyHandler();
        for(JButton currentButton:mp.values()){
        currentButton.addKeyListener(handler);
    }
}//end of constructor
//private class for event handling
    private class KeyHandler implements KeyListener{
        public void keyPressed(KeyEvent event){
            character = String.format("%s", KeyEvent.getKeyText(event.getKeyCode()));
            textArea.setText(character);
        }
        public void keyReleased(KeyEvent event){

        }
        public void keyTyped(KeyEvent event){

        }
    }

Is that allowed/good approach? When I press the button nothing gets added to the textArea, so I assume the listeners haven't been added

Edited 1 Year Ago by Violet_82

This question has already been answered. Start a new discussion instead.