You are viewing redgrittybrick

Red Gritty Brick
Recent Entries 
A simple example.

This shows a label that displays some data values from a list. There is a menu and some buttons for moving back and forwards through the list. At the start or end of the list, the appropriate buttons and menu items are disabled.

Note that I'd usually have the "Controller" code as part of the View for Swing Desktop Applications.

I've used java.util.Observer and Observable to link the Model with the View. In practice I rarely do this. I think it helps illustrate MVC and ways of coupling classes.

package org.redgrittybrick.test;

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Observable;
import java.util.Observer;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Gen {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Gen();
            }
        });
    }

    private static final String PRIOR = "Prior", NEXT = "Next";

    // APPLICATION
    Gen() {
        GenModel model = new GenModel();
        GenControl controller = new GenControl(model);
        JFrame view = new GenListView(model, controller);
        view.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        view.pack();
        view.setLocationRelativeTo(null);
        view.setVisible(true);
    }

    // A VIEW
    class GenListView extends JFrame implements Observer {
        private JLabel label = new JLabel();
        private JMenuItem priorItem, nextItem;
        private JButton priorButton, nextButton;
        private GenModel model;

        GenListView(GenModel model, GenControl controller) {
            this.model = model;

            JMenuBar bar = new JMenuBar();
            JMenu menu = new JMenu("Go");
            priorItem = new JMenuItem(PRIOR);
            priorItem.addActionListener(controller);
            menu.add(priorItem);
            nextItem = new JMenuItem(NEXT);
            nextItem.addActionListener(controller);
            menu.add(nextItem);
            bar.add(menu);
            setJMenuBar(bar);

            JPanel panel = new JPanel(new GridLayout(1,3));
            priorButton = new JButton(PRIOR);
            priorButton.addActionListener(controller);
            panel.add(priorButton);
            nextButton = new JButton(NEXT);
            nextButton.addActionListener(controller);
            panel.add(nextButton);
            update(null,null);
            panel.add(label);

            add(panel);
            model.addObserver(this);
        }

        @Override
        public void update(Observable observable, Object object) {
            label.setText(model.get());
            priorButton.setEnabled(!model.isFirst());
            priorItem.setEnabled(!model.isFirst());
            nextButton.setEnabled(!model.isLast());
            nextItem.setEnabled(!model.isLast());
        }
    }

    // A CONTROLLER
    class GenControl implements ActionListener {
        GenModel model;

        GenControl(GenModel model) {
            this.model = model;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            String actionName = e.getActionCommand();
            if (actionName.equals(PRIOR)) {
                model.prior();
            } else if (actionName.equals(NEXT)) {
                model.next();
            } else {
                System.err.println("Bug: Unexpected action: "
                        + actionName);
            }
        }
    }

    // A MODEL
    class GenModel extends Observable {
        private final String[] data = { "One", "Two", "Three", "Four" };
        private int current = 0;

        public String get() {
            return data[current];
        }

        public void next() {
            if (current + 1 < data.length)
                current++;
            else
                current = 0;
            setChanged();
            notifyObservers();
        }

        public void prior() {
            if (current > 0)
                current--;
            else
                current = data.length - 1;
            setChanged();
            notifyObservers();
        }

        public boolean isFirst() {
            return current == 0;
        }

        public boolean isLast() {
            return current == data.length - 1;
        }

    }


}
Red Gritty Brick
2008-04-30 - Java Sockets
I'm learning about Sockets (the TCP variety) Here's a pretty basic example of using them with Swing

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.net.UnknownHostException;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class PwSocket {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new PwSocket();
            }
        });
    }
    
    

    PwSocket() {
        final String pw = JOptionPane.showInputDialog("Password");
        
        final SocketThing socketThing = new SocketThing(pw);

        final JFrame f = new JFrame("Passworded Socket");
    
        final JLabel label = new JLabel("Busy...");
        
        new SwingWorker<Void, Void>() {
            @Override
            protected Void doInBackground() throws Exception {
                socketThing.start();
                return null;
            }
            @Override
            protected void done() {
                if (socketThing.hasError()) {
                    JOptionPane.showMessageDialog(f, socketThing.getErrorMessage());
                    System.exit(1);
                } else {
                    label.setText("["+socketThing.getData()+"]");
                }
            }
        }.execute();

        JPanel p = new JPanel();
        p.add(label);

        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.add(p);
        f.pack();
        f.setLocationRelativeTo(null);
        f.setVisible(true);
    } // constructor

    class SocketThing {
        private Socket sock;
        private PrintWriter out = null;
        private BufferedReader in = null;

        private String errorMessage;
        private String data;

        SocketThing(String pw) {
            System.out.println("Creating SocketThing...");
            if (!pw.equals("Foo")) {
                errorMessage = "Bad password!";
            } else {
                try {
                    sock = new Socket("www.google.com", 80);
                    out = new PrintWriter(sock.getOutputStream(), true);
                    InputStream is = sock.getInputStream();
                    InputStreamReader isr = new InputStreamReader(is);
                    in = new BufferedReader(isr);
                } catch (UnknownHostException e) {                    
                    e.printStackTrace();
                    errorMessage = e.getMessage();
                } catch (IOException e) {
                    e.printStackTrace();
                    errorMessage = e.getMessage();
                }
            }
            System.out.println("SocketThing created.");
        }

        public void start() {
            System.out.println("Starting SocketThing...");
            if (out != null) {
                out.println("GET / HTTP/1.1");
                out.println("");
                try {
                    data = in.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                    errorMessage = e.getMessage();
                    return;
                }
            }
            System.out.println("SocketThing finished");
        }

        public boolean hasError() {
            return errorMessage != null;
        }

        public String getErrorMessage() {
            return errorMessage;
        }
        
        public String getData() {
            return data;
        }
    }

}
Red Gritty Brick

DOM vs SAX


There are two main approaches to parsing XML - stream based (SAX) and document based (DOM).

When I was first learning about parsing XML in Java I wrote a few small test programs, here's an example using the DOM approach. It was obviously written in a hurry and contains some strange things that need tidying up. I'll address this in a later entry.

If you are simply going to construct a Document and then traverse it, as this example does, you should probably consider SAX instead.

XML


Here's an example of XML
<inventory>
  <animal type="mammal">
    <name>Fred</name>
    <species>Hippo</species>
    <weight units="Kg">1552</weight>
  </animal>
  <animal type="reptile">
    <name>
       Gert
       AKA Gertrude
       the galloping reptile
    </name>
    <species>Croc</species>
  </animal>
</inventory>

Output


This is what the program displays. Note that whitespace used in the XML for indentation is ignored but whitespace within the element data is retained.
inventory.animal.name() = 'Fred'.
inventory.animal.species() = 'Hippo'.
inventory.animal.weight() = '1552'.
inventory.animal.name() = '
       Gert
       AKA Gertrude
       the galloping reptile
    '.
inventory.animal.species() = 'Croc'.

Java


This is the Java program that parses the XML.
public class ParseXMLbyDOM {

    public static void main(String[] args) {

        String filename = "XML/animals.xml";

        String uri = "file:" + new File(filename).getAbsolutePath();
        Document doc = null;
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory
                    .newInstance();
            DocumentBuilder builder = factory.newDocumentBuilder();
            doc = builder.parse(uri);
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        doRecursive(doc, "");
    }

    private static void doRecursive(Node node, String name) {
        if (node == null)
            return;
        NodeList nodes = node.getChildNodes();
        for (int i = 0; i < nodes.getLength(); i++) {
            Node n = nodes.item(i);
            if (n == null)
                continue;
            doNode(n, name);
        }
    }

    private static void doNode(Node node, String name) {
        String nodeName = "unknown";
        switch (node.getNodeType()) {
        case Node.ELEMENT_NODE:
            if (name.length() == 0) {
                nodeName = node.getNodeName();
            } else {
                nodeName = name + "." + node.getNodeName();
            }
            doRecursive(node, nodeName);
            break;
        case Node.TEXT_NODE:
            String text = node.getNodeValue();
            if (text.length() == 0 || text.matches("\n *")
                    || text.equals("\\r")) {
                break;
            }
            String type = "";
            NamedNodeMap attrs = node.getAttributes();
            if (attrs != null) {
                Node attr = attrs.getNamedItem("type");
                if (attr != null) {
                    type = attr.getNodeValue();
                }
            }
            System.out.println(name + "(" + type + ") = '"
                    + text + "'.");
            nodeName = "unknown";
            break;
        default:
            System.out.println("Other node "
                    + node.getNodeType() + " : "
                    + node.getClass());
            break;
        }
    }
}
Red Gritty Brick
2008-04-11 - Java Timer
Here's an example of using a Timer to time-out some user input. In this case I use javax.swing.Timer but the same principle could apply to using java.util.Timer.



import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.text.DecimalFormat;

import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class Bomb implements ActionListener {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Bomb();
            }
        });
    }

    JFrame bomb = new JFrame("Bomb");
    JLabel countLabel = new JLabel("10.000");
    JTextField codeField = new JTextField(10);
    JButton button = new JButton("Disarm");

    Timer timer;
    static final int INTERVAL = 25;
    double time = 10.0;
    DecimalFormat decimal = new DecimalFormat("#0.000");

    Bomb() {
        timer = new Timer(INTERVAL, this);
        timer.setInitialDelay(1000);
        timer.start();

        countLabel.setFont(new Font("Monospaced", Font.BOLD, 24));
        button.addActionListener(this);

        Box controlPanel = new Box(BoxLayout.LINE_AXIS);
        controlPanel.add(new JLabel("Code: "));
        controlPanel.add(codeField);
        controlPanel.add(button);

        Box panel = new Box(BoxLayout.PAGE_AXIS);
        panel.add(countLabel);
        panel.add(controlPanel);

        bomb.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        bomb.add(panel);
        bomb.pack();
        bomb.setLocationRelativeTo(null);
        bomb.setVisible(true);
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == timer) {
            time -= INTERVAL*0.001;
            String timeString = decimal.format(time);
            countLabel.setText(timeString);
            System.out.println("Time: " + timeString);
            if (time <= 0.001) {
                JOptionPane.showMessageDialog(bomb, "Kaboom!");
                System.exit(1);            
            }
        } else if (e.getSource() == button) {
            timer.stop();
            JOptionPane.showMessageDialog(bomb, "whirrr ... Kaboom!");
            System.exit(1);            
        } else {
            JOptionPane.showMessageDialog(bomb, "Spanner in the works!");
        }
    }
}
Red Gritty Brick
When I was a teenager, music was sold on vinyl records. I bought albums and listened to them on my parent's record player. I wasn't too good at looking after my records so over time they became dirty, scratched and full of dust. My music became full of clicks rumbles and hisses.

When I bought my first car, I bought a compact-cassette player so that I could listen to music in the car. I recorded the albums I had bought onto blank cassette tapes. The quality was awful but that didn't matter, the car was noisy and I was glad just to be able to hear "my" music whilst driving.

I stopped buying vinyl records and started buying new music on tapes. I bought my own hi-fi equipment including a cassette deck to play my music tapes at home. The quality wasn't great but at least tapes didn't get scratched or affected by dust. Ok I had to occasionally clean the tape heads in the player. Now I had to decide whether to buy new pre-recorded cassettes of the music I had on albums, mostly I didn't, I just recorded the old vinyl onto cassettes. But eventually I started buying all my new music on pre-recorded compact-cassette tapes.

Then came CDs. I wanted to "upgrade" to the better quality of CDs but what to do with my music collection on vinyl-records and on compact-cassettes? Then I got a job in a big city and stopped driving to work, now I took a long train journey to work. I bought a portable CD player and started buying CDs. Now my previous investment in music was inaccessible to me. Over the years I'd paid a lot of money for all those records and tapes. It seemed unfair that I'd have to pay three times over for the music I wanted to listen to.

So some of my music is on records in the loft, its inaccessible to me, stranded in an old technology. Some is on record and tape. I almost never listen to tapes nowadays - it's too inconvenient finding the right track and rewinding tapes - I've become used to the convenience of CDs where you can access any track instantly. A few albums I have purchased and repurchased on record and on tape and on CD. As I said, this irritates me.

Along came MP3s, I ripped my CDs to MP3s so I could listen to my music wherever my PC or laptop was. The quality was acceptable to me, it was far better than those hissy old tapes in my first car. It seemed I was freed of those old restrictions that stranded so much of my music collection in old technologies.

Along came iTunes. It would be convenient to sample small pieces of tracks on an album and download just those tracks that appealed to me. No longer would I buy an album and find I only liked listening to one or two tracks. However there were also competing online stores like AllOfMP3.com. I became aware of the issues of DRM and the questionable legality of AllOfMP3.com. In the end I downloaded iTunes to my PC because it had a good reputation and I think it right that music authors should get a reasonable payment for their music if they want.

I started buying my music through iTunes. I don't have an iPod, I listen on my PC, but I reasoned that if I really needed to transfer my music out of iTunes I could always use iTunes to burn a CD then rip the CD to MP3.

Along came iTunes-plus, by paying a bit extra you could buy music in a form that could be transferable to any portable music player, not just iPods. I carried on buying the cheaper DRM-protected tracks.

I bought a Nokia phone. It could play MP3s and unprotected AAC files. I transferred some of the MP3 files I had ripped from CDs. It was fun. Now I wanted to transfer some of those tracks I'd bought via iTunes. I created a CD. I listened to it, most of the tracks were really awfully distorted, basically it was unusable.

I paid iTunes a lump sum to upgrade my purchased music to iTunes-plus DRM-free versions. Alas many tracks are not available on iTunes-plus. I'm forced to waste hours messing around with awkward and poor-quality workarounds in order to be able to enjoy my music when away from my PC.

I'm greatly irritated that over the years, the music industry has been actively working to make it harder and more inconvenient for me to enjoy my music at places, times and using devices that are convenient to me, the consumer. For the music industry, the consumer is NOT king.

Maybe Apple and the electronics manufacturers have their arms tied behind their backs by the music industry but they have really failed to make the music business work in a way convenient to their customers.

I see no good reason for the artificial barriers between formats and devices. Why cant I play music I bought from any on-line store on any music-playing device I've bought?
Red Gritty Brick
This page was loaded Dec 20th 2014, 11:29 am GMT.