i
i
i
i
i
i
i
i
472 19. Building Interactive Graphics Applications
Figure 19.3 shows a translation from this verbal solution into a simple pro-
gramming structure. We introduce the set of AllWorldBa lls to represent all the
balls that are currently on the computer screen. The only other difference between
the pseudocode in Figure 19.3 and our verbalized solution is in the added elapsed
time check in Step (C): SufficientClockTimeHasElapsed. (Recall that the veloci-
ties are dened in pixels per second.) To support proper pixel displacements, we
must know real elapsed time between updates.
As we add additional details to parse and execute the user’s commands (B), the
solution must be expanded. The revised solution in Figure 19.4 shows the details
of a central parsing switch statement (B) and the support for all three commands
a user can issue: dening a new HeroBall (B1); selecting a HeroBall (B2); and
adjusting current HeroBall velocity with the slider bars (B3). Undened user
actions (e.g., mouse movement with no button pressed) are simply ignored (B4).
Notice that HeroBall creation (B1) involves three user actions: mouse down
(B1), followed by mouse drag (B1-1), and nally mouse up (B1-2). The parsing
of this operation is performed in multiple consecutive passes through the outer
while-loop (A): the rst time through, we create the new HeroBall (B1); in the
subsequent passes, we perform the actual dragging operation (B1-1). We assume
that mouse drag (B1-1) will never be invoked without mouse button down (B1)
action, and thus the HeroBall is always dened during the dragging operation.
The LeftMouseButtonUp action (B1-2) is an implicit action not dened in the
original specication. In our implementation, we choose this implicit action to
activate the insertion of the new HeroBall into the AllWorldBalls set. In this
way the HeroBall is not a member of the AllWorldBalls set until after the user has
completed the dragging operation. This delay ensures that the HeroBalls velocity
and position will not be affected when the UpdateSimulation() procedure updates
all the balls in AllWorldBalls set (C). This means a user can take the time to
drag out a new HeroBall without worrying that the ball will free fall before the
release of the mouse button. The simple amendment in the drawing operation
(D1) ensures a proper drawing of the new HeroBall before it is inserted into the
AllWorldBalls set.
When we examine this solution in the context of supporting user interaction,
we have to concern ourselves with efciency issues as well as the potential for
increased complexity.
Efficiency Concerns. Typically a user interacts with an application in bursts of
activity—continuous actions followed by periods of idling. This can be explained
by the fact that, as users, we typically perform some tasks in the application and
then spend time examining the results. For example, when working with a word
i
i
i
i
i
i
i
i
19.2. Programming Models 473
main() {
while ( GUISystem::UserAction != Quit ) {
switch (GUISystem::UserAction) {
// Begins creating a new Hero Ball
case GUISystem::LeftMouseButtonDown:
HeroBall = CreateHeroBall() // hero not in AllWorldBalls set
DefiningNewHeroBall = true
// Drags out the new Hero Ball
case GUISystem::LeftMouseButtonDrag:
RefineRadiusAndVelocityOfHeroBall()
SetSliderBarsWithHeroBallVelocity()
// Finishes creating the new Hero Ball
case GUISystem::LeftMouseButtonUp:
InsertHeroBallToAllWorldBalls()
DefiningNewHeroBall = false
// Selects a current hero ball
case GUISystem::RightMouseButtonDown:
HeroBall = SelectHeroBallBasedOnCurrentMouseXY()
if (HeroBall != null)
SetSliderBarsWithHeroBallVelocity()
// Sets hero velocity with slider bars
case GUISystem::SliderBarChange:
if (HeroBall != null)
SetHeroBallVelocityWithSliderBarValues()
// Ignores all other user actions e.g. Mouse Move with no buttons, etc
default:
} // end of switch(userAction)
// Move balls by velocities under gravity and remove off-screen ones
if ( OperatingSystem::SufficientClockTimeHasElapesd)
UpdateSimulation()
DrawBalls(AllWorldBalls)
// Draw the new Hero Ball that is currently being defined
if (DefiningNewHeroBall)
DrawBalls(HeroBall)
EchoToStatusBar() // Sets Status Bar with number of balls currently on screen
} // end of while(UserAction != Quit)
} // end of main() function. Program terminates.
(B1-1) Support
for dra
g
actions
(B1): Define new
Hero Ball
(B2): Select
current Hero Ball
(B3): Set Hero
Ball Velocity
(A):
(B4): Undefined
actions are ignored
(B1-2) Implicit
Action
(B):
(C):
(D):
(D1): Draw the
new Hero Ball
(E):
Figure 19.4. Programming solution based on the control-driven programming model.
processor, our typical work pattern consists of bursts of typing/editing followed
by periods of reading (with no input action). In our example application, we
can expect the user to drag out some circles and then observe the free-falling of
the circles. The continuous while-loop polling of user commands in the main()
function means that when the user is not performing any action, our program will
i
i
i
i
i
i
i
i
474 19. Building Interactive Graphics Applications
still be actively running and wasting machine resources. During activity bursts,
at the maximum, users are capable of generating hundreds of input actions per
second (e.g., mouse-pixel movements per second). If we compare this rate to the
typical CPU instruction capacities that are measured at 10
9
per second, the huge
discrepancy indicates that, even during activity bursts, the user command-parsing
switch statement (B) is spending most of the time in the default case not doing
anything.
Complexity Concerns. Notice that our entire solution is in the main() function.
This means that all relevant user actions must be parsed and handled by the user
command-parsing switch statement (B). In a modern multi-program shared win-
dow environment, many actions performed by users are actually non-
application specic. For example, if a user performs a left mouse button click or
drag in the drawing area of the program window, our application should react by
dragging out a new HeroBall. However, if the user performs the same actions in
the title area of the program window, our application should forward these actions
to the GUI/Operating/Window system and commence the coordination of moving
the entire program window. As experienced users in window environments, we
understand that there are numerous such non-application specic operations, and
we expect all applications to honor these actions (e.g., iconize, re-size, raise or
lower a window, etc.). Following the solution given in Figure 19.4, for every user
action that we want to honor, we must include a matching supporting case in the
parsing switch statement (B). This requirement quickly increases the complexity
of our solution and becomes a burden to implementing any interactive applica-
tions.
An efcient GUI system should remain idle by default (not taking up ma-
chine resources) and only become active in the presence of interesting activities
(e.g., user input actions). Furthermore, to integrate interactive applications in
sophisticated multi-programming window environments, it is important that the
supporting GUI system automatically takes care of mundane and standard user
actions.
19.2.2 Event-Driven Programming
Event-driven programming remedies the efciency and complexity concerns with
a default MainEventLoop() function dened in the GUI system. For event-driven
programs, the MainEventLoop() replaces the main() function, because all pro-
grams start and end in this function. Just as in the case of the main() func-
tion for control-driven programming, when the MainEventLo op() function re-
i
i
i
i
i
i
i
i
19.2. Programming Models 475
UIS
y
stem::MainEventLoo
p
() {
SystemInitialization()
// For initialization of application state and
// registration of event service routines
loop forever {
WaitFor ( GUISystem::NextEvent)
// Program will stop and wait for the next event
switch (GUISystem::NextEvent) {
case GUISystem::LeftMouseButtonDown:
if (user application registered for this event)
Execute user defined service routine.
else
Execute default UISystem routine.
case GUISystem::Iconize:
if (user application registered for this event)
Execute user defined service routine.
else
GUISystem::DefaultIconizeBehavior()
} // end of switch(GUISystem::NextEvent)
} // end of loop forever
} // end of GUISystem::MainEventLoop() function. Program terminates.
(A): For application
initialization
(C): Stop and wait
for next event
(D): Central parsing
switch statement
(B): Continuous
outer loop
Every possible
event
Figure 19.5. The default
MainEventLoop
function.
turns, all work should have been completed, and the program terminates. The
MainEventLoop() function denes the central control structure for all event-driven
programming solutions and typically cannot be changed by a user application. In
this way, the overall control of an application is actually external to the user’s
program code. For this reason, event-driven programming is also referred to as
the external control model.
Figure 19.5 depicts a typical MainEventLoop() implementation. In this case,
our program is the user application that is based on the MainEventLoop() func-
tion. Structurally, the MainEventLoop() is very similar to the main() function
of Figure 19.4: with a continuous loop (B) containing a central parsing switch
statement (D). The important differences between the two functions include:
(A) SystemInitialization(). Recall that event-drivenprograms start and end
in the MainEventLoop() function. SystemInitialization() is a mechanism
dened to invoke the user program from within the MainEventLoop().It
is expected that user programs implement SystemInitialization() to initial-
ize the application state and to register event service routines (refer to the
discussion in (D)).
i
i
i
i
i
i
i
i
476 19. Building Interactive Graphics Applications
(B) Continuous outer loop. Since this is a general control structure to
be shared by all event-driven programs, there is no way to determine the
termination condition. User program are expected to override appropriate
event service routines and terminate the program from within the service
routine.
(C) Stop a nd wait. Instead of actively polling the user for actions (wasting
machine resources), the MainEventLoop() typically stops the entire appli-
cation process and waits for asynchronous operating system calls to re-
activate the application process in the presence of relevant user actions.
(D) Events and central parsing switch statement. Included in this state-
ment are all possible actions/events (cases) that a user can perform.
Associated with each event (case) is a default behavior and a toggle
that allows user applications to override the default behavior. During
SystemInitialization(), the user application can register an alternate service
routine for an event by toggling the override.
To develop an event-driven solution, our program must rst register event service
routines with the GUI system. After that, our entire program solution is based on
waiting and servicing user events. While control-driven programming solutions
are based on an algorithmic organization of control structures in the main() func-
tion, an event-drivenprogramming solution is based on the specication of events
that cause changes to a dened application state. This is a different paradigm for
designing programming solutions. The key difference here is that, as program-
mers, we have no explicit control over the algorithmic organization of the events:
over which, when, or how often an event should occur.
The program in Figure 19.6 implements the left mouse button operations for
our ball shooting program. We see that during system initialization (A), the pro-
gram denes an appropriate application state (A1) and registers left mouse button
(LMB) down/drag/up events (A2). The corresponding event service routines (D1,
D2, and D3) are also dened. At the end of each event service routine, we redraw
all the balls to ensure that the user can see an up-to-date display at all times. No-
tice the absence of any control structure organizing the initialization and service
routines. Recall that this is an event-driven program: the overall control structure
is dened in the MainEventLoop which is external to our solution.
Figure 19.7 shows how our program from Figure 19.6 is linked with the pre-
dened MainEventLoop() from the GUI system. The MainEventLoop() calls the
SystemInitialization() function dened in our solution (A). As described, after
the initialization, our entire program is essentially the three event service rou-
tines (D1, D2, and D3). However, we have no control over the invocation of
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.182.107