500 likes | 599 Views
F27SB2 Software Development 2. Lecture 6: Java GUIs 5. Buttons and enumerated types. often want to manipulate a problem specific set of values e.g. a student my fail , pass , gain merit or gain distinction in an exam useful if we had distinct values for each possibility
E N D
F27SB2 Software Development 2 Lecture 6: Java GUIs 5
Buttons and enumerated types • often want to manipulate a problem specific set of values • e.g. a student my fail, pass, gain merit or gain distinction in an exam • useful if we had distinct values for each possibility • enumerated type • set of discrete values with textual identifiers
Buttons and enumerated types • could use distinct variable names • e.g. exam grades: fail, pass, merit, distinction • could give each variable a distinct value from an existing class • e.g. exam grades as integer final int fail = 0; final int pass = 1; final int merit = 2; final int distinction = 3;
Buttons and enumerated types • can now use variables as if they were values • disadvantage • no distinct class for the enumerated type • can use any value from representation class in context where enumerated type value is expected • e.g. intmygrade = 27;
Buttons and enumerated types • better to define a new class class Grade { private int rep; public Grade(int r) { rep = r; } } ... Grade fail = new Grade(0); Grade pass = new Grade(1); ...
Buttons and enumerated types • a variable of a class can only be set to values from that class Grade mygrade = 27; // type error! Grade mygrade = pass; // OK! • still problems of input/output • everything must be represented in files/from keyboard/on screen using characters • need to convert characters to/from enumerated type • user can enter invalid characters
Buttons and enumerated types Grade readGrade(BufferedReader f) { String g = f.readLine().trim(); if(g.equals(”fail”)) return fail; if(g.equals(”pass”)) return pass; ... throw new Exception(“bad grade”); }
Buttons and enumerated types • replace string input with JButtons • one JButtonfor each value • select JButtonto enter value • no need to check validity • user can only select from available JButtons • no need to convert string
Buttons and enumerated types • e.g. count fruit consumption • JButton- select fruit • JLabel- display count fruit count JButton JLabel JFrame
Buttons and enumerated types • represent each item of fruit as member of a class with own: • JButton • JLabel • integer count class Item { JButtonb; JLabelc; int count;
Buttons and enumerated types • constructor to initialise JButton, count, and JLabel public Item(String name) { b = new JButton(name); b.setFont(new Font("sanserif",Font.BOLD,24)); b.setForeground(Color.white); b.setBackground(Color.black); count=0; c = new JLabel("0",JLabel.CENTER); c.setFont(new Font("sanserif",Font.BOLD,24)); c.setBackground(Color.white); } }
Buttons and enumerated types • NB no separate String field for name • hold name on JButton • use getText if we need the name • class for Fruit enumerated type class Fruit extends Frame implements ActionListener • constructor to: • create each value • add each JLabeland JButton to JFrame • add ActionListener for each JButton
Buttons and enumerated types • could use individual variables { Item papaya = new Item(“papaya”); Item peach = new Item(“peach”); ... • for many Items use an array { Item [] f; String [] names = {"papaya","peach","pear","persimmon", "physalis","pineapple","plum","pomegranite"}; final int FMAX = 8;
Buttons and enumerated types public Fruit() { f = new Item[FMAX]; setLayout(new GridLayout(FMAX,2)); for(int i=0;i<FMAX;i++) { f[i] = new Item(names[i]); add(f[i].b); f[i].b.addActionListener(this); add(f[i].c); } }
Buttons and enumerated types f papaya 1 0 1 1 peach JButton b JLabel c int count FMAX pomegranite 221
Buttons and enumerated types • actionPerformedto: • identify JButton • update count & JLabel public void actionPerformed(ActionEvent e) { for(int i=0;i<FMAX;i++) if(e.getSource()==f[i].b) { f[i].count++; f[i].c.setText(f[i].count+""); } } }
Buttons and enumerated types class TestFruit { public static void main(String [] args) throws IOException { ... } }
Numeric key pad • use as front end to other programs • 10 decimal digit keys • 1-9 + 0 • clear key - Z(ero) • multiple digit display
Numeric key pad JFrame digit N digit 0 JPanel of JLabels 1 2 3 4 5 6 JPanel ofJButtons 7 8 9 Z 0
Numeric key pad • keep track of current value in display • key 0-9 • shift all displays left • put new key value in right-most display • multiply current value by 10 and add new digit
Numeric key pad • e.g. current value is 14 • user presses 5 • current value = 14 * 10 + 5 == 145 0 1 4 1 4 5
Numeric key pad • Z • set all displays to 0 & set current value to 0 • use BorderLayout for JFrame • add display to North • add keys to Center • use GridLayoutfor JPanels
Numeric key pad • make array of JLabels for display • make array of JButtons for keypad class Keypad extends JFrameimplements ActionListener { JLabel [] display; final int DISPLAYS = 10; JButton[] keys; JButton CLR; int value; final int KEYS = 10; JPaneld,k;
Numeric key pad JLabelsetupLabel(String s) { JLabel l = new JLabel(s,JLabel.CENTER); l.setFont(new Font("Sansserif",Font.PLAIN,18)); l.setBackground(Color.white); l.setOpaque(true); return l; } public JButtonsetupButton(String s,Container c) { JButton b = new JButton(s); b.setFont(new Font("Sansserif",Font.PLAIN,18)); b.setBackground(Color.white); b.setOpaque(true); b.addActionListener(this); c.add(b); return b; }
Numeric key pad • map JLabels to display public Keypad() { int i; d = new JPanel(new GridLayout(1,DISPLAYS)); display = new JLabel[DISPLAYS]; for(i=0;i<DISPLAYS;i++) display[i]=setupLabel("0"); • add JLabels to display in reverse order for(i=DISPLAYS-1;i>=0;i--) d.add(display[i]); add(BorderLayout.NORTH,d);
Numeric key pad • add keypad JButtons in order: 1-9, Z, 0 k = new JPanel(new GridLayout(4,3)); keys = new JButton[KEYS]; for(i=1;i<KEYS;i++) keys[i] = setupButton(i+"",k); CLR = setupButton("Z",k); keys[0] = setupButton("0",k); add(BorderLayout.CENTER,k); value = 0; }
Numeric key pad public void actionPerformed(ActionEvent e) { if(e.getSource()==CLR) { value = 0; for(int i=0;i<DISPLAYS;i++) display[i].setText("0"); } else { for(int i=0;i<KEYS;i++) if(e.getSource()==keys[i]) • ith key selected so new digit has value i { value=10*value+i;
Numeric key pad • shift text from display[j] to display[j+1] • lose text on leftmost display... for(int j=DISPLAYS-2;j>=0;j--) display[j+1]. setText(display[j].getText()); • set rightmost display to i display[0].setText(i+""); return; } } } }
Sliding blocks puzzle • 8 square blocks with a distinctive mark on each block • square tray with 3*3 block positions • arrange blocks in tray in some specified order from some initial configuration • cannot pick blocks up • can only slide block into free space
Sliding blocks puzzle 1 3 1 2 3 4 2 6 4 6 b) a) 7 8 7 8 5 5 1 2 3 1 2 3 4 5 6 4 5 6 c) d) 7 8 7 8
Sliding blocks puzzle • represent tray as 3*3 grid of JButtons • numbered blocks • block in row i/column j has number: i*3+j+1 column: 0 1 2 • block in row 0 column 0 = 0*3+0+1 = 1 • block in row 0 column 1 = 0*3+1+1 = 2 • block in row 0 column 2 = 0*3+2+1 = 3 • block in row 1 column 0 = 1*3+0+1 = 4 • block in row 1 column 1 = 1*3+1+1 = 5 • block in row 1 column 2 = 1*3+2+1 = 6 • block in row 2 column 0 = 2*3+0+1 = 7 • block in row 2 column 1 = 2*3+1+1 = 8 1 2 3 row: 0 1 2 4 5 6 7 8
Sliding block puzzle • user selects JButton to “move” block into space • program swaps text on selected JButton and space JButton • can only move block if it is next to the space • i.e. in same row and block is to left/right of space • i.e. in same column and block is above/below space
Sliding block puzzle • suppose block is in row i and column j • suppose space is in row spaceI and column spaceJ • block can move into space if: i==spaceI && (j==spaceJ-1 || j==spaceJ+1) || j==spaceJ && (i==spaceI-1 || i==spaceI+1)
Sliding blocks puzzle class Blocks extends JFrame implements ActionListener { JButton [][] blocks; • remember row/column for space intspaceI,spaceJ; public JButtonsetupButton(String s,Container c) { JButton b = new JButton(s); b.setFont(new Font("Sansserif",Font.PLAIN,18)); b.setBackground(Color.white); b.setOpaque(true); c.add(b); b.addActionListener(this); return b; }
Sliding blocks puzzle public Blocks() { setLayout(new GridLayout(3,3)); blocks = new JButton[3][3]; • set up each block with appropriate label for(int i=0;i<3;i++) for(int j=0;j<3;j++) blocks[i][j]= setupButton((i*3+j+1)+"",this); • set up spaceJButtonin bottom right corner blocks[2][2].setText(""); spaceI=2; spaceJ=2; }
Sliding blocks puzzle public void actionPerformed(ActionEvent e) { for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(e.getSource()==blocks[i][j]) if((i==spaceI && (j==spaceJ-1 || j==spaceJ+1)) || (j==spaceJ && (i==spaceI-1 || i==spaceI+1))) • set current space JButton text to text from selected JButton { blocks[spaceI][spaceJ]. setText(blocks[i][j].getText());
Sliding blocks puzzle • remember row/column position of new space JButton and set text to blank spaceI=i; spaceJ=j; blocks[spaceI][spaceJ].setText(""); return; } } } class TestBlocks { ... }
Noughts and crosses • game played on 3*3 board • each player makes either “O” or “X” mark • players take it in turns to place mark on free grid square of their choice • first player to place 3 marks in horizontal/vertical/diagonal straight line wins X O O X
Noughts and crosses • represent board as 3*3 grid of JButtons • player presses JButton to make mark JFrame messages JLabel X JPanelofJButtons O O X
Noughts and crosses • computers chooses/marks JButton in turn • after user plays: • check if legal square i.e. no mark • set mark • check if user wins • computer plays in next free square • if none then draw • many better algorithms • check if computer wins
Noughts and crosses class Noughts extends Frame implements ActionListener { JButton [][] squares; JLabel messages; JPanelboard; public JButton setupButton(String s,Container c) { JButton b = new JButton(s); b.setFont(new Font("Sansserif",Font.PLAIN,24)); b.setBackground(Color.white); b.setOpaque(true); c.add(b); b.addActionListener(this); return b; }
Noughts and crosses public Noughts() { board = new JPanel(new GridLayout(3,3)); squares = new JButton[3][3]; for(int i=0;i<3;i++) for(int j=0;j<3;j++) squares[i][j]= setupButton("",board); add(BorderLayout.CENTER,board); messages = new JLabel("Select a square to play X.", JLabel.CENTER); messages.setFont(new Font("Serif",Font.ITALIC,18)); messages.setBackground(Color.white); add(BorderLayout.NORTH,messages); }
Noughts and crosses booleancheckwin(String mark) { booleanrwin, cwin; for(int i=0;i<3;i++) { rwin=true; cwin=true; for(int j=0;j<3;j++) • check next in row i { rwin=rwin && squares[i][j].getText().equals(mark); • check next in column i cwin=cwin && squares[j][i].getText().equals(mark); } if(rwin || cwin) return true; }
Noughts and crosses • check both diagonals return (squares[0][0].getText().equals(mark) && squares[1][1].getText().equals(mark) && squares[2][2].getText().equals(mark)) || (squares[0][2].getText().equals(mark) && squares[1][1].getText().equals(mark) && squares[2][0].getText().equals(mark)); }
Noughts and crosses • return boolean to indicate whether or not computer could find a blank square booleancomputerplay() { for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(squares[i][j].getText().equals("")) { squares[i][j].setText("O"); return true; } return false; }
Noughts and crosses public void actionPerformed(ActionEvent e) { for(int i=0;i<3;i++) for(int j=0;j<3;j++) if(e.getSource()==squares[i][j]) if(squares[i][j].getText().equals("")) { squares[i][j].setText("X"); if(checkwin("X")) messages.setText("You win."); else if(!computerplay()) messages.setText("Draw."); else if(checkwin("O")) messages.setText("I win.");
Noughts and crosses else messages.setText("Select a square to play X."); return; } else { messages. setText("Can't play in that square."); return; } } } class TestNoughts { ... }