How to Write a GUI in Java

GUIs are not easy things to write. There are many opinions about how to make it easier, and in that sense this opinion is one among many.

We need a yardstick when comparing methodologies. As a programmer, this boils down to having a fulfilling job. That, in turn, boils down to concentrating on modeling the world, rather than wrestling with syntax. This has the happy side effect of being more efficient (which managers like) and avoiding needless repetition (which most everyone likes). That is, we will pick a methodology that makes us happy.

At a fundamental level, humans view the world as a bunch of objects. OOP makes it easy to convert those notions into a model a computer can run. For me, the so-called Object Domain pattern is the ONLY pattern, because it lets us model the world. (One can criticize this notion, but overall it is the truth, especially at the business level.)

In business, these models are no good if they don't inform us, or if they stray too far from reality. This is the function of IO, which can be a device, GUI, or whatever. We are most concerned with user IO here, though.

Modern user IO is usually handled by a GUI. The person interacts with pictures. The cool thing about pictures is that they present a lot of information in a compact format that (most) humans readily understand.

_________________
Picture Languages

In a very real sense, there is a picture language that has been evolving for about 20 years. The major trend that I have seen is the increase in information presented.

Fundamentally, all user input is a series of keystrokes, mouse clicks. (Sometimes it is visual or aural, but mostly not). More abstractly, you can think of a user specifying points on the screen.

Now, as the system evolves, it occasionally needs input. Converting this basic data into the data the system needs is complex, and is the job of the GUI. So is presenting this information.

(Neal Stephenson has an interesting take on where this language will evolve in _The Diamond Age_)

_______________________
Modern Picture Language

Modern picture languages present a lot of constraint information. They let you select from lists. They give you a bar to slide around, limited by two ends. They look like knobs complete with stops.

______________________________
The nature of system evolution

Computer systems evolve in time in a deterministic way according to their initial state. Whenever the system changes in ways that cannot be predicted, this is non-deterministic. The class of non-deterministic interaction we are interested in is from the user.

The main method that instances an object and manipulates is an example of non-deterministic stuff from the obejct POV.

A GUI can be thought of as providing non-deterministic calls from the object POV as well.

Our object domain presents a set of calls (methods in Java) that can be executed. Displaying object state is an easy problem, because it is deterministic. Modifying object state is not easy for two reasons: its not deterministic, and it involves a lot of data conversion.

Why does it involve data conversion? Keystrokes and mouse clicks must be converted into something the Object Domain understands.

Note that Java doesn't have good support for modeling one particular aspect of Object state, which is the current constraints on its methods.
____________________
The easy conversions

There are a few data types in Java that are very easy to pass to the Object Domain. By convention they are strings and integers. Some complex types are easy, such as date, color, font simple because they are so common and well supported.

_____________________
The Hard converisions

GUIs can be thought of as solving the problem of user specification of complex data types. Its a much harder task to get the user to specify a complex data type. There are only a 2 ways to do it:
1) Pick
2) Build

Picking is easy. Select from a list. (this is a clear application of constraints, BTW).

Building is not easy, simply because it can involve nested builds. Every build is a colletion of picks and simple conversions. The general build problem is recursive!

The recursive build requires some thought to understand. The user wishes to alter the system. But only with the root object. The user must specify objects lower on the object tree before the higher ones. They must be created OUTSIDE of the original context for which they were intended. This implies a meta constraint on our object domain which is guaranteed by java.

One can view the general specification of a complex object by a user like a tree. An object contains all the other objects which are required for its constructor. The user goes 'depth first' from below, picking or specifying primitives (and by primitives, I mean strings, too).

Its important to realize that we can specify all constraints on that root object by a list of primitive constraint. These would be the leaves on the tree (all primitive constructor arguments). We can phrase them in any way we like, grouping them by class, for example.

__________________________________
Time dependance on the constraints

In general, the system (including its constraints) can evolve during the build process. (It cannot evolve because of the build process - this is an important meta-constraint) This can be problematic for the user. In particular, if the user is almost done, an invalid change down the tree invalidates all dependancies.

____________________________
Making a GUI out of the tree

Every node has a Swing Component associated with it. These components can be grouped in containers in such a way that is meaningful and usable for the user.

At the end of it all, the objects are constructed bottom up, no matter the order in which the user specified the list of primitives. (Q: should we require that the objects be constructed from the bottom up as they are specified? No, this is unnecessary since the root method has specified all constraints.)

The user calls the method with the new object they created, and the system state is altered.

___________
Concurrency

In some cases, the user build process occurs disjointed from the system, meaning that the constraints can change between the time the user requests the call, and the time the user makes the call. One solution is to avoid this occurence - to freeze the system for a time. This is pointless, and will be considered no further.

There is no general solution. Sometimes, the call will just not be allowed, and the user must adjust something. If this is a common problem, decreasing latency is the only solution.

Note that modern weblications are a latent model, and applets generally are not.

_________________________________________
Advantages of modeling method constraints

Lots of them. You can do complicated things like enforce client dependant constraints. Client has low memory? Avoid that long pick list. Client high latency? Warn them about it.

The constraints can be executed on the client. For example, in JavaScript

__________________
About transactions

They would have to be supported in the root call. In particular, its important that the root method not be executed concurrently.

_____________________
Modification requests

I've hinted that the client must request to execute a method, and in so doing retrieve a constraint list. I am concerned that certain behavior should be prohibited in the request, e.g. that no change in system state should be allowed. However, I can imagine times when a request for change could modify constraints.

The nice thing is that the request need not be denied out of hand. Any other users that would be affected by the change would be notified.

Note that modifying constraints on a populated system would require the modifier to normalize the system in some way (that is, bring all existing data into conformance).

_______________
Mutlithreaded

BTW, the system is always assumed on a seperate thread from the GUI. Otherwise, it cannot evolve independantly! Even if its a weblication, you can think of the browser as one thread, and the server as another.

___________________
Relationship to MVC

We can use standard MVC methodolgy for a passive client (not much controller, unless there is some way to modify your view of the system, so the controller is modifying the V, not the M). During the build process, the model is the argument to the method.

__________
An example

The main application of these ideas is to business systems.

Lets start small. Single user, simple system. We'll do something that is near and dear to my heart, a game.

First, the system. Lets consider a simple physical system, a one dimensional particle. We can apply an arbitary force at any time. We specify the force, and zap the system with it. To keep the particle bounded on the screen, we specify that it bounces elastically between two walls.

After start up, we specify initial conditions. Then we start the system. Later, we can reset conditions, or we can impart a force. Specification of the force in a one dimensional system is not complicated, but that's good for a start. Who knows, maybe we can add support for different units?

The communcation is this: can I start you up? Sure. Start. OK, can't start anymore, but you can stop or reset my conditions. Can I send invoke a force? Sure, within limits (these limits are determined by the underlying machine. We want to have meaningful representation of motion.)

On the client, we can have real time numerical or slider bar representation of position and velocity. Force can be specified using any number of widgets. Further, continuous force mode can be started. We may even add support for a constant or time dependant force (rather than the impulse we already have).

How can we make this into a game? Well, we could have the user attempt to get the ball to hit the sides at a particular cadence. Or something. Maybe its just fun watching the particle!

Thought on space dependant force. Could be represented by a bar on the display, and can move. in time. Movable walls.

Ideas: Present the user with preset forces (elephant foot, car collision, butterfly wings), provide ability to scale.

Q: Should derived information be part of the model or the view? It doesn't really matter, but I would prefer if it were part of the model. From a design/process point of view this makes the most sense.

______________
Implementation

I have lots of ideas about how to automate the constraint process. For now, we will forget all that and do it manually.

First, the model.

There is an upper limit to how often the model can be updated which is system dependant. This limit may be different from the display rate. Ideally the client should tell the system how often it wants to be notified. (this is an example of concurrency).

The model will be simple. Force, Particle, Mass, Position, Frame, Boundary (and ElasticBoundary), and Time. We will have a threaded World object which puts it all together and accepts force requests.

Position is defined WRT Frame. Every Particle has a Mass, Position and Velocity defined for all Time. The World contains an active Frame, and a Particle, and takes force commands. The World starts and stops, and in between sends new Time objects to the World, evolving it. (Perhaps later we will store all force commands for playback).

Some thought needs to be given to coordinates for time and space. Ideally, the World would be able to present itself using different frames (or rather, frame rates).

[Note that this physical model is characterized by steady, regular changes whereas business models tend to change intermittently]

From the View's POV, the system is non-deterministic. However, an interesting excersize (later) would be to do a distributed version where the system evolves seperately pending messages from other nodes.

How can I get the most dynamic range out of the model? Use a float for the Canonical position and velocity?

The basic display will need some work. In particular, if I allow it to resize, then it must be able to tell the system about its new coordinate system (or rather, that it can give more or less resolution).

__________________________________
Problems specific to this example

Coordinate systems. Ignoring the GUI for the moment, there is an upper limit on computing resolution. You can't change fewer than one bit at a time in a data structure (space). With time, there are actually two constraints: the computer operates at a set speed, and a similar constraint to space.

Assuming that we don't waste resolution by using a float from 0.0 to 1.0, I am perfectly happy to use this normalized system for everything. If we would waste resolution, then we should use an integer type, such as a long, a double, or even a BigInteger (although the replacement from IBM should be used, instead of the native one).

We have a choice, now. Since our representation is bound, and so is our particle, we could choose to make this an integral part of the model. That would be simplest, so that is what we will choose. There may be a way around this, but it doesn't come to mind.

We wish to allow the user to interpret this information in conventional units. That is, we would like to model 'real life' and so we must provide unit aware constructors.

The user states that the particle moves from 0 to N somethings, and that each second is a *something*. (The system knows how many native ticks there are per second, so it can figure out how many ticks per *something*.)

Some constraints: the particle can be lost between ticks. Consider a lightyear scale, with a particle moving at microscopic values. In other words, velocity cannot go below 1 ( 1 bit per tick ). Velocity changes should not be allowed below 1 bit per tick. That is, accelerations or velocities that are too small must be ignored. Better to tell the user of this than let them think the system is evolving correctly!

In other words, the dynamic range of the system remains constant, but the user should not be allowed to abuse it by entering a 'signal' (initial conditions) that is too small or too large for representation.

_____
Usenet post (unsent)

Hello All,

I am ashamed to say it, but properly modeling the 1 dimensional motion has me stumped. And I have a physics B.S.

The problem isn't really the kinematics, but rather the coordinate systems involved. In particular, there is a basic 'dynamic range' for both time and space, limited by the data structure I choose for each. For example, I might get 32 bits of range for both by choosing an 'int'or a 'float' in Java. The next thing (which has to be measured at start up) is the systems temporal resolution. That is, how many times the system can be evolved per second. (I call each evolution a 'tick', although this doesn't necessarily coorespond to the system clock. It is undoubtadly quite smaller).

From these three basic properties, we can derive some other constraints on the system. For example, the particle's velocity cannot be less than 1 bit per tick. Further, acceleration cannot be less than 1 bit per tick per tick. We may also want to put some upper bounds on velocity, to ensure we do not have a very short run.

Let's assume we are using 32 bits for both time and space. That is a numeric range of about 10E17. If the system evolves at 100 Hz (100 ticks per second), that means our simulation could run for 10E15 seconds of real time(a really long time) if the particle was set to the slowest velocity. If we set space to be 1 meter, then 1 bit of space would be 10^-15 meter (really small). Our minimum velocity would be 10^-15/10^-2=10^-13 m/s. Our maximum velocity would be 10^15 m/s: well beyond reason (and not very interesting, as we would run out of space after one tick!).

Lets try to lay it all out:
x := system space
t := system time
v:= system velocity
x_max = 10E17 ///32 bits of space
t_max = 10E17 ///32 bits of time, or ticks
v_max = 10E17 ///x_max/(t_min = 1)
tickrate = 10E2 Hz ///system dependant, upper limit 2001 PC = 1GHz
ticklife = 1/tickrate ///life in seconds, 10^-2 sec
system_life = t_max * ticklife ///How long the system can run in real time, 10^15 sec
(I suppose we could wrap)/

t_factor := some real value of time, specified per tick, e.g. 1/100 sec per tick
x_factor := some real value of space, specified per bit, e.g. 10^-17 m per tick
t_view := t * t_factor ///this is time as interpreted by human
x_view := x * x_factor /// space as interpreted by human

physical constraints:

1. relative limits on time and space via h (x_factor * t_factor > h)
2. absolute lower limits based on what we can measure (probably much larger than 1
3. absolute upper limits based on properties of universe (age and size)
4. conventional velocity upper bound by 1% error (when relativistic position expression disagrees with classical by more than 1%) x = vt vs. x_r = vt/(sqrt(1-v^2/c^2)) or x/x_r < bound. We can solve for v_upper given bound.
5. absolute velocity upper bound by c.

representation constraints:
we may want to allow clients to modify sample rate based on the ability of the client to represent data. In this case, we have a tick_rate_client which may be larger or smaller than tick_rate. If it is larger, we could interpolate (but in our case this would be rare). If it is smaller, we can reduce the load on the system by sampling at our lower rate.

______
end usenet post

After writing the post, I solved the problem. Some interesting behavior we will see:

1. Some constraints are dependant on the system (velocity constraints) and others are not (factor constraints).

2. Constraints change in time. In particular, if velcity is changing (say, under constant force) then so is the upper limit on how much impulse you can impart. This provides a good example of real time constraint updating, even in a single user environment.

____
Modeling the constraints

I've already done alot of work on this - I called it 'Domain' but its the same thing as Constraint. Ideally, all public methods would have constraints defined. But what is the structure of this thing?

It may be that once I start coding it will be obvious. But lets see how many ways we can think of to do it:


______
Accessing the constraints

A method constraint is valid in the context of its object. Therefore, the constraint should be from the object. E.g. getXConstraint(); where x is a method name (or a property name for mutators). This constraint is immutable from the client, but perhaps mutable from the system.

Another way to do this, which would reduce the number of methods but also avoid compile-time checks and perhaps increase data flow, would be to provide the entire tree from a single call, and force the client to navigate the tree. The former method is superior to this, I think.

_____
Specifying and generating the constraints.

It is a tree structure, either pick or primitive. The generating object may wish to cash pick lists for perormance reasons, but care should be taken to avoid update anomolies.