|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Evan Summers's BlogCommunity: JavaDesktop ArchivesA short history of Web UI programmingPosted by evanx on June 26, 2008 at 07:18 AM | Permalink | Comments (12)Web 1.0, XUL, Ajax, Laszlo, Flex and Silverlight have a common approach - declare the UI view using markup (HTML or XML), and use JavaScript to handle the UI events and manipulate the UI. JavaFX/Swing is a notable exception - which is exciting and/or risky?! 'Cos Web developers know and love JavaScript and HTML, so XML plus JavaScript is right up their alley. If you're a Java UI programmer, there's GWT, Wicket and Echo. And with a great new Java plugin in the works, maybe Swing applets will be considered again in some quarters? But all web developers know JavaScript, and not necessarily Java, Groovy, et al, so probably JavaScript/Swing is a better bet than Java/Swing? Imagine having an XML schema for a flashy JavaFX/Swing toolkit, call it JavaFXml, with great JavaScript bindings, so make that JavaScriptFXml ;)
HTML, CGI, Perl
JavaScript, DHTML
Java Applets
PHP
Java JSPs, Servlets
XUL
Ajax
Laszlo
Flex
Silverlight
JavaFX
Everything from HTML, through to XUL, Ajax, Laszlo, Flex and Silverlight, have a common approach, namely let's declare the UI view using markup (HTML or XML), and use JavaScript to handle the UI events and manipulate the UI.
With a great new Java plugin in the works, and other JavaFX-induced improvements for client-side Java, maybe Java/Swing applets will be the preferred option for many of the Java programmers out there, rather than moving to one of the available scripting languages on the JVM eg. JavaScript, Groovy, JRuby, JPython, JavaFX Script? If we want JavaFX/Swing to succeed in the browser, surely we need a GUI tool to design those flashy UIs, generate XML, and be scriptable using JavaScript first, and otherwise Groovy, Java et al, for programmers that prefer those other JVM languages.
Taking a cue from the cutting-edge of EJB3/Seam programming, last week i wrote an article titled "Gooey MVnC" proposing a convention-over-configuration MVC framework for Swing GUIs - to eliminate boilerplate and glue code for beans binding, events and tasks. Everytime i revise that article, i might write a new blog entry, like this one, just so that i can link to it again, which is precisely the reason why i was inspired to write this blog entry!
MVnC architecture for Swing GUIsPosted by evanx on June 19, 2008 at 06:52 AM | Permalink | Comments (0)Rather than put our "application logic" in a "messy" view class, we create a separate "controller" class, with event handlers. We wish this controller class to be as neat and tidy as possible eg. with minimal boilerplate or much else besides our application logic. Let's explore how we might achieve this, using an annotation-driven application framework, with some AOP and convention-over-configuration.
Please submit your comments and suggestions for discussion below. This is an ideas-in-progress, without an implementation (yet). As such this article should be considered to be a first exploratory draft of a design-in-progress... Next month, i'll whip up some kinda prototype, if it's deemed worth it, and if i'm still unemployed ie. with time on my hands.
Our controller class includes annotations in order to enable our framework infrastructure to automatically map events from our GUI components to event handler methods, and to support background tasks and EDT-switching via AOP.
public class LoginController extends GBasicController { @View LoginView view = new LoginView(); // JPanel with components @FormBean User user = new User(); // for form fields auto binding ... @BackgroundTask void fetchUsers() throws DatabaseException { ... // long running task } @BackgroundTaskDone void fetchUsersDone() { ... // update GUI with results from task } @EventHandler void okActionPerformed() { ... // handle OK button pressed } @EventHander void usernameEntered() throw DataException { ... // validate username exists in database view.password.requestFocusInWindow(); } ... } Annotations in our model beans, eg. User, relate to binding and validation, where we wish to support automatic binding of view components to bean properties, eg. by matching component names to bean property names.
Java DroidPosted by evanx on November 21, 2007 at 02:50 AM | Permalink | Comments (2)Recently i was travelling through Europe for three months without my laptop and/or its 3G wireless internet connection, sometimes cycling in the French Pyrenees, not knowing for sure if i would find a bed at the next town, after many hours in the saddle, running out of sunlight, not to mention energy. One of many things i learnt from this wonderful experience is that cellphones ought to have practical web browsers. They ought to negate the need for finding an internet cafe, but they don't, not mid-level handsets anyway. I bought one of the latest Nokia 3G feature phones in London for £89.99, with which i took photo's and sent SMS'es to my heart's content, but browsing the web was not practical eg. searching for accommodation, checking maps, train schedules, booking flights and what-not.
As we now know, Android is another opensource mobile platform, built on Linux et al, with an Apache-licensed Java'esque layer ie. Harmony, Dalvik VM and android.* which includes a brand new UI toolkit. Many handset makers welcome this free offering from Google, who is vendor-neutral, and bidding on the 700Mhz spectrum to boot. Opensource OS'es aren't dominating consumer PCs, and consumers aren't crying out for opensource handsets per se. But phones that integrate well with your favourite Google services may be very attractive to customers. Nokia, RIM and Apple have their own smartphone software platforms, and so they aren't in the OHA, where handset makers commit to producing an Android phone. Carriers want to offer great phones to their customers, but also they are a conservative bunch, and concerned about VoIP and IM impacting their revenue, not to mention dual-mode handsets that can switch at wifi hotspots. Are developers crying out for yet another mobile platform? If it affords total freedom on millions of truely open handsets, then for sure. I'm crying out for extending the PC platform to mobiles, so i can write once, run everywhere. Android steps in that direction, being a Linux-based mobile platform. But it is a divergence from mobile Java efforts and standards many years in the making, through collaboration by the major players eg. Sun, Nokia, et al. Android employs the Java programming language, but unfortunately is not a standard or complete Java platform, ie. it doesn't commit to JavaME or JavaSE. Having said that, JavaME is bound to be supported on many Android-based handsets, and in time maybe JavaSE too. There are other Linux-based mobile platforms, and JavaME is pretty universal, so Android is a non-standardised upstart at this stage. We can only wait to see the market penetration of Android handsets in the years ahead, and how developers and other players respond, eg. Sun with JavaFX Mobile. Android's APIs might become a JSR which is then included in the JavaFX Mobile stack, and/or JavaFX Mobile might leverage Android's OS? Who knows!?
The hype around the Blackberry, iPhone and future gPhones is contributing to the rapid growth of the smartphone market in general.
And today's smartphones are tomorrow's affordable handsets.
To my mind the game then gets really interesting when common handsets have converged with personal computers, and these platforms become indistinguishable to consumers and software developers. Gimme a handset with Linux, Firefox, JavaSE, Swing and Webstart - otherwise it's just a gimmicky ol' phone, innit!?
What is Android vs JavaFX Mobile?Posted by evanx on November 13, 2007 at 10:45 AM | Permalink | Comments (11)So the "personal computer" platform with its graphics, internet et al, is converging with telephony handsets, and visa versa. It's nice. I'm trying to understand how Android changes the pace of this convergence, and how it's different to JavaFX Mobile.
Yes please, we want the full JavaSE with Swing on mobile phones already. 'Cos these devices have the CPUs, RAM and display resolutions that our PCs had when Java first started practising its love all across the internets. Some reading suggests that SavaJE was built on a minimal Linux kernel, and that JavaFX Mobile is a Linux/Java stack. Android is also a Linux/Java stack, so, um, can someone please tell me if Android competes with JavaFX Mobile, and what their differences, similarities and/or respective futures, might be? Android is opensource, in fact it's Apache-licensed, and uses Apache Harmony's class libraries. (Linux is GPL, as are many of the native libraries in Android's stack, so it clearly isn't entirely Apache-licensed.) Is JavaFX Mobile to be opensourced? If it has to compete with Android, then i guess it will be GPL'ed. It seems that Android does not put Swing front-and-center at this stage, and maybe that differentiates Android and JavaFX Mobile in their initial incarnations. Will Java developers have to choose between these two mobile platforms, or will handsets support both JavaFX/Swing and Android? That's hard to imagine, given that JavaFX uses OpenJDK and Android uses Apache Harmony, isn't it?
Credits: The image is a print of "Grandpa's Phone" by Hans Oosterban. One quote is inspired by Homer Simpson's "Oh, so they have Internet on computers now!" Another is a Bushism or two in disguise.
Gooey Table ModelPosted by evanx on October 02, 2007 at 06:33 AM | Permalink | Comments (0)We introduce a generic table model supporting a list of backing beans, with simplistic "beans binding" facilitated by java.beans.PropertyDescriptor.
The following demo exercises our table models (and forms).
Incidently, notice how the selection works, eg. click on the search icon to select the person, and enter a blank product ID to select some booty! ;) Later in this series, we'll look at a popup finder for entities.
We implement a table model in our application as follows.
public class ProductMovementDetailTableModel extends GTableModel<ProductMovementDetail> { ProductMovementDetailInfo info = new ProductMovementDetailInfo(); GTableColumn productId = createColumn(info.productId); GTableColumn label = createColumn(info.label); GTableColumn productUnit = createColumn(info.productUnit); GTableColumn unitCost = createColumn(info.unitCost); GTableColumn quantity = createColumn(info.quantity); GTableColumn amount = createColumn(info.amount); public ProductMovementDetailTableModel() { super(ProductMovementDetail.class); ... // setEditable() on column objects } } where we create column objects to contain metadata eg. column headings, types, et cetera. Each row of the table has a backing bean, eg. ProductMovementDetail in the above example. As presented in the Gooey Beans Info prequel, we define metadata for the bean's properties in a "bean info" object, eg. ProductMovementDetailInfo. The column objects wrap "property info" objects which are created in the bean info class. A controller is implemented to handle events from the table component, eg. row selection and cell editing. The beans and column objects are used in these event handlers to reference rows and columns. Disclaimer: This design predates JSR 295 (Beans Binding), which is the future, and so will be presented in future, in this series' 2nd Edition ;) Incidently, the days of my publishing an article every month in this Foundation series seem to have come to an end, because i've been travelling. Right now i'm in Germany, and from next week i'll be cycling across southern France and northern Spain (woohoo!) without a computer, so um, zero productivity...
what i read about today on the computer internet: OpenProjPosted by evanx on September 05, 2007 at 10:29 AM | Permalink | Comments (2)I was excited to read about OpenProj just now. This helps out the opensource desktop by providing an alternative to MsProject, innit. But i got even more excited when i noticed it's a Java/Swing app, as can be seen from the OpenProj CVS. It's always interesting to invetigate how relatively large and serious Swing apps are cobbled together, and to try to pick up a few tips. So I look forward to checking it out, and maybe writing a blog entry or two, should i be so inspired.
Having said that, i've managed precious little time for anything serious since leaving Cape Town a month ago. I've visited friends and family in Johannesburg, London, and currently Russia. In a couple of weeks, Germany, and thereafter (hopefully) i'll be cycling across South of France, over the Pyrennes, and across Northern Spain!? That's still just a dream that i can't believe might actually happen next month, so...
But i do have a Swing article to finish and publish next week or so, called Gooey Table Model. After that, i'll be under the radar for a month or two... So has anyone tried out OpenProj? (I haven't cos i'm on an antiquated Windows98 machine right now, with a painfully slow dial-up connection, and no java...)
Hey the other thing that i invetigated today on the computer internet thingymajig was the H2 database. But i'll ramble incoherently about that tomorrow...
Gooey GoalsPosted by evanx on July 26, 2007 at 05:26 AM | Permalink | Comments (1)So i gave this talk, discussing the following stuff:
JSRs 295 and 296 I gave an overview of what and where JSR 295 and 296 are, with special emphasis that both have public java.net sites with active mailing lists, where all the excitement is happening, and open to everyone to join the fun, which is "A Very Good Thing" :) "It's the way of the future, It's the way of the future, It's the way of the future..." (Howard Hughes' character in the Aviator, loosing it.) I used to say that incessantly to my niece to irritate her. Then i left somewhere for three weeks, and returned, lapsing immediately into "It's the way of the future, It's the way of the future..." as soon as she entered my vicinity. Heh heh. No, i hadn't been mumbling it for three weeks! ;) I suggested that JSR 296 was well scoped to address basic good practice of Swing development, namely Lifecycle, Resource Injection, Actions/Tasks, and Session State. I suggested that i wasn't sure about JSR 295's scope, because on the one hand it is designed to be "beans binding for everything" ie. to bind one property to another property generically, and on the other hand it is implemented specifically as "beans binding for Swing components." I think it might be layered as such, eg. basic property-to-property beans binding (and groups of bindings), and building a Swing layer on top of that, or next to that, which might reuse/extend some basic interfaces, but otherwise is very specific eg. to JTable et al. I've lost track a little bit there, with all the frenetic activity :) Swing I suggested that Swing is onwards and upwards at the moment :)
Strings I was banging on as usual about the problem with string references eg. for properties for binding, JPA queries (in strings), component names for resources, et al - they're not toolable as in refactoring, auto-completion... I suggested that software naturally degrades, and without refactoring, a broken window left unrepaired will lead to a horribly run-down building before very long. Test coverage is meant to address this ie. to make refactoring feasible. But what about maximum assistance from the IDE, eg. auto-completion et al, when it comes to referencing properties, resources, XML elements, in JPA queries, et al!? In an ideal world, the language together with the tools will enable totally safe refactoring on one hand, as well as maximum productivity on the other, ie. prompting, auto-completion, and error highlighting. And of course we always want compile-time errors rather than runtime ones eg. caused by unresolved string references. Gooey After a year so in development, i'm getting to stage where i want to whip this dodgy framework of mine into some kinda state, to release on gooey.dev.java.net. My goals are to address my requirements as follows ;)
Meme This will be an experimental ORM using meta entity objects, and entity property objects to reference "tables and columns" for queries, ie. so that entities are refactorable, without fear of breaking queries. (See the Dog House article.) Technical Writing I do technical writing as a design exercise. When you write about code, you notice areas for improvement. It's like a self review mechanism, innit. Aiii. Also writing reinforces my "Simplicity through Multiplicity" principle. The more classes, and the more methods, the better. If it's easier to explain, then it's probably easier to read and understand too. Opensource I discussed the difference between the GPL and Apache licenses, and suggested that people license frameworks and such-like under Apache, so that companies can reuse their code, without having to track what they're changing - which potentially makes it impractical to assimilate your framework into their code-base. "If you love something, set it free." ;) It's counter-intuitive that it's best to surrender control, but invariably that turns out to be best option, in hindsight.
Gooey Bean ProxyPosted by evanx on July 23, 2007 at 06:39 AM | Permalink | Comments (0)We expose a "presentation model" bean using an interface, used to create a dynamic proxy, with a backing Map of property/values eg. for GUI prototyping, or otherwise a java.bean.
We expose the properties of the presentation model using an interface as follows.
public interface PersonInfo extends GObservableBean { GProperty<String> username(); GProperty<String> firstNames(); GProperty<String> lastName(); GProperty<String> displayName(); GProperty<String> email(); GProperty<Date> birthday(); GProperty<Date> lastLogin(); GProperty<BigDecimal> score(); GProperty<PersonTitle> title(); GProperty<PersonGender> gender(); GProperty<PersonMaritalStatus> maritalStatus(); } In this case, we can use "dynamic proxies" (from java.lang.reflect), to access our bean properties, rather than looking them up using string literal references eg. via BeanInfo. Our proxy object will use the Method name to look up the property. Also, we have the option of not creating a backing bean for starters, which lends itself towards rapid prototyping, since the above property interface is clearly quite concise.
Half Baked BeansPosted by evanx on July 20, 2007 at 03:37 AM | Permalink | Comments (2)Let's define a minimal property interface.
public interface Property<V> {
public void set(V value);
public V get();
}
where its implementation wraps a java.bean.PropertyDescriptor. Now baked beans...
public interface BakedBeanInfo<B> {
public Property getProperty(String propertyName);
}
where its implementation wraps a java.bean.BeanInfo, and constructs a collection of the bean's Property instances. Now the trick is we expose our bean/properties as an interface...
public interface PersonInfo {
Property<String> username();
Property<String> displayName();
Property<Integer> age();
...
}
where we use dynamic proxies to create a bean, and/or bean info, without worrying about the implementation (eg. QBeanInfo presented in Gooey Bean Info et al).
PersonInfo personBean = GBeanFactory.createObservable(PersonInfo.class);
...
GTableModel<PersonInfo> tableModel = new GTableModel(PersonInfo.class);
GForm<PersonInfo> form = new GForm(PersonInfo.class);
...
logger.info(tableModel.getSelected().displayName().get());
form.set(tableModel.getSelected());
where we bind to a backing bean instance (eg. Person.class) ie. a POJO/java.bean with accessors/mutators - or not eg. just use the proxy instance as our presentation model. Lemme repeat... For prototyping, we might not worry about creating a Person.class, but just use the bean info interface to create our observable beans (via dynamic proxy), with built-in PropertyChangeSupport. Our Property implementation might let us specify (default) presentation properties (eg. label, display width, format et al) of that property, and attach validators, as in Gooey Bean Form. waddaya think?!
PS. The next installment on Gooey Beans is immiment at last, about JTable's, since i got the demo working, as in the following sneak preview, woohoo! :)
Notice how the selection works, eg. click on the search icon to select the pirate, and enter a blank booty barcode to select some booty! Later i'll look at a popup finder for entities, rather than switching tabs as it currently works.
My usual blah blah blahPosted by evanx on July 18, 2007 at 01:50 PM | Permalink | Comments (10)In The future of Windows should be open source, the author suggests that "the desktop is becoming obsolete." This always gets my back up! (If you ever want to get a rise out of me, just say exactly that!) My comment was a regurgitation of what i always say on this subject, which is getting so frikkin boring, that i'm boring myself to tears, but since i wrote such a long comment, i thought i would cut and post it, and here it is again. I know, gutting. iTunes is a desktop/internet app. Expect to see more such apps, ie. "internet apps" which are also "desktop apps" - that run outside the browser rather than within it. If you think it's possible to implement the rich Office experience using HTML/Ajax... you're stupid, no offense ;) What about an IDE as an ajax web app - ouch! One can try to emulate desktop apps with web apps, but you'll never get a richer, more responsive user experience, with the same multitude of features - and of course OpenOffice, Kontact et al are improving all the time. And broadband means... click-and-run (and auto-update). Download times are a rapidly diminishing concern...
And why even try to supplant great opensource apps with half-baked web apps full of ads?! Rather make the opensource apps like OpenOffice more "webby." Cos why can't apps run outside the browser? Why does everything have to run inside the browser - including Office, email et al - that's just silly! The web browser (eg. Firefox) will never match the abilities of the OS/desktop (eg. Linux/KDE/GNOME) in terms of managing resources, processes, application windows, eg. tabbing, switching, minimising, exposing, etcetera, etcetera. Why try to turn a cute 5Mb browser into the 100Mb gorilla of a full-blown graphical desktop environment, when the likes of KDE and GNOME exist? No one will ever again develop a graphical desktop environment, from scratch, that can catch up to KDE and GNOME, or would want to... MacOSX is NextStep legacy underneath, and Windows is also legacy proprietary rubbish underneath. So to summarise, rather than desktop apps going away, desktop apps will become more leveraging of the internet and leveragable via the internet, eg. launch from the internet, persist settings et al to the internet eg. using REST, ie. be everything that is good about web apps. Desktops apps already auto-update from the internet which you might have noticed, so... onward and upward! PS. With the advent of internet retailing, eg. amazon.com and the like, people started falling over themselves saying, "This is the future! Bricks-and-mortar retailers will surely all close down!?" Well they didn't. They took what was good about the internet, and added it to what they already had, which was good, and they got better all around. I'll warrant it's gonna be the same with the desktop. Life goes on much as before, just better.
PS. So I think the category "web apps" should make space to include both "browser apps" as well as "webby desktop apps" eg. Webstart Swing apps that use webservices, and not the local filesystem (except for caching and cookies, like a browser).
My checklist for the next yearPosted by evanx on July 14, 2007 at 05:43 AM | Permalink | Comments (4)Things to Streamline I recently started writing a Swing feed reader (FeedTrove.dev.java.net) - which i was on my checklist, so that's ticked - but i have still more things to do there...
More Swing Besides a feed reader, i have a few other "small" swing apps i want to write (desperately!)
Wheels to Reinvent Even though i know the future of web development is JEE/JSF/Seam, because it's standardised, i like interesting approaches like Wicket and Echo2, ie. using Java code (rather than XHTML et al) to build user interfaces ie. a hierachal composition of components. So i started a research project (divlet.dev.java.net) to experiment with that. Having done the basics, I still have two or three big issues to solve in my mind and implement in my svn, but no rush.
Things to Finish The "Gooey Beans" series on aptframework.dev.java.net has temporarily stalled because of two many things on my plate! But i want finish that off in the next few months - with an article per month - including this month! So I got back into it this week, after a few months' neglect. Actually it'll never be finished, but i want to solve some "big" remaining issues for me...
Also "outstanding" but much less of a priority for me is "Hyper Beans," where i want to address describing a printable/viewable document using java code (rather than XML), in order to produce HTML, Excel and/or PDF output - using iText and Apache POI. And after that, ODF. This is for business "documents and reports" eg. invoices and such, and also the results of database queries and such, innit. In the "Jelly Beans" series, i got so many things i want to do, i won't even start! OK, i'll list some of them quickly....
un-Java-ish Things to Do
Now that my goals are set, i begin the task of trying to achieve them innit! But before i start, it's time for me to cycle around Cape Point, for the third time this week, it's nice! Which reminds me, my other blog is called "Getting Fit, Aiii". Because, yes it's true, i'm not really a Java professional. Actually right now, I'm trying desperately to break into the fitness instructing field - much less deadlines and zero stress - and you get to exercise while you work! The position i'm applying for (spinning instructor), requires you to "work" zero or otherwise 45 minutes a day, yeah baby, yeah! And you are encouraged to shout out things like "yeah baby yeah" at the top of your voice every minute or two, which is another perk! ;)
The other seven hours of the day... Actually I would like to be building a real Swing app for real people, using Netbeans 6.0, AppFramework (not aptframework), WebServices and/or JPA - so gimme a bell if you got simple requirements and plenty of bucks!
Chronicles of the Trove: Fixing by DeprefixingPosted by evanx on June 17, 2007 at 07:42 AM | Permalink | Comments (1)I have one very simple rule for design, namely to create as many classes as possible! Let's name this "Evan's Rule of Simplicity by Multiplicity." So I just noticed a simple cue to refactor out a class. Consider the following GUI construction.
public class MainView { JTabbedPane mainTabbedPane = new JTabbedPane(); ... DefaultMutableTreeNode categoryRootTreeNode = new DefaultMutableTreeNode(new CheckBoxModel("All", false)); DefaultTreeModel categoryTreeModel = new DefaultTreeModel(categoryRootTreeNode); JTree categoryTree = new JTree(categoryTreeModel); ... public MainView() { categoryTree.setEditable(true); ... } ... } You see we have a few related components categoryTree, categoryTreeModel and categoryRootTreeNode. They all start with the same prefix ie. category, so as to distinguish them from other trees. So the clue is when seeing such prefixes, refactor them out to a class so as to "de-prefix" them, as follows.
public class CategoryTreeView { DefaultMutableTreeNode rootTreeNode = new DefaultMutableTreeNode(new CheckBoxModel("All", false)); DefaultTreeModel treeModel = new DefaultTreeModel(rootTreeNode); JTree tree = new JTree(treeModel); Map<Category, DefaultMutableTreeNode> treeNodeMap = new HashMap(); Map<Feed, DefaultMutableTreeNode> feedTreeNodeMap = new HashMap(); TreeCellRenderer renderer = new CheckBoxTreeCellRenderer(); CheckBoxTreeCellEditor editor = new CheckBoxTreeCellEditor(); ... public CategoryTreeView() { tree.setEditable(true); ... } ... } So let's name this "Evan's Rule of Fixing by Deprefixing." A further step might be refactoring this to extend something eg. JTree or DefaultTreeModel, rather than being a composition. We hook up that class, to a now simpler MainView.
public class MainView { JTabbedPane mainTabbedPane = new JTabbedPane(); ... CategoryTreeView categoryTreeView = new CategoryTreeView(); ... public MainView() { ... } ... } So our increasingly complex system progressively devolves to a collection of increasingly simple classes. It's nice! PS. Here is (another) sneak preview of this feed reader toy that's been distracting me of late, and the actual reason i wrote this blog entry, ie. as an excuse for this postscript, as will be the case with all entries in this series - I know, gutting. PPS. That's from The Office when David Brent says, "Well, there's good news and bad news. The bad news is that Neil will be taking over both branches, and some of you will lose your jobs. Those of you who are kept on will have to relocate to Swindon, if you wanna stay. I know, gutting. On a more positive note, the good news is, I've been promoted, so... every cloud... You're still thinking about the bad news aren't you?"
There seems to be the odd GUI feeze-up but i don't know why!? I'm doing every GUI-ish thing on the EDT as far as i can see. Personally i suspect JEditorPane! ;) Anyway, one can dispose the frame into the system tray, and pop it up again.
Chronicles of the Trough: Sneak PreviewPosted by evanx on June 07, 2007 at 01:18 AM | Permalink | Comments (4)Here is a sneak preview of a trivial feed reader app using the Java6 SystemTray. It checks a few preconfigured (Java) feeds every 10 minutes, popping up a message when a new article is spotted.
The feedtray app itself is small (18k using pack200), but depends on ROME and AppFramework and their dependencies ie. jDOM and SwingWorker, so the total packed size is around 250k, and unpacked, well... much more! Note that when you minimise or close the window, the frame is disposed, but the app still runs in the SystemTray. You have to right-click on the TrayIcon and choose "Exit" to exit the app and dispose its JVM instance.
You can browse the code for this exercise at
feedtray.dev.java.net.
FeedTray requires rome.dev.java.net
(which requires jdom.org),
Also see "New System Tray Functionality in Java SE 6,"
on the Sun Developer Network,
Splash ScreenPosted by evanx on April 25, 2007 at 01:44 AM | Permalink | Comments (0)If it's gonna take a while to start up our Swing app, then we probably wanna display a splash screen. It's easy with Java6 - just add a -splash command-line option.
We initialise a SplashScreen instance and get its Graphics2D as follows.
public class SplashTest { static Logger logger = Logger.getLogger(SplashTest.class.getSimpleName()); final SplashScreen splash = SplashScreen.getSplashScreen(); Rectangle splashBounds; Graphics2D splashGraphics; protected void initSplash() throws Exception { if (splash == null) { throw new Exception("no splash image specified eg. -splash:mysplash.png"); } splashBounds = splash.getBounds(); splashGraphics = (Graphics2D) splash.createGraphics(); ... } protected void updateSplash(String status, int progress) { if (splash == null) return; drawSplash(splashGraphics, status, progress); splash.update(); } ... } where in drawSplash() we draw a progress bar ourselves over the splash image using the Graphics2D instance.
Screen CapturePosted by evanx on March 28, 2007 at 06:52 AM | Permalink | Comments (6)For documentation purposes (and perhaps remote support), we need snapshot images of our application. So let's build such support directly into our application itself.
We can capture whole desktop, and save it to a PNG file, as follows.
public void captureScreen(String fileName) throws Exception { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); BufferedImage image = new Robot().createScreenCapture(new Rectangle(screenSize)); ImageIO.write(image, "png", new File(fileName)); } Alternatively, we might capture our JFrame, including its window decoration, as follows.
public void captureFrame(JFrame frame, String fileName) throws Exception { BufferedImage image = new Robot().createScreenCapture(frame.getBounds()); ImageIO.write(image, "png", new File(fileName)); }
Interview with Mono's Miguel de IcazaPosted by evanx on March 26, 2007 at 04:47 AM | Permalink | Comments (9)i was just reading an interview with Miguel de Icaza, creator of Mono. He mentions their "Mono Migration Analyzer" tool for users to see the coverage for their (Windows) .NET apps. They collect automated reports generated by this tool to see what features of Mono are missing for most real world applications in the wild, and this is used to prioritise Mono development. He mentions they expect to support 50% of current applications with some minor incremental updates, and Novell is staffing up the Mono team for a big push. Mono 2.0 will support ASP.NET 2.0, but Windows.Forms 2.0 will come later. (When is Mono 2.0 scheduled?) On the opensourcing of Java, he says Mono is targeting the .NET crowd who are typically not using Java, for migration of .NET apps to Linux, so it doesn't impact them. But naturally it will make Java more ubiquitous in the opensource space. He suggests that for desktop applications, Java still has to address its memory usage limitations. (Don't other high-level runtimes like .NET and Mono also have relatively high memory usage compared to native C/C++ apps? I thought this was the trade-off for easing development.) He doesn't seem to like WPF. Although it has some great elements to it, it has some "ugly" ones too, he says. For now they are focussing on Windows.Forms, because people have adopted that in droves, whereas WPF is too new, so not used much yet. (How do these GUI toolkits compare to Swing?)
PS. If Netbeans supported Mono, and automatically converted the uppercase method names to lowercase ones, then i'd give it a try ;)
That is, if Windows.Forms compares favourably with Swing?
Google vs the OpenSource DesktopPosted by evanx on March 24, 2007 at 03:47 AM | Permalink | Comments (0)i was just reading a blog "Google Hasn’t Improved Search" (to kill some time before the South Africa vs Australia cricket match starts shortly). The author says,
Whenever they release a new product, it does nothing to improve the existing search offering. Whenever they do something to change the existing search offering, it's a minor layout move. Whenever there's a new product in labs, it's no longer outlandish, it doesn't make me think and again; is no improvement or change to their core offering: SEARCH. I agreed and added the following ranting comment about Google, which i repeat below. But enough about you, let's talk about me, what i think Google don't seem to have a cohesive plan except to hire anyone who's anyone, away from other companies who need them eg. Sun et al, for what purpose? To take over the information world, to displace and replace everyone else? It doesn't feel right. Rather than leverage and contribute to opensource projects such as Thunderbird and OpenOffice, to web-enable those as stateless RIAs or something, they develop web-based apps for mail, calendaring and docs which are relatively poor in terms of usability and features compared to the opensource desktop equivalents. But at least the web apps have ads! ;) Why don't they use Thunderbird/XUL for gmail? Why not add "G-drive" integration to OpenOffice? And throw in ads somewhere to pay for it. So i think they are taking the industry backwards with their "web-browser-hobbled desktop knock-offs" when they could be driving the whole rich opensource desktop forward to leverage their internet infrastructure, and not just the browser.
But enough about my thoughts, let's talk about my plans
I'm gonna be spending the next few months flitting around the country between Johannesburg, Durban and Cape Town, visiting various family and friends, with my two notebooks and my backpack. One "notebook" is a computer with GSM 3G connection, so i'm good to go. My other very important notebook is paper-based. Cos I find the best way to design software i want to write, is in a coffee shop with pen and paper and a double cappucino or three. After i've overstayed my welcome and exhausted the hospitality of my family and friends once again, i'm thinking of heading over to Europe and getting a job like my mom says i should. I'm justing waiting for Netbeans6 with its minty goodies like JSR295, JSR296, JPA... Ooo, what a good time to reenter to job market! :) Tipsy Snipsy: Forward Focus TraversalPosted by evanx on March 15, 2007 at 04:59 AM | Permalink | Comments (5)As you've noticed, when you press Enter on fields like JTextField et al, an ActionEvent is generated, and focus is not transferred to the next field in the focus cycle. But what if you are not interested in ActionEvent's on fields, and would rather Enter have the same effect as Tab, maybe because your users are used to having to enter data with the Enter key?
protected void setDefaultFocusTraversalKeys() { Set set = new HashSet( KeyboardFocusManager.getCurrentKeyboardFocusManager(). getDefaultFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS)); set.add(KeyStroke.getKeyStroke("ENTER")); KeyboardFocusManager.getCurrentKeyboardFocusManager(). setDefaultFocusTraversalKeys( KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, set); } But then we aint gonna get those ActionEvent's no more, which may or may not be a problem.
Setting Focus Traversal Keys for the Entire Application on JavaAlmanac.com. Using the Swing Focus Subsystem on the Java Tutorial.
System PropertiesPosted by evanx on March 01, 2007 at 07:25 AM | Permalink | Comments (0)
Let's use reflection to set a bunch of configurable values via the command-line using "system properties."
We put our configurable properties into a separate object, specifying the default values, as follows.
public class CommandoDemoProperties { public String host = "aptframework.net"; public int port = 80; public int sslPort = 443; public boolean useSSL = true; public String clientKeyStoreFileName = "keystores/client.private"; public String serverKeyStoreFileName = "keystores/server.public"; ... } We create the following helper to inject any command-line parameters via reflection, according to the field names, eg. -Dport=8080.
public class QSystemPropertyHelper { ... protected void injectSystemProperties(Object properties) throws IllegalAccessException { for (Field field : properties.getClass().getFields()) { Class type = field.getType(); String key = field.getName(); Object defaultValue = field.get(properties); Object value = defaultValue; String string = System.getProperty(key); if (string == null) continue; if (type == String.class) { value = string; } else if (type == Integer.class || type == int.class) { value = Integer.getInteger(key); } else if (type == Boolean.class || type == boolean.class) { value = Boolean.getBoolean(key); } else { logger.warning(key, type); } if (value != defaultValue) { field.set(properties, value); } } } } where we support properties which are strings, integers or boolean values.
Dumbed Down WWWPosted by evanx on February 24, 2007 at 11:26 PM | Permalink | Comments (4)The "Google Operating System" blog entry "Google Docs & Spreadsheets vs Microsoft Office" quotes a Writely post as follows. "One of the reasons the web is so nice is that the page UI is simple... a few things at a time, a very easy metaphor, etc. It passes the 'mom' test - I can usually just tell my mom to go to a site, and she usually can figure it out. I can't remember the last time I could do that with a desktop app. So, even though the windows desktop is 'richer', it's not necessarily better."
My mom is 60 year old granny who has been working on a Linux desktop, using OpenOffice, Thunderbird and Firefox every day for years. Prior to that she used a Win95 computer for email and browsing BBC's Food website, when she was housekeeper and cook in the UK, for Richard Branson's parents, actually :) OK, she didn't setup her Linux desktop herself - my brother did it for her. Well, I don't service my car myself, does that mean i shouldn't be driving a car?! Well in that case, if i was limited to riding a donkey, I'd name it Ajax ;) So that blog tries to imply that the browser is the web, as in collaboration, contextual search and what-not. Shame, maybe they haven't heard of Webservices, which can be consumed by Java RIAs, which can be launched from the browser using WebStart? It's time to start thinking beyond the "browser is the web" paradigm, because the web can be so much more than the browser! In future, our favourite opensource desktop apps like OpenOffice, Firefox and Thunderbird, might get web-enabled and transformed into caching, stateless web clients, eg. using Amazon S3 for storage, and mashing up a bunch of other webservices. But some people believe the web should be so much less than the desktop, dumbed down to the lowest common denominator. When their vested interest is around web ads, can we expect otherwise?
By the time they figure out that ultimately people want more than that, and are better at using computers than they than give them credit for, maybe they'll be classic victims of the Innovator's Dilemma.
Gooey Event HubPosted by evanx on February 16, 2007 at 08:36 AM | Permalink | Comments (6)
We implement a event listener list singleton supporting weak references. Then we can add listeners to an object we wish to observe, and fire events to its observers, without implementing any such support in the observed objects eg. addListener(), removeListener(), fireEvent(). We can choose to fire an event in a background SwingWorker thread, or in the EDT eg. using invokeLater() or invokeAndWait(). So we might use this event hub as a basic event/message bus.
We create BackgroundEvent and UpdateGuiEvent classes to enable some EDT switching as follows.
public EventHubDemo() { ... public void actionPerformed(ActionEvent event) { if (checkForNewMessagesAction.equalsActionCommand(event)) { checkForNewMessagesAction.setEnabled(false); eventHub.fireEventInBackground(new BackgroundEvent(this, event)); } ... } protected void doInBackground(ActionEvent event, JProgressBar progressBar) { if (checkForNewMessagesAction.equalsActionCommand(event)) { try { ... eventHub.fireEventAndWait(new UpdateGuiEvent(this, event)); } catch (Exception e) { eventHub.fireEventAndWait(new ExceptionEvent(this, event, e)); } } ... } where we wish to handle checkForNewMessagesAction in a background SwingWorker thread, and once completed, switch back into the EDT to update the GUI.
Bound Gooey BeansPosted by evanx on February 05, 2007 at 03:07 AM | Permalink | Comments (0)
In the Gooey Beans Info prequel, we explicitly declare properties. Now we allow a bean info instance to be bound to a specific bean, in order to support bound properties ie. firing PropertyChangeEvent's.
In our bean, we instantiate a bound bean info class with PropertyChangeSupport as follows.
public class BakedBean { public final BakedBeanInfo info = new BakedBeanInfo(this); private BigInteger barcode; private String label; private Integer bakingTemparature; private BigDecimal medianLength; ... public BakedBean() { } ... public void setBarcode(BigInteger barcode) { this.barcode = barcode; info.barcode.firePropertyChanged(barcode); } } where we use property "literals" from our bean info to firePropertyChanged(). We can add PropertyChangeListener's as follows.
public class BakedBeanDemo implements PropertyChangeListener, Runnable { BakedBean bean = new BakedBean(); ... public BakedBeanDemo() { ... bean.info.getPropertyChangeSupport().addPropertyChangeListener(this); } ... }
Unhybridising RIA development with SwingPosted by evanx on February 02, 2007 at 11:28 AM | Permalink | Comments (26)Our editor highlights Bruce Eckel's Hydridizing Java.
The timing for Java (applets) for internet clients for Web 1.0 was too early. The bandwidth, RAM and CPU of the common users and their PCs were insufficient for anything other than a browser rending HTML. Naturally this led to the current popular technologies eg. PHP, AJAX, server-side Java, which leverage HTML/browsers. Of course the efforts of Sun et al followed the money to the server-side. However, with megabits of broadband, gigs of RAM, and multicore multigigahertz processing becoming the norm, I contend that events are shaping up for Swing to live up to its potential as a serious candidate for Web 3.0, with Netbeans as one of its many allies. 50megs in the scheme of 2gigs is not relevant, and multi-megabyte WebStart downloads via multi-megabit broadband is worth a few second's wait for a killer application you use regularly.
Java/Swing/Netbeans potentially allows developers to deliver RIA and desktop functionality with rapid ease.
There are engineering problems to be solved (and killer applications to be developed). But fortunately there are lots of engineers,
not least ourselves. And it's opensource, so... Let's do this! :)
Gooey Bean AspectPosted by evanx on January 15, 2007 at 06:36 AM | Permalink | Comments (4)
We use CGLIB to enhance a half-baked Java Bean with no firePropertyChange() invocations in its setters, into a bean that does fire PropertyChangeEvent's from its setters.
Our QBeanInterceptor registers the PropertyDescriptor's setters methods into a setterMap.
public class QBeanInterceptor extends QInterceptor { BeanInfo beanInfo; Map<Method, PropertyDescriptor> setterMap = new HashMap(); BeanPropertySupport beanAnnotation; boolean fireByDefault; ... public Object invoke(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable { Object oldValue = null; Object newValue = null; PropertyDescriptor propertyDescriptor = null; if (args.length == 1 && fireAtWill(method)) { newValue = args[0]; propertyDescriptor = setterMap.get(method); if (propertyDescriptor != null) { oldValue = getOldValue(target, propertyDescriptor); } } Object result = super.invoke(target, method, args, proxy); if (propertyDescriptor != null) { QBean bean = (QBean) target; bean.getPropertyChangeSupport().firePropertyChange( propertyDescriptor.getName(), oldValue, newValue); } return result; } ... } where if the method is a key to an associated PropertyDescriptor in setterMap, then we invoke firePropertyChange() to fire a PropertyChangeEvent.
Here is a trivial demo that is hardly worth downloading. And it's quite large, because it depends on a CGLIB jar. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||