Friday, December 23, 2011

Happy Holidays!

Hey there!  Just wanted to wish all of you a fantastic happy holiday season; it couldn’t be more festive.  For me, Christmas came a little early, though, because of the release of the Unity 3.5 Developer Preview, which is a Beta version of the soon-to-be-released Unity 3.5.  The talk of the town in this grand new release?  The new Flash export feature.
You see, Unity Technologies, the makers of Unity 3D, has added a capability to allow developers to export their games as Flash applications so they can be run without a Unity Web Player plugin or JavaScript activity the browser.  Not only that, web games will run without a plugin in Google Chrome, thanks to Google’s Native Client API.
To quote Unity’s website:
Unity 3.5 is one of our biggest releases to-date. It’s packed full of new features and improvements that we think you are going to love. We can't wait to see what you will create with it, so we've decided to open our 3.5 beta program to the public. Starting today, you can download a time-limited beta version of Unity 3.5.
This release also provides a hands-on preview of Unity's upcoming Flash deployment add-on. Experience first-hand how Flash deployment in Unity opens up new publishing options, by enabling you to push your interactive 3D content to the web through Adobe Flash Player.
Some of those features happen to include a new Particle System (with Legacy particle support included, of course) and a built-in path finding system for Pro license holders (path can be run but not created under Unity Basic).  They’ve re-written the occlusion culling system to allow for doors that open and close, dynamically changing the viewable areas, and has built in LOD support.
They’ve also added multithreaded rendering, which will give a performance boost on multi-core systems.  To see all the new features, check here:  link.  Those of you who want to try the Flash should do it now, because once Unity 3.5 officially ships, you will be forced to upgrade and Flash support will require an additional license like the iOS and Android exports do.
Well, I’ll be playing on 3.5 Beta.  See you soon.
SevenBits

Monday, December 5, 2011

Little Java Neaties–Swing

Today I’m going to show you all the neat little things you can do with Java.  Java is a very versatile programming language, and tonight I’m focusing on Swing.  Included in the package javax.swing and included on all versions of Java, it can be used to create interesting GUI applications.  For those of you who think they know what Java is but are a little sketchy, here’s a small sample to entertain ye:
 
   1:  import java.io.*;
   2:  import java.net.*;
   3:   
   4:  public class RemoteFileCopier {
   5:      public RemoteFileCopier(File name, Socket connection) throws java.io.IOException {
   6:          OutputStream out = connection.getOutputStream();
   7:          InputStream in = new FileInputStream(name);
   8:          
   9:          int ch;
  10:          
  11:          while ((ch = in.read()) != -1)
  12:          out.write(ch);
  13:          
  14:          in.close(); out.close();
  15:      }
  16:  }

Being as it is, I’m not going to explain how to compile or run this code.  If you don’t know how, find yourself a good Java book.  I like Head First Java by Oreilly Publishing, as it includes interesting examples to help you learn Java, including a rudimentary drum beat player.

Anyhow, there are a lot of things Swing can do, namely that it is much simpler than the native Win32 API – heck, I suppose there are WYSIWYG Java GUI builders out there, but Swing (and the AWT) provide an easy way to build complex GUIs in code.  Check this little snippet out, taken from this website.

   1:  // file: EmptyFrame.java
   2:  // Adapted from Core Java, vol.1, by Horstmann & Cornell
   3:      
   4:  import javax.swing.*;
   5:      
   6:  class MyFrame extends JFrame {
   7:    public MyFrame() {
   8:     setTitle("My Empty Frame");
   9:     setSize(300,200); // default size is 0,0
  10:     setLocation(10,200); // default is 0,0 (top left corner)
  11:    }
  12:      
  13:  public static void main(String[] args) {
  14:      JFrame f = new MyFrame();
  15:      f.show();
  16:    }
  17:  }

This class extends the JFrame class, so it doesn’t have to create an instance of it and can call its public methods directly.
Deprecation Warning: If your Java compiler complains about line 15 being “deprecated”, and you want to shut it up, change it to   f.setVisible(true);
Now that code snippet created a window with a size of 300 pixels by 200 pixels.  However, it’s rather empty.  Let’s add a small push button.

   1:  // file: EmptyFrame.java
   2:  // Adapted from Core Java, vol.1, by Horstmann & Cornell
   3:      
   4:  import javax.swing.*;
   5:   
   6:  class MyFrame extends JFrame {
   7:    public MyFrame() {
   8:      setTitle("My Empty Frame");
   9:      setSize(300,200); // default size is 0,0
  10:      setLocation(10,200); // default is 0,0 (top left corner)
  11:      Container pane = getContentPane();
  12:      JButton button = new JButton("CHANGE THIS TEXT");
  13:      pane.add(button);
  14:    }
  15:      
  16:    public static void main(String[] args) {
  17:      JFrame f = new MyFrame();
  18:      f.show();
  19:    }
  20:  }

Now the entire window will be filled with a button.  I hope now you see what Swing is capable of – in fact, you can obviously use Swing to create a GUI for a previously command line run application.  And because it’s Java, it’ll work in every operating system that has a JVM, though the controls will look a bit different depending on your OS.

To demonstrate this point, here’s a simple terminal application using two text fields.  It’s actually a small part of a large module I’m writing for yet another project called Tracker.

   1:  import javax.swing.*;
   2:  import java.awt.event.*;
   3:  import java.awt.*;
   4:  import java.util.StringTokenizer;
   5:   
   6:  public class CommandWindowDialog extends JDialog implements ActionListener {
   7:   
   8:      private JTextArea log = new JTextArea(5, 40);
   9:      private JTextField prompt = new JTextField();
  10:      
  11:      private static final String COMMANDS = "help (h) - shows this window.\n" +
  12:          "quit (exit) <exit code> - exit the program with error code.  if error not specified, command ignored.\n" +
  13:          "clear (cls) - clears the screen.\n" +
  14:          "what - displays information.\n" +
  15:          "echo <message> - echos the message.\n" +
  16:          "exec <program name> - executes the specified program.\n";
  17:      
  18:      public CommandWindowDialog(Tracker parent) {
  19:          super(parent, "Command Window", false);
  20:          setSize(500, 250);
  21:          
  22:          log.setText("Type <help> for a list of commands.\n\n");
  23:          log.setEditable(false);
  24:          
  25:          addComponents();
  26:          
  27:          setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  28:          setVisible(true);
  29:      }
  30:      
  31:      private void addComponents() {
  32:          Container c = getContentPane();
  33:          c.add("Center", new JScrollPane(log));
  34:          c.add("South", prompt);
  35:          
  36:          prompt.addActionListener(this);
  37:      }
  38:      
  39:      public void actionPerformed(ActionEvent e) {
  40:          try {
  41:              CommandWindowDialog.processCommand(prompt.getText(), log);
  42:              prompt.setText("");
  43:          }
  44:          catch (java.io.IOException exec) { JOptionPane.showMessageDialog(this, exec.getMessage()); }
  45:      }
  46:      
  47:      public static void processCommand(String command, JTextArea log) throws java.io.IOException {
  48:          StringTokenizer parser = new StringTokenizer(command);
  49:          
  50:          String head = parser.nextToken();
  51:          
  52:          if (head.equals("quit") || head.equals("exit")) {
  53:              if ((JOptionPane.showConfirmDialog(null, "This will immediatly kill your current connection.  Okay?") == JOptionPane.YES_OPTION)) {
  54:                      System.exit(Integer.parseInt(parser.nextToken()));
  55:              }
  56:          }
  57:          
  58:          if (head.equals("cls") || head.equals("clear")) {
  59:              log.setText("");
  60:          }
  61:          
  62:          if (head.equals("help") || head.equals("h")) {
  63:              log.setText(log.getText() + "Understood Commands:\n" + COMMANDS + "\n");
  64:          }
  65:          
  66:          if (head.equals("what")) {
  67:              log.setText(log.getText() + "This is the Tracker command window.  Here you can see various processes and enter commands.\n");
  68:          }
  69:          
  70:          if (head.equals("echo")) {
  71:              log.setText(log.getText() + command.substring(5) + "\n");
  72:          }
  73:          
  74:          if (head.equals("exec")) {
  75:              Process p = new ProcessBuilder(command.substring(5), null).start();
  76:              p = null; //Prevent memory leaks.
  77:          }
  78:      }
  79:  }

If you strip out the vast majority of the input-processing code, what you’re left with is actually the GUI-building code:

   1:  import javax.swing.*;
   2:  import java.awt.event.*;
   3:  import java.awt.*;
   4:  import java.util.StringTokenizer;
   5:   
   6:  public class CommandWindowDialog extends JDialog implements ActionListener {
   7:   
   8:      private JTextArea log = new JTextArea(5, 40);
   9:      private JTextField prompt = new JTextField();
  10:      
  11:      ...
  12:      
  13:      public CommandWindowDialog(Tracker parent) {
  14:          super(parent, "Command Window", false);
  15:          setSize(500, 250);
  16:          
  17:          log.setText("Type <help> for a list of commands.\n\n");
  18:          log.setEditable(false);
  19:          
  20:          addComponents();
  21:          
  22:          setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
  23:          setVisible(true);
  24:      }
  25:      
  26:      private void addComponents() {
  27:          Container c = getContentPane();
  28:          c.add("Center", new JScrollPane(log));
  29:          c.add("South", prompt);
  30:          
  31:          prompt.addActionListener(this);
  32:      }
  33:      
  34:      ...
  35:   
  36:  }

Although some of you may find this cumbersome, it is certainly much simpler when compared to the native Win32 API, whose code looks like this (when coded in C):

   1:  ...
   2:   
   3:  LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
   4:  {
   5:      switch(Message)
   6:      {
   7:          case WM_CREATE:
   8:          {
   9:              HMENU hMenu, hSubMenu;
  10:              HICON hIcon, hIconSm;
  11:   
  12:              hMenu = CreateMenu();
  13:   
  14:              hSubMenu = CreatePopupMenu();
  15:              AppendMenu(hSubMenu, MF_STRING, ID_FILE_ADD, "&Add File");
  16:              //hSubMenu = CreatePopupMenu();
  17:              //AppendMenu(hSubMenu, MF_STRING, ID_FILE_EXIT, "E&xit");
  18:              AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&File");
  19:   
  20:              hSubMenu = CreatePopupMenu();
  21:              AppendMenu(hSubMenu, MF_STRING, ID_STUFF_GO, "&Go");
  22:              AppendMenu(hMenu, MF_STRING | MF_POPUP, (UINT)hSubMenu, "&Control");
  23:   
  24:              SetMenu(hwnd, hMenu);
  25:   
  26:              hIcon = (HICON)LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 32, 32, LR_LOADFROMFILE);
  27:              if(hIcon)
  28:              {
  29:                  SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM)hIcon);
  30:              }
  31:              else
  32:              {
  33:                  MessageBox(hwnd, "Failed to load large file icon.  It should be in same directory as program.", "Error", MB_OK | MB_ICONERROR);
  34:              }
  35:   
  36:              hIconSm = (HICON)LoadImage(NULL, "menu_two.ico", IMAGE_ICON, 16, 16, LR_LOADFROMFILE);
  37:              if(hIconSm)
  38:              {
  39:                  SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM)hIconSm);
  40:              }
  41:              else
  42:              {
  43:                  MessageBox(hwnd, "Failed to load small file icon.  It should be in same directory as program.", "Error", MB_OK | MB_ICONERROR);
  44:              }
  45:          }
  46:          break;
  47:          case WM_COMMAND:
  48:              switch(LOWORD(wParam))
  49:              {
  50:                  case ID_FILE_EXIT:
  51:                      PostMessage(hwnd, WM_CLOSE, 0, 0);
  52:                  break;
  53:                  case ID_STUFF_GO:
  54:                      if (strcmp (szFileName,"") != 0) {
  55:                          IncinerateFiles(hwnd); }
  56:                      else {
  57:                          MessageBox(hwnd, "No file selected. Select a file using File > Add File.", "Error", MB_OK | MB_ICONERROR); }
  58:                  break;
  59:                  case ID_FILE_ADD:
  60:                      GetNameOfTarget(hwnd);
  61:                  break;
  62:                  case ID_STUFF_ABOUT:
  63:                      MessageBox(hwnd, "(c) 2011 Subversion Systems.  All rights reserved.\n\nNot responsible for any potential illegal use of program.", "About", MB_OK);
  64:                  break;
  65:              }
  66:          break;
  67:          case WM_CLOSE:
  68:              DestroyWindow(hwnd);
  69:          break;
  70:          case WM_DESTROY:
  71:              PostQuitMessage(0);
  72:          break;
  73:          default:
  74:              return DefWindowProc(hwnd, Message, wParam, lParam);
  75:      }
  76:      return 0;
  77:  }
  78:   
  79:  int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
  80:      LPSTR lpCmdLine, int nCmdShow)
  81:  {
  82:      WNDCLASSEX wc;
  83:      HWND hwnd;
  84:      MSG Msg;
  85:   
  86:      wc.cbSize         = sizeof(WNDCLASSEX);
  87:      wc.style         = 0;
  88:      wc.lpfnWndProc     = WndProc;
  89:      wc.cbClsExtra     = 0;
  90:      wc.cbWndExtra     = 0;
  91:      wc.hInstance     = hInstance;
  92:      wc.hIcon         = NULL;
  93:      wc.hCursor         = LoadCursor(NULL, IDC_ARROW);
  94:      wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
  95:      wc.lpszMenuName  = NULL;
  96:      wc.lpszClassName = g_szClassName;
  97:      wc.hIconSm         = NULL;
  98:   
  99:      if(!RegisterClassEx(&wc))
 100:      {
 101:          MessageBox(NULL, "Window Registration Failed!", "Error!",
 102:              MB_ICONEXCLAMATION | MB_OK);
 103:          return 0;
 104:      }
 105:   
 106:      hwnd = CreateWindowEx(
 107:          WS_EX_CLIENTEDGE,
 108:          g_szClassName,
 109:          "Incinerator",
 110:          WS_OVERLAPPEDWINDOW,
 111:          CW_USEDEFAULT, CW_USEDEFAULT, 640, 480,
 112:          NULL, NULL, hInstance, NULL);
 113:   
 114:      if(hwnd == NULL)
 115:      {
 116:          MessageBox(NULL, "Window Creation Failed!", "Error!",
 117:              MB_ICONEXCLAMATION | MB_OK);
 118:          return 0;
 119:      }
 120:   
 121:      ShowWindow(hwnd, nCmdShow);
 122:      UpdateWindow(hwnd);
 123:   
 124:      while(GetMessage(&Msg, NULL, 0, 0) > 0)
 125:      {
 126:          TranslateMessage(&Msg);
 127:          DispatchMessage(&Msg);
 128:      }
 129:      return Msg.wParam;
 130:  }

Now isn't that a good old fashioned pain in the ass?  So, sure, you could use Visual C, which I hear has a drag and drop GUI builder (correct me if I’m wrong), but that requires .NET, which has dependencies and requires the system to be installed for the end user.  Java, although it requires a JVM, requires no such other dependencies, so you’re set on a new PC install.

Also, you’ll notice just code size.  The C Win32 implementation required 130 lines (the actual code is bigger due to trimming of irrelevant parts).  That’s a lot of code for a programmer to write, debug, and maintain.

So, in essence Swing is a much easier GUI creation tool in nearly every way.  If you want to full API docs, the version 7 link is here.

That’s all for tonight, folks.  You can grab our RSS feed to subscribe and always stay up to date.  Hopefully we’ll have more Java talks in the future!  Thank you, and goodnight.

-SevenBits