Josh Bloch Charlie Garrod 17-214 1 Administrivia Reading due - - PowerPoint PPT Presentation

josh bloch charlie garrod
SMART_READER_LITE
LIVE PREVIEW

Josh Bloch Charlie Garrod 17-214 1 Administrivia Reading due - - PowerPoint PPT Presentation

Principles of Software Construction: Objects, Design, and Concurrency Part 2: Design case studies Design case study: Java Swing Josh Bloch Charlie Garrod 17-214 1 Administrivia Reading due today: UML and Patterns 26.1 and 26.4


slide-1
SLIDE 1

1

17-214

Principles of Software Construction: Objects, Design, and Concurrency Part 2: Design case studies Design case study: Java Swing

Josh Bloch Charlie Garrod

slide-2
SLIDE 2

2

17-214

Administrivia

  • Reading due today: UML and Patterns 26.1 and 26.4
  • Homework 4b due Thursday, October 22nd
slide-3
SLIDE 3

3

17-214

Key concepts from Thursday

  • Observer design pattern
  • Introduction to concurrency

– Not enough synchronization: safety failure – Too much synchronization: liveness failure

  • Event-based programming
  • Introduction to GUIs
slide-4
SLIDE 4

4

17-214

Today

  • Finish introduction to GUIs
  • Design case study: GUI potpourri

– Strategy – Template method – Observer – Composite – Decorator – Adapter – Façade – Command – Chain of responsibility

  • Design discussion: Decoupling your game from your GUI
slide-5
SLIDE 5

5

17-214

Examples of events in GUIs

  • User clicks a button, presses a key
  • User selects an item from a list, an item from a menu
  • Mouse hovers over a widget, focus changes
  • Scrolling, mouse wheel turned
  • Resizing a window, hiding a window
  • Drag and drop
  • A packet arrives from a web service, connection drops, …
  • System shutdown, …
slide-6
SLIDE 6

6

17-214

An event-based GUI with a GUI framework

  • Setup phase

– Describe how the GUI window should look – Register observers to handle events

  • Execution

– Framework gets events from OS, processes events

  • Your code is mostly just event handlers

GUI Framework OS Application

get event drawing commands next event event— mouse, key, redraw, …

See edu.cmu.cs.cs214.rec06.alarmclock.AlarmWindow…

slide-7
SLIDE 7

7

17-214

GUI frameworks in Java

  • AWT – obsolete except as a part of Swing
  • Swing – widely used
  • SWT – Little used outside of Eclipse
  • JavaFX – Billed as a replacement for Swing

– Released 2008 – never gained traction

  • A bunch of modern (web & mobile) frameworks

– e.g., Android

slide-8
SLIDE 8

8

17-214

GUI programming is inherently multi-threaded

  • Swing Event Dispatch Thread (EDT) handles all GUI events

– Mouse events, keyboard events, timer events, etc.

  • No other time-consuming activity allowed on the EDT

– Violating this rule can cause liveness failures

slide-9
SLIDE 9

9

17-214

Ensuring all GUI activity is on the EDT

  • Never make a Swing call from any other thread

– “Swing calls” include Swing constructors

  • If not on EDT, make Swing calls with invokeLater:

public static void main(String[] args) { SwingUtilities.invokeLater(() -> new Test().setVisible(true)); }

slide-10
SLIDE 10

10

17-214

Callbacks execute on the EDT

  • You are a guest on the Event Dispatch Thread!

– Don’t abuse the privilege

  • If > a few ms of work to do, do it off the EDT

– javax.swing.SwingWorker designed for this purpose

slide-11
SLIDE 11

11

17-214

Components of a Swing application

JButton JPanel JTextField … JFrame

slide-12
SLIDE 12

12

17-214

Swing has many widgets

  • JLabel
  • JButton
  • JCheckBox
  • JChoice
  • JRadioButton
  • JTextField
  • JTextArea
  • JList
  • JScrollBar
  • … and more
  • JFrame is the Swing Window
  • JPanel (a.k.a. a pane) is the container to which you add your components

(or other containers)

slide-13
SLIDE 13

13

17-214

To create a simple Swing application

  • Make a window (a JFrame)
  • Make a container (a JPanel)

– Put it in the window

  • Add components (buttons, boxes, etc.) to the container

– Use layouts to control positioning – Set up observers (a.k.a. listeners) to respond to events – Optionally, write custom widgets with application-specific display logic

  • Set up the window to display the container
  • Then wait for events to arrive…
slide-14
SLIDE 14

14

17-214

E.g., creating a button

// public static void main… JFrame window = … JPanel panel = new JPanel(); window.setContentPane(panel); JButton button = new JButton("Click me"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { System.out.println("Button clicked"); } }); panel.add(button); window.setVisible(true);

panel to hold the button

slide-15
SLIDE 15

15

17-214

E.g., creating a button

// public static void main… JFrame window = … JPanel panel = new JPanel(); window.setContentPane(panel); JButton button = new JButton("Click me"); button.addActionListener( (e) -> System.out.println("Button clicked") ); panel.add(button); window.setVisible(true);

panel to hold the button

slide-16
SLIDE 16

16

17-214

The javax.swing.ActionListener

  • Listeners are objects with callback functions

– Can be registered to handle events on widgets – All registered widgets are called if event occurs interface ActionListener { void actionPerformed(ActionEvent e); }

class ActionEvent { int when; String actionCommand; int modifiers; Object source(); int id; … }

slide-17
SLIDE 17

17

17-214

Button design discussion

  • Button implementation should be reusable but customizable

– Different button label, different event-handling

  • Must decouple button's action from the button itself
  • Listeners are separate independent objects

– A single button can have multiple listeners – Multiple buttons can share the same listener

slide-18
SLIDE 18

18

17-214

Swing has many event listener interfaces

  • ActionListener
  • AdjustmentListener
  • FocusListener
  • ItemListener
  • KeyListener
  • MouseListener
  • TreeExpansionListener
  • TextListener
  • WindowListener

class ActionEvent { int when; String actionCommand; int modifiers; Object source(); int id; … }

interface ActionListener { void actionPerformed(ActionEvent e); }

slide-19
SLIDE 19

19

17-214

Today

  • Finish introduction to GUIs
  • Design case study: GUI potpourri

– Strategy – Template method – Observer – Composite – Decorator – Adapter – Façade – Command – Chain of responsibility

  • Design discussion: Decoupling your game from your GUI
slide-20
SLIDE 20

20

17-214

The decorator pattern abounds

slide-21
SLIDE 21

21

17-214

The decorator pattern abounds

UML from https://medium.com/@dholnessii/structural-design-patterns-decorator-30f5a8c106a5

slide-22
SLIDE 22

22

17-214

Swing layouts

see http://docs.oracle.com/javase/tutorial/uiswing/layout/visual.html

The simplest, and default, layout. Wraps around when out of space. Like FlowLayout, but no wrapping More sophisticated layout managers

slide-23
SLIDE 23

23

17-214

A naïve hard-coded implementation

  • A new layout would require changing or overriding JPanel

class JPanel { protected void doLayout() { switch(getLayoutType()) { case BOX_LAYOUT: adjustSizeBox(); break; case BORDER_LAYOUT: adjustSizeBorder(); break; ... } } private adjustSizeBox() { … } }

slide-24
SLIDE 24

24

17-214

A better solution: delegate the layout responsibilities

  • Layout classes, e.g.:

contentPane.setLayout(new FlowLayout()); contentPane.setLayout(new GridLayout(4,2));

  • Similarly, there are border classes to draw the borders, e.g.:

contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));

slide-25
SLIDE 25

25

17-214

Another GUI design challenge: nesting containers

  • A JFrame contains a JPanel, which contains a JPanel (and/or
  • ther widgets), which contains a JPanel (and/or other

widgets), which contains…

slide-26
SLIDE 26

26

17-214

The composite pattern

  • Problem: Collection of objects has behavior similar to the

individual objects

  • Solution: Have collection of objects and individual objects

implement the same interface

  • Consequences:

– Client code can treat collection as if it were an individual object – Easier to add new object types – Design might become too general, interface insufficiently useful

slide-27
SLIDE 27

27

17-214

Another composite pattern example

public interface Expression { double eval(); // Returns value } public class BinaryOperationExpression implements Expression { public BinaryOperationExpression(BinaryOperator operator, Expression operand1, Expression operand2); } public class NumberExpression implements Expression { public NumberExpression(double number); }

slide-28
SLIDE 28

28

17-214

Recall: Creating a button

//static public void main… JFrame window = … JPanel panel = new JPanel(); window.setContentPane(panel); JButton button = new JButton("Click me"); button.addActionListener( (e) -> { System.out.println("Button clicked"); }); panel.add(button); window.setVisible(true);

slide-29
SLIDE 29

29

17-214

An alternative button

class MyButton extends JButton { public MyButton() { super("Click me"); } @Override protected void fireActionPerformed(ActionEvent e) { super.fireActionPerformed(e); System.out.println("Button clicked"); } } //static public void main… JFrame window = … JPanel panel = new JPanel(); window.setContentPane(panel); panel.add(new MyButton()); window.setVisible(true);

slide-30
SLIDE 30

30

17-214

Discussion: Command vs. template method patterns

//static public void main… JFrame window = … JPanel panel = new JPanel(); window.setContentPane(panel); JButton button = new JButton(“Click me”); button.addActionListener( (e) -> { System.out.println("Button clicked"); }); panel.add(button); window.setVisible(true); class MyButton extends JButton { public MyButton() { super(“Click me”); } @Override protected void fireActionPerformed(ActionEvent e) { super.fireActionPerformed(e); System.out.println("Button clicked"); } } …

slide-31
SLIDE 31

31

17-214

Better use of template method: partial customization

JComponent:

slide-32
SLIDE 32

32

17-214

Event propagation and deep container hierarchies

slide-33
SLIDE 33

33

17-214

Event propagation and deep container hierarchies

slide-34
SLIDE 34

34

17-214

Event propagation and deep container hierarchies

slide-35
SLIDE 35

35

17-214

Event propagation and deep container hierarchies

slide-36
SLIDE 36

36

17-214

Event propagation and deep container hierarchies

slide-37
SLIDE 37

37

17-214

The chain of responsibility pattern

  • Problem: You need to associate functionality within a deep

nested or iterative structure, possibly with multiple objects

  • Solution: Request for functionality, pass request along chain

until some component handles it

  • Consequences:

– Decouples sender from receiver of request – Can simplify request-handling by handling requests near root of hierarchy – Handling of request not guaranteed

slide-38
SLIDE 38

38

17-214

The design of JList and JTree

  • Highly flexible rendering of lists and trees

– Can change rendering of cells – Can change source of data to display // example of simple use String [] items = { "a", "b", "c" }; JList<String> list = new JList<>(items);

slide-39
SLIDE 39

39

17-214

Using JLists with a ListModel

  • Allows a list widget (the view) to react to changes in the model

// with a ListModel ListModel<String> model = new DefaultListModel<>(); model.addElement("a"); JList<String> list = new JList<>(model); interface ListModel<T> { int getSize(); T getElementAt(int index); void addListDataListener(ListDataListener l); void removeListDataListener(ListDataListener l); }

slide-40
SLIDE 40

40

17-214

Using JLists with a ListModel

  • Allows a list widget (the view) to react to changes in the model

// with a ListModel ListModel<String> model = new DefaultListModel<>(); model.addElement("a"); JList<String> list = new JList<>(model); interface ListModel<T> { int getSize(); T getElementAt(int index); void addListDataListener(ListDataListener l); void removeListDataListener(ListDataListener l); } interface ListDataListener extends EventListener { void intervalAdded(…); void intervalRemoved(…); void contentsChanged(…); }

slide-41
SLIDE 41

41

17-214

Attaching a data source to a JList

  • Assume we have an anagram generator, and we want to update

a JList with new anagrams as they are generated

// design 1 class AnagramGen implements ListModel<String> { List<String> items … int getSize() { return items.size(); } String getElementAt(int index) { items.get(index).toString(); } void addListDataListener(ListDataListener l) {…} … }

slide-42
SLIDE 42

42

17-214

Attaching a data source to a JList

  • Assume we have an anagram generator, and we want to update

a JList with new anagrams as they are generated

// design 2 class AnagramGen { DefaultListModel<String> items … public ListModel<String> getListModel() { return items; } public Iterable<String> getItems() { return items.elements(); } … }

slide-43
SLIDE 43

43

17-214

Attaching a data source to a JList

  • Assume we have an anagram generator, and we want to update

a JList with new anagrams as they are generated

// design 3 class AnagramAdapter implements ListModel<String> { private final AnagramGen an; public AnagramAdapter(AnagramGen s) {an = s;} int getSize() { return count(an.getWords()); } String getElementAt(int index) { find(an.getWords(), index).toString(); } void addListDataListener(ListDataListener l) {…} … }

slide-44
SLIDE 44

44

17-214

Comparing the three proposed designs

+getItems()

  • items

AnagramGen JList +getSize() +getElementAt() AnagramAdapter +getSize() +getElementAt() «interface» ListModel

+getItems() AnagramGen JList +getSize() +getElementAt() DefaultListModel 1 1

+getItems() +getSize() +getElementAt()

  • items

AnagramGen JList +getSize() +getElementAt() «interface» ListModel

1 2 3

slide-45
SLIDE 45

45

17-214

The adapter pattern

  • Problem: You have a client that expects one API for a service

provider, and a service provider with a different API

  • Solution: Write a class that implements the expected API,

converting calls to the service provider's actual API

  • Consequences:

– Easy interoperability of unrelated clients and libraries

  • Client can use unforeseen future libraries

– Adapter class is coupled to concrete service provider, can make it harder to override service provider behavior

slide-46
SLIDE 46

46

17-214

The adapter pattern, illustrated

Have this and this? Use this!

slide-47
SLIDE 47

47

17-214

Aside: The façade pattern

Façade √ √ √ √ √ √ √

Subsystem classes

slide-48
SLIDE 48

48

17-214

The façade vs. adapter patterns

  • Motivation:

– Façade: Provide simple interface for a complex API

  • Façade interface is typically new

– Adapter: Match interface expected by an existing client to existing API

  • Adapter interface is defined by the existing client's expectations
slide-49
SLIDE 49

49

17-214

Today

  • Finish introduction to GUIs
  • Design case study: GUI potpourri

– Strategy – Template method – Observer – Composite – Decorator – Adapter – Façade – Command – Chain of responsibility

  • Design discussion: Decoupling your game from your GUI
slide-50
SLIDE 50

50

17-214

Design discussion: Decoupling your game from your GUI

slide-51
SLIDE 51

51

17-214

Summary

  • GUI programming is inherently multi-threaded

– Swing calls must be made on the event dispatch thread – No other significant work should be done on the EDT

  • GUIs are filled with design patterns
slide-52
SLIDE 52

52

17-214

Paper slides from lecture are scanned below..