November 2004 Archives

FotoBuzz

| 1 Comment

Wes and Dudley have done it again.

From the makers of Gush comes FotoBuzz, a Flash application allowing you to easily annotate digital images.

The tool is remarkably simple to use, and very effective. Simple click the add comment button, position the comment over the area in which it applies (resizing as necessary), and enter the title and text for the comment in the appropriate text fields. The information then gets posted to a server side script (php or python) that process the comment and allows visitors to see the annotations.

FotoBuzz has been used to annotate a Gush screenshot. Check out the example here, and don't forget to try out the demo on FotoBuzz's main page.

Great job guys.. I haven't seen anything like this on the internet at all yet. This is a great use of Flash, and an awesome idea. Makes me wish I thought of it first!

FotoBuzz Website

User interface design

| 4 Comments | No TrackBacks

I've been working lately on designing an application interface. If you've ever done interface design before, you know it's not as straightforward as it may sound. In general, you never get it right the first time...

One thing I've learned in my years of programming is test early and test often (not just with user interfaces, but with your classes as well). Make prototypes and get them in front of people to see how they interact. Take the best ideas from each prototype and build off of those until you get something more usable than your original concept. Through a process of iterative refinement you can make your application highly usable for a large group of people.

Here are some guidelines that I've found helpful in designing applications to get you started on the right track.

At the very least, I would recommend reading Apple's guidelines. Generally, whenever Apple makes a recommendation in regards to design it's best to at least consider what they have to say. For instance, the menubar at the top of the screen is much more effective than having a menubar at the top of each application window. Be cognizant of Fitts' law.

If you get through all of the links above you notice there's a constant theme that emerges. The same items appear in multiple guideline lists - that should tell you something about application design. Experts have spent countless hours and lots of money to come to a few basic ideas that have been proven effective. By using those basic ideas in your own applications, you can provide a "more better" user experience. After all, experience matters.

If you have any other good links, please add them in the comments. Enjoy some good weekend reading material...

The v2 list-based components don't have an event for letting a user double click a row in the list. That's changed as of today.

Consider the following code snippet:

// Double-Click Hack for List-based components
// Nov. 15, 2004 - Darron Schall

// create quick reference to ScrollSelectList's prototype
var sslp = _global.mx.controls.listclasses.ScrollSelectList.prototype;

// only run this code once.., make sure that $oldOnRowPress is not
// defined to avoid inifinite recursion when onRowPress is called
if (!sslp.$oldOnRowPress) {
	sslp.DOUBLE_CLICK_INTERVAL = 300; 	// in milliseconds, how close two clicks must 
											// be received to register as a double click

	// save a reference to the onRowPress function since we need to overwrite it to add 
	// functionality, and we don't want to lose the original.
	sslp.$oldOnRowPress = sslp.onRowPress;
	
	// add doubleClick event to the ScrollSelectList class
	sslp.onRowPress = function(rowIndex) {
		// if the user pressed the samw row within the time limit, fire off
		if (getTimer() - this.lastPressedTime < this.DOUBLE_CLICK_INTERVAL && this.lastPressedRow == rowIndex) {

			this.dispatchEvent({target:this,type:"doubleClick",row:rowIndex});
		} else {
			// not a double click - record their click time and the row selected to prepare
			// for double click
			
			// only allow double clicks under the proper conditions
			if (this.enabled && this.selectable) {
				this.lastPressedTime = getTimer();
				this.lastPressedRow = rowIndex;
			} else {
				// not really necessary, but just in case.. make sure
				// doubleClick doesn't accidentally fire
				this.lastPressedTime = 0;
				this.lastPressedRow = -1;
			}
			
			// invoke the old method that we just overwrote - using apply to get the scope correct
			this.$oldOnRowPress.apply(this, [rowIndex]);
		}
	};
}
delete sslp;

The basic premise is that when an item is clicked in a list-based component, the onRowPress method is called (see SelectableRow.as). The onRowPress method is defined in ScrollSelectList and is in charge of determining if a row can be selected, then firing off the change event as necessary (which is done in selectRow).

In order to add the double click event, we replace the onRowPress in ScrollSelectList with one that times press events. If the same row was pressed 2 times within a certain interval, we can fire off the double click event. We also make sure to call the original onRowPress (that we saved in $oldOnRowPress) in order to keep current functionality working.

In order for this to work, place the above code snippet on a frame after the export frame for the classes in your movie. The code modifes the ScrollSelectList class at runtime, so ScrollSelectList must be loaded before this code executes. Typically, you can just drag a list on the stage and place this code in frame 1 since the default export for classes is before frame 1.

Then, you can listen for a new event - "doubleClick" - from List, Tree, and DataGrid components. Anything that inherits from ScrollSelectList now has a doubleClick event. Sample usage is as follows:

// drag v2 list component onto stage and name it "list"
// place above code on frame 1 followed by below code:
list.dataProvider = [{label:"test"},{label:"test2"},{label:"test3"}];
list.addEventListener("doubleClick", mx.utils.Delegate.create(this, onItemSelected));
function onItemSelected(eventObj) {
 	// do something with the selected item
	trace("double click");
}

Yup, this is a hack.. As always, your mileage may vary.

Good luck, and enjoy!

When this isn't this...

| 3 Comments | No TrackBacks

One of the privileges I have at my new job is being able to teach Flash training classes once a week. This week's class will finish up functions and elaborate on variable scope and event handling. We'll also build a first "real" application from the ground up. In preparing my notes, I was reminded of a problem that confuses a lot of new users still trying to grasp scope...

When Flash MX came out (years ago) a brilliant consequence was realized over Flash 5 - all of your code could now be placed on frames. It seems like such a simple concept, but it was brand new at the time. Sure Flash 5 had frame actions, but the Player had been updated to allow event handling code to be placed on a frame instead of requiring the code to be placed on a specific MovieClip or Button instances. This allowed for complete separation of ActionScript from source .fla files which resulted in a major boost in workflow. No more did we have to spend hours trying to find the nested movieclip 6 levels deep that contained the event handling code we sought. Double click the wrong thing when you're nested that deep and you lose your actions.. good luck finding them again, especially if you have the classic "blank" mc on the stage just to use it's enterFrame event.

For me, the change was welcome. I've always been heavy on the coder side and having large script blocks fit my mental model perfectly. The change was easy, too. We just replaced actions on MovieClips (like, onClipEvent(enterFrame) { ... }) with actions on Frames (movieClipInstance.onEnterFrame = function() {.. }). Awesome.. Everything was the same, worked just as well, and it was easier to write code and maintain it. Definitely a win - I couldn't imagine going back to placing event handling code on individual instances. Can you?

In the change, however, a subtle shift in scope occurred on Buttons. Consider the following code:

// button on the stage "aButton"

// actions on the button look like this, obviously not commented out though
/*
on (press) {
	trace(this.prop);
}
*/

// actions on the frame are below:
prop = "timeline property";

aButton.prop = "button property";

// the on press is a button event

aButton.onRelease = function() {
	trace(this.prop);
}

The code is simple. We create a variable on the timeline called "prop." We also create a variable with the same name inside of the button instance. The button then has a press event on the button itself, and a release event that contains the exact same code but defined as an event handler property on the frame containing the button.

When the code executes, if you press the button you see "timeline property" in the output. Likewise, if you release the button you see "button property." What happened? If the code in the event handler is the exact same, shouldn't we see the same thing? The simple answer is "this" isn't what we expected it to be. When you define event handlers in frame actions, "this" is scoped to the object containing the listener that receives the event (there are expections, of course). However, if you use an event handler on a button itself, "this" actually refers to the timeline the button resides on. In this example, the aButton.onRelease has "this" as the button instance, but the on (press) has "this" as the timeline the button lives on. Crazy, huh?

I don't believe this is too much of a problem anymore today since most people I come in contact with no longer rely on the "Flash 5" style of event handling. However, the button and movieclip event handlers have not been deprecated, so the chance to make this mistake still exists. If you use button event handlers I'm sure you're already aware of this. If you don't use button event handlers, now is not a good time to start.

I know this is old news to a lot of you.. but again, I was thinking about this today as I was preparing my notes for tomorrow's class. I thought I'd share this in the chance that this entry might lead someone to greater understanding.

Voting Results Flash RIA

| 3 Comments | No TrackBacks

This is a nice example of an RIA that updates in realtime with the latest results of the US Presidential election. Lots of cool little features.. great use of Flash, and very informative.

US Elections @ BBC News



About this Archive

This page is an archive of entries from November 2004 listed from newest to oldest.

October 2004 is the previous archive.

December 2004 is the next archive.

Find recent content on the main index or look in the archives to find all content.

Archives

OpenID accepted here Learn more about OpenID
Powered by Movable Type 5.02