2

I am working on a typing app which includes the a keyboard but I have found a bit hard to re-size the space button to make it wider than the other buttons.. This is the way I am displaying and organizing my layout..

I can resize the whole buttons but its NOT what I want.. the whole point is to be resize just the space bar.. :)

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Arrays;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;

public class example extends JFrame 
{  
    //Individual keyboard rows  
    String firstRow[] = {"~","1","2","3","4","5","6","7","8","9","0","-","+","BackSpace"};
    String secondRow[] = {"Tab","Q","W","E","R","T","Y","U","I","O","P","[","]","\\"};
    String thirdRow[] = {"Caps","A","S","D","F","G","H","J","K","L",":","\"","Enter"};
    String fourthRow[] = {"Shift","Z","X","C","V","B","N","M",",",".","?","   ^" };
    String fifthRow[]={"               " ,"<" ,"v",">" };
    String strText = "";
    //all keys without shift key press
    String noShift="`1234567890-=qwertyuiop[]\\asdfghjkl;'zxcvbnm,./";
    //special characters on keyboard that has to be addressed during key press
    String specialChars ="~-+[]\\;',.?";

    //Jbuttons corresponding to each individual rows 
    JButton first[];
    JButton second[];
    JButton third[];
    JButton fourth[];
    JButton fifth[];


    //Driver main method to start the application 
    public static void main(String[] args) {
        //launch typing tutor
        new example().setVisible(true);
    }

    // No argument constructor to create frame
    public example()
    {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //set size of the content pane ie frame
        this.getContentPane().setPreferredSize(new Dimension(1200,275));

        initWidgets();
    }


    // Method to initialize frame component 
    private void initWidgets()
    {

        //set the layout and place component in place and pack it 
        setLayout(new BorderLayout());
        //Various panel for the layout 
        JPanel jpNorth = new JPanel();
        JPanel jpCenter = new JPanel();
        JPanel jpKeyboard = new JPanel();
        JPanel jpNote = new JPanel();
        add( jpNorth, BorderLayout.NORTH);
        add( jpNote);
        add( jpCenter, BorderLayout.CENTER);
        add(jpKeyboard, BorderLayout.SOUTH);

        //layout for keyboard 
        jpKeyboard.setLayout(new GridLayout(5,1));
        //pack the components
        pack();

        //paint first keyboard row  and add it to the keyboard
        first = new JButton[firstRow.length];
        //get the panel for the  row
        JPanel p = new JPanel(new GridLayout(1, firstRow.length));
        for(int i = 0; i < firstRow.length; ++i) 
        {
            JButton b= new JButton(firstRow[i]);
            b.setPreferredSize(new Dimension(100,50));
            first[i] = b;
            p.add(first[i]);
        }
        jpKeyboard.add(p);

        //paint second keyboard row  and add it to the keyboard
        second = new JButton[secondRow.length];
        //get the panel for the  row
        p = new JPanel(new GridLayout(1, secondRow.length));
        for(int i = 0; i < secondRow.length; ++i) 
        {
            second[i] = new JButton(secondRow[i]);
            p.add(second[i]);

        }
        jpKeyboard.add(p);

        //paint third keyboard row  and add it to the keyboard
        third = new JButton[thirdRow.length];
        //get the panel for the  row
        p = new JPanel(new GridLayout(1, thirdRow.length));
        for(int i = 0; i < thirdRow.length; ++i)
        {
            third[i] = new JButton(thirdRow[i]);
            p.add(third[i]);
        }
        jpKeyboard.add(p);

        //paint fourth keyboard row  and add it to the keyboard
        fourth = new JButton[fourthRow.length];
        //get the panel for the  row
        p = new JPanel(new GridLayout(1, fourthRow.length));
        for(int i = 0; i < fourthRow.length; ++i)
        {
            fourth[i] = new JButton(fourthRow[i]);
            p.add(fourth[i]);
            if(i==fourthRow.length-2)
                p.add(new JPanel());

        }
        p.add(new JPanel());
        jpKeyboard.add(p);

        //paint the fifth row
        fifth = new JButton[fifthRow.length];
        //get the panel for the  row
        p = new JPanel(new GridLayout(1, fifthRow.length));
        //put empty panel for layout adjustments 
        for(int i = 0; i < 1; ++i)
        {
            JPanel  spacePanel = new JPanel();
            p.add(spacePanel);
        }
        //draw the buttons 
        for(int i = 0; i < fifthRow.length; ++i)
        {
            if(i==1) //space bar panel
            {
                JButton b = new JButton(fifthRow[i]);
                b.setPreferredSize(new Dimension(400,10));
                b.setBounds(10, 10, 600, 100);
                fifth[i]=b;
                //add empty panels for layout 
                p.add(new JPanel());p.add(new JPanel());p.add(new JPanel());p.add(new JPanel());p.add(new JPanel());p.add(new JPanel());p.add(new JPanel());p.add(new JPanel());
            }
            else
            {
                fifth[i]=new JButton(fifthRow[i]);
            }
            if(i==0) //first black panel
            {
                   //place a black panel at first
                   JPanel  spacePanel = new JPanel();
                   p.add(spacePanel);
            }
            p.add(fifth[i]);

        }
        jpKeyboard.add(p);

        } //end of initWidgets   

}//end of class

Well, if any of you guys can walk me through I will really appreciate it and if you guys need any clarification or more info please just let me know.. :)

mKorbel
  • 109,525
  • 20
  • 134
  • 319
valbu17
  • 4,034
  • 3
  • 30
  • 41

2 Answers2

6

There are two problems, one, you're calling pack before you've actually finished building the content. pack uses the contents preferred size to calculate the size of the window, this would cause you issues as the (potential) size of the content would be different to what you wanted. The fact it works is down to the use of setPreferredSize you called earlier, which you should avoid doing.

The second issue is the choice of layout manager. GridLayout will give each component within the container an equal amount of space, horizontally and vertically based on the avaiable space of the parent container.

A better solution might be to use GridBagLayout, for example.

Keyboard

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Example extends JFrame {

    //Individual keyboard rows  
    String firstRow[] = {"~", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0", "-", "+", "fill", "BackSpace"};
    String secondRow[] = {"Tab", "Q", "W", "E", "R", "T", "Y", "U", "I", "O", "P", "[", "]", "\\"};
    String thirdRow[] = {"Caps", "A", "S", "D", "F", "G", "H", "J", "K", "L", ":", "\"", "fill", "fill", "Enter"};
    String fourthRow[] = {"Shift", "Z", "X", "C", "V", "B", "N", "M", ",", ".", "?", "blank", "^"};
    String fifthRow[] = {"blank", "blank", "fill", "fill", "fill", "fill", "fill", "fill", "fill", "fill", "", "<", "v", ">"};

    //Jbuttons corresponding to each individual rows 
    JButton first[];
    JButton second[];
    JButton third[];
    JButton fourth[];
    JButton fifth[];

    //Driver main method to start the application 
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                new Example().setVisible(true);
            }
        });
    }

    // No argument constructor to create frame
    public Example() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        initWidgets();
    }

    // Method to initialize frame component 
    private void initWidgets() {

        //set the layout and place component in place and pack it 
        setLayout(new BorderLayout());
        //Various panel for the layout 
        JPanel jpNorth = new JPanel();
        JPanel jpCenter = new JPanel();
        JPanel jpKeyboard = new JPanel(new GridBagLayout());
        JPanel jpNote = new JPanel();
        add(jpNorth, BorderLayout.NORTH);
        add(jpNote);
        add(jpCenter, BorderLayout.CENTER);
        add(jpKeyboard, BorderLayout.SOUTH);

        first = new JButton[firstRow.length];
        second = new JButton[secondRow.length];
        third = new JButton[thirdRow.length];
        fourth = new JButton[fourthRow.length];
        fifth = new JButton[fifthRow.length];

        addKeys(jpKeyboard, 0, firstRow, first);
        addKeys(jpKeyboard, 1, secondRow, second);
        addKeys(jpKeyboard, 2, thirdRow, third);
        addKeys(jpKeyboard, 3, fourthRow, fourth);
        addKeys(jpKeyboard, 4, fifthRow, fifth);

        pack();

    } //end of initWidgets   

    protected void addKeys(JPanel parent, int row, String[] keys, JButton[] buttons) {

        GridBagConstraints gbc = new GridBagConstraints();
        gbc.gridy = row;
        gbc.gridx = 0;
        gbc.fill = GridBagConstraints.BOTH;

        int gap = 0;
        for (int index = 0; index < keys.length; index++) {
            String key = keys[index];
            if ("blank".equalsIgnoreCase(key)) {
                gbc.gridx++;
            } else if ("fill".equalsIgnoreCase(key)) {
                gbc.gridwidth++;
                gap++;
            } else {
                System.out.println("Add " + key);
                JButton btn = new JButton(key);
                buttons[index] = btn;
                parent.add(btn, gbc);
                gbc.gridx += gap + 1;
                gbc.gridwidth = 1;
                gap = 0;
            }
        }

    }

}//end of class

If you find the answer useful, I would appreciate if you could mark @peeskillet's answer as correct, as he answered first and spotted a few problems I didn't...an upvote would be nice though ;)

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • which function will you use to change the height and width of the buttons in your keyboard example? – valbu17 Mar 14 '14 at 04:15
  • I wouldn't. The width and height and derived from the requirements of the buttons text and the `GridBagConstraints`, such as `fill` and `gridwidth`. If you "really" want to change the size of the buttons, consider changing the margins – MadProgrammer Mar 14 '14 at 04:19
  • Thanks, A lot for the help.. I can't seem to make my KeyListener to work properly.. Im trying to edit the string typed and set a background colour for it. Not sure if you are willing to help me out a bit on it?? – valbu17 Mar 14 '14 at 22:56
  • `KeyListener` has issues with focus. The component it is registered to must be focusable and have focus before it can respond to key events. – MadProgrammer Mar 14 '14 at 23:25
  • posted a question with more info regarding my issue.. is not related to this post tho.. if you are interested in taking a look at it.. this is the link.. http://stackoverflow.com/questions/22417890/use-of-keylistener-to-change-string-background-and-set-it-back-when-the-key-is-r – valbu17 Mar 15 '14 at 00:09
4

What pack() does is pack the frame, using the preferred sizes of the components. What you are doing is pack()ing before add the components and setting their preferred sizes, so the pack() is insignificant to the components added after the call (in terms of preferred size. So pack() the frame after you add all the components and set their preferred sizes.

Another thing you need to consider is that GridLayout will not respect the preferred size of the components. It will actually make them all the same size.

See here to see which layout managers will respect preferred sizes. And restructure your code accordingly. I'd look into a GridBagLayout as MadProgrammer suggest, that way you can just use one layout manager. It's a little tricky if you have no experience with it. Another option is just to stick with the default FlowLayout of the JPanel and nest panels as you have done.

Also see Laying out Components Within a Container to learn about the layout mangers available and hot they work.

Community
  • 1
  • 1
Paul Samsotha
  • 205,037
  • 37
  • 486
  • 720
  • hey thanks for help not sure if you are willing to continue helping, I have encounter another problem with my program.. its about the KeyListener, Im trying to change the string background colour and when is release set back to white.. – valbu17 Mar 14 '14 at 23:00