Skip to content

Instantly share code, notes, and snippets.

@paul-hammant
Last active April 5, 2019 08:24
Show Gist options
  • Save paul-hammant/2a5ef0b23809f4a9a34815422b7116bc to your computer and use it in GitHub Desktop.
Save paul-hammant/2a5ef0b23809f4a9a34815422b7116bc to your computer and use it in GitHub Desktop.
Demo of MVC concepts using Java's Swing.
import javax.swing.*;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;
import java.awt.*;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Swing_MVC_MultiCounterDemo extends JFrame {
// See also two inner classes: CounterWidget & CounterModel
final CounterModel model;
public Swing_MVC_MultiCounterDemo() {{
setTitle("Counter MVC demo using Swing");
model = new CounterModel(0);
add(new JPanel(){{
setBorder(BorderFactory.createTitledBorder("Single Shared Model"));
add(new CounterWidget(model).view);
add(new CounterWidget(model).view);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
}});
add(new JPanel(){{
setBorder(BorderFactory.createTitledBorder("Two Separate Models"));
add(new CounterWidget(new CounterModel(3)).view);
add(new CounterWidget(new CounterModel(17)).view);
setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
}});
getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS));
pack();
setLocation(500, 500);
}}
public static void main(String[] args) {
Swing_MVC_MultiCounterDemo demo = new Swing_MVC_MultiCounterDemo();
demo.addWindowListener(new WindowAdapter()
{
@Override
public void windowClosing(WindowEvent e)
{
e.getWindow().dispose();
System.out.println("Frame closed, views/controllers eligible for GC, model value = "
+ demo.model.getCount() + ". Now exit."); ;
}
});
demo.setVisible(true);
}
public class CounterWidget {
final View view;
class View extends JPanel {
final JTextField text;
final JButton plus;
final JButton minus;
View(CounterModel model) {{
add(new JLabel("Count:"));
text = new JTextField("0", 4);
text.setDocument(model);
add(text);
plus = new JButton("+");
final int s = (int) (getFont().getSize() * 1.7);
plus.setPreferredSize(new Dimension(s, s));
add(plus);
minus = new JButton("-");
minus.setPreferredSize(new Dimension(s, s));
add(minus);
}}
}
CounterWidget(CounterModel model) {
view = new View(model);
// controller logic
view.plus.addActionListener(e -> {
model.increment();
});
view.minus.addActionListener(e -> {
model.decrement();
});
}
}
public class CounterModel extends PlainDocument {
CounterModel(int initialValue) {
setCount(initialValue);
}
void increment() {
setCount(getCount() + 1);
}
void decrement() {
setCount(getCount() - 1);
}
private void setCount(int i) {
try {
super.remove(0, getLength());
super.insertString(0, "" + i, null);
} catch (BadLocationException e) {
throw new UnsupportedOperationException(e);
}
}
int getCount() {
try {
return Integer.parseInt(super.getText(0, super.getLength()));
} catch (BadLocationException e) {
throw new UnsupportedOperationException(e);
}
}
public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException {
for (int i = 0; i < str.length(); i++) {
final char c = str.charAt(i);
if (!"0123456789".contains(String.valueOf(c)))
if (i == 0 && c != '-') {
return;
}
}
super.insertString(offset, str, attr);
}
}
}
@paul-hammant
Copy link
Author

paul-hammant commented Apr 5, 2019

That app, when running, looks like:

image

The first two counters move up and down together. The third and fourth two are independent of each other (as well as independent to the first two).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment