See event driver from Turbo Vision Source Codes

zhaozj2021-02-16  51

1: In the traditional program, the subject of an interactive function is undoubtedly a cyclic code as follows: Constantly read the user's input, and take the corresponding action according to the input, complete the required function. For example: BOOL quit = false; char ch; while {ch = read_input (); switch (ch) {copy 'i': // ... ... Break; Case 'q': quit = true; / / ... Break; default: // ...}} The program based on the event-driven mechanism is not the same, and the main program may be as follows: int main () {TMYAPP myApp; myapp.run (); return 0 In the entire program, the only thing to have a bit of relationship with the event is a Handleevent function, which may not be like you I imagine (Note: Take the application in Turbo Vision, according to the inheritance of the class, function Call sequence is: tmyapp :: run ()  TApplication :: run ()  TGroup :: execute ()  TGROUP :: EXECUTE ()  TMYAPP :: Handleevent () To process events): Void TMYAPP :: HandleEvent (TAPPLICES) {TAPPLICATION :: handleEvent (event); // act like base if (event.what == evCommand) {switch (event.message.command) {case cmMyNewWin:! // but respond to additional commands myNewWindow (); // define action for cmMyNewWin Break; default: // ... ... Return;}; // clear evenet at handling}} From here, we can see a simple, a gap: there is no headache loop, the program Objects only need to handle the events received, the structure of the program is very simple and clear; but it is also the simple process, which makes it clear and understands. Read the user input, it is already sent in front of the incident, which is a bit can't work, and who is the road in front? Everything, everything is true: read the user's input, and package it into an event, then distribute it to different objects in accordance with certain rules; it is, it has created simple, and it has achieved mystery; It's, users can focus all the efforts in the process of events without distracting other trivial things. For example: Press the left mouse button on a non-active window, the user simply ensures that the window can adjust it to the front desk when the window is received, and it can be displayed correctly. Between the mouse, the system has done a lot of things silently behind the scenes: read the action of the mouse and forms the event, and send the event to the non-active window in accordance with certain rules. The system is completed for us, and the event is driven to the event.

Whether it is curiosity, or asks for knowledge, people have unveiled veil and explore the impulse. The most direct way is to see the source code, borrow a sentence: "Before the source code, there is no secret". In the source code, it will clearly display how the system collects the user's input, and how the user is packaged into an event, distributing the individual objects in the program. Track to the source level level, I believe it is enough to understand the event drive mechanism. However, where do you find such a source code? The Windows operating system is based on event-driven, but where is its source code? The Linux operating system is an active code. However, in the face of its vast file, how to make it easily, practice the source code driver's source code is not can't pull it in the mud. Therefore, it is best to have an event-driven, miniature application framework, which can clearly understand the event drive mechanism and not to scare the climber. Turbo Vision is undoubtedly the best candidate. Turbo Vision is an application framework that provides a new method for DOS-based application development, which can generate a complete interface, including windows, dialogs, menus, mouse, and simple editors. Borland C 3.1 comes with the source code of Turbo Vision, and the source code of Turbo Vision can also be found. The framework of the Turbo Vision application is as follows:

TMYAPP -> TAPPLICATION -> TPROGRAM -> TGroup -> TView -> TOBJECT -> TPROGINIT -> TSTreamable Figure 1: Turbo Vision Application Framework A Turbo Vision Application is a view, events, and dumb objects The combination. Below, a simple introduction to the view and dumb objects respectively, as for the event, there will be a detailed introduction. The view is the program element object visible on the screen. In Turbo Vision programs, all visible are views. Title, window border, scroll bar, menu bar, etc. are all views. The view can also be combined to form complex program elements, such as dialogs. The collection of these views is called group. As a special view, the group is composed of an element called its subview, and the group itself can also form a more complex element as a single view and other views such that a complex view chain is formed. Dumb object is an object in the program, not displayed on the screen, cannot interact with the user, so it is called its dummy object. They complete computing, with background tasks such as communication with peripherals, and must be done by view when they need to display information. This is only a simple introduction to Turbo Vision. When used in some concepts, it will be annotated to help readers understand. 2: Introduction to the event is an unable to subdivision, describing the specific events that the application must respond. Each key button, each mouse action, and a certain part of a part of the program constitute a separate event. Therefore, users enter a word is not an event, but a collection of a series of independent keystroke events. Different events have different properties, have different structures, so it is necessary to understand different types of events. The structure of the event is as follows: struct tevent {ushort what; union {mouseeventtype mouse; keydownevent keydown; messageevent message;}; void getMouseEvent (); void getKeyEvent (); void getKeyEvent ();}; The structure of the event tevent can be clearly seen, from essentially Speaking, there are four types of events: mouse events, keyboard events, message events and empty events, corresponding to TEVENT:: WHAT members, Evmouse, EvKkeyboard, EvMessage, Evnothing. According to the value of TEVENT:: WHAT, the TEVENT object can determine its own type, use the corresponding member function getMouseEvent () or getKeyEvent () to get the event. The mouse event includes four: Mouse keys, the EVMOUSETOEUP events caused by the mouse button, the evMouseMove event generated by the mouse, keeps the EVMouseAuto event generated by a key, so the structure of the mouse event is as follows: struct mouseeventtype { Uchar butttons; // Mouse button Boolean DoubleClick; // Do you double click on TPoint where; // When you have a mouse event, the position}; keyboard events are simpler. When a key is pressed, an evkeydown event is generated, and the button information is recorded.

The structure is as follows: struct keydownevent {union {ushort keycode; charscantype charscan;};}; struct charscantype {uchar charcode; // character code uchar scancode; // scan code}; message event sub-command, broadcast and user information three kinds, EVCOMMAND, EVBROADCAST corresponds to command and broadcast, user information can represent user-defined constants. The difference between the three events is the way it is transmitted, and the transmission of the event will be discussed in more detail later. The structure of the message event is as follows: struct message; union {void * infoptr; long infolong; ushort infoword; short infoint; uchar infobyte; char infochar;};}; empty event indicates an event that has been processed. The information contained in this event is no longer useful, it can be ignored. When the Turbo Vision object is processed, the member function Void ClearEvent (TEVENT & E) will set the event as an empty event. Many events finally convert to a certain command. For example: Press the mouse button on a status item in the status line to generate a mouse event. When the status line object is handled, the command event is bound to the command event to determine the command event's Command data member by generating a hung up command event. When you get the command event, get the event to get the event next time, get The order incident just generated. After the event has a simple concept, the following enters the topic: Event driver. 3: The event-driven mechanism faces the event-driven thousands of Wanxu, where is the best entry point? We want to know two main aspects: (1) How does the system collect users' input, pack it into an event? (2) How does the system distribute these events? Because this is the most mysterious place in an event-driven mechanism, as for how objects in the program deal with these events, they are not our concern. We still start from the main program main (), in accordance with the call sequence of the function, the 藤 系统 系统 系统 前 前 前 前 前 前 前 前 前 前 前 前 前 替 前 前 前 前 前 替 到

TMYAPP :: Run () -> Tapplication :: Run () -> TPROGRAM :: Run () -> TGROUP :: EXECUTE () Figure 3: Part of the TGROUP's partial source code is as follows: Ushort Tgroup :: execute () {DO {endState = 0; do {tevent E; getEvent (e); // read user input handleevent (e); // Handling user input IF (E.WHAT! = evNothing EventError (e); // If the event is not processed, discard this event} while (endState == 0); // If the group is modal, it will be executed until the // endmodal member function termination group Modal (! "); Return endstate;} Here, we have seen familiar processes: constantly read the user's input, then processed until the user exits. This is in the expectation, which is this cycle completed interaction. Even if event-driven is based, this cycle code is less. 3.1: Wherever the event is incident, how the system collects the user's input and packaged, which is attributed to the mysterious Void getEvent (TEVENT & Event) function. The getEvent function is the only function that must care about the event source in Turbo Vision. It is known from the inheritance relationship of the class: TGROUP inherits from TVIEW, and it does not overload the base class. So, in tgroup :: execute (), call is TView :: getEvent, tracking can know: void TView :: getEvent (TEVENT & Event) {if (Owner! = 0) Owner-> getEvent (event);} TVIEW invokes the GetEvent member function of its owner, and in a Turbo Vision application, a TProgram (or TAPPLICATION) object is the ultimate owner of all view classes, so, in the default, each getEvent call is terminated TProgram :: getEvent (unless the user has modified the getEvent member function of a view class).

The source code of the TPRogram :: getEvent is as follows: void tprogram :: getEvent (TEVENT & Event) {if (pending.what! = EvNothing) {Event = Pending; pending.what = evNothing;} // Consider whether there is a hanging from the previous event Event Else {Event.getMouseEvent (); if (event.what == evNothing) {event.getKeyEvent (); // Consider whether there is a mouse event, keyboard event if (event.what == evNothing) iDLE (); }}}} (Statusline! = 0) {// For keyboards and mouse events of the status row, switch directly into the corresponding command event // to avoid a unnecessary loop. IF ((Event.What & EvkeyDown)! = 0 || ((Event.What & evmousedown)! = 0 &&firstthat (HASMOUSE, & Event) == statusline)) statusline-> handleevent (Event);}} in tprogram: : GetEvent, first check if there is a suspend event generated by tprogram :: putevent, and then check the mouse event, the keyboard event, if all, call the IDLE function, indicating that there is no incident. If the user wants to add new events (such as reading characters from serial port), you can override TAPPLICATION :: getEvent in the application object. Add a getcomEvent (Event) call in the getEvent's loop code. If the user does not want to modify the loop code, you can overload the IDLE function. When there is no mouse, the keyboard event, perform getcomEvent. One thing to note is that the task executed in the IDLE cannot suspend the application, otherwise the user's input will be blocked, resulting in an illusion that the program cannot respond. At this point, the acquisition of the event has gradually understood, and the clouds cover the smog of getMouseevent, GetKeyEvent, etc. The source code is listed below, which is omitted: 1: Suspending Events Generated by Putevent, the view of the view calls the PUTEVENT of the owner, so default, all views of PuteVent calls are terminated TProgram :: Putevent. TPROGRAM :: PuteVENT Backs up the Event to the class's static variable pending, returning when the next tprogram :: getEvent call.

void TProgram :: putEvent (TEvent & event) {pending = event;} 2: mouse events obtained from mouse events TEvent :: getMouseEvent functions, tracking call sequence which found: TEvent :: getMouseEventTEventQueue :: getMouseEvent, and TEventQueue :: The source code of GETMOUSEEvent is as follows (TeventQueue is a mouse event's FIFO queue, which can accommodate the number of events): Void TEVENTQUE :: getMouseEvent (TEVENT & EV) {if (mouseeevents == true) {getMouseState (EV); // Current mouse status if (ev.mouse.buttons == 0 && lastmouse.buttons! = 0) {ev.What = evmouseup; lastmouse = ev.mouse; return; // Get a release button event (evmouseup)} (Ev.mouse.Buttons! = 0 && lastmouse.buttons == 0) {if (ev.mouse.buttons == DOWNMOUSE.BUTTONS && ev.mouse.where == Downmouse.where && ev.What - Downticks <= Doubledelay Ev.mouse.doubleClick = true; // Judgment Event Double-click DownMouse = ev.Mouse; autoticks = DOWNTICKS = ev.What; AutodeLay = RepetDelay; ev.What = evmousownloadown; LastMouse = ev. mouse; Return; // Return to one mouse Double-click Event (Ev.Mouse.Buttons = lastmouse.buttons; if (ev.mouse.where! = lastmouse.where) {ev.What = evmouse_ {ev.What = evmouse; Return; Return ; // Returns a mouse mobile event (evmousemove)} if (ev.mouse.buttons! = 0 && ev.What - autoticks> autodlay) {autoticks = ev.What; autodelay = 1; ev.What = evmouseauto; LastMouse = Ev.mouse; Return; // Press the button button unto,

The EvMouseAuto event}}} ev.What = evNothing; // None mouse event} Personally, tracking to this step, you can initially see the clues of the mouse event, then learn to track the mouse TMOUSE of Turbo Vision and Low-level support THWMOUSE, where calling interrupt program INT86 (0x33, & regs, & regs) requires the system to provide support for mice, and is incorporated in this paper. 3: Compared to the keyboard event, the keyboard event is much more, directly call the interrupt handler to get button information on the keyboard: void tevent :: getKeyEvent () {// call interrupt to get keyboard event ASM {MOV AH, 1 Ion; jnz keywaiting;}; what = evNothing; return; keydown; asm {mov AH, 0; INT 16H;}; keydown.keycode = _ax; return;} 4: status line (tstatusline) Special Processing If the mouse event or keyboard event occurs on the status line, call the TSTATUSLINE's event handler Handleevent, transfer the mouse event or keyboard event into a command event, call the PuteVent to a command event before tprogram :: getEvent returns. In the event queue, return the next time to return to getEvent, thereby reducing the mouse or keyboard event to the status line, then converting into a command event, and returning this unlike. 3.2: The transfer event of the event has been taken by TProgram :: getEvent, and each object also knows how to deal with them to receive events, and the middle bridge is undoubtedly an event transfer mechanism. This requires the concept of the group, and the essence of the event deepens more about a layer of understanding. The group is an object that contains and manages other views (known as a group). The group authorizes part of its management zone to a sub-view. For example: Tapplication is a group object, managing the entire screen, contains three sub-views, TMenuBar, TDesktop, TSTATUSLINE, and the top line of the screen is separated to TMenubar, and the bottom of the screen will be given to TSTATUSLINE, and the rest is owned by TDESKTOP. This is true, however, not allowing the child view overlap, but it is not possible. So how do you handle overlapping subview? Connect the child view to a group of processes, called the insertion process. After creating a child view, insert it into the group. The group records the insertion order of the subview, ie z order. The z order determines the order of display of the group neutral view and the sequence of delivery of the event. The subview chain in the group is a loop chain, pointer TView * Last point to the last subview in the last view chain. Insert the new subview each time you inserted into the chain. When the display is displayed, it is displayed one by one according to the order insert, so the last inserted subview is displayed at the foremost, covering the previously inserted subview. The Turbo Vision view can be defined as a modal view, i.e., only the view and its sub-view can be interactive with the user, other objects in the program cannot receive the user's input. For example: The dialog is a modal view. When a dialog is active, everything outside the dialog cannot receive the user's input.

However, the status line is an exception: During the program running, the status row has been in the optional state, even when the program is performing a modal view that does not contain the status line. In the front, the event is divided into mouse events, keyboard events, message events, and empty events. It is based on the source of the event; the event can be re-categorized according to the transfer method of the event: location event (ie mouse event), focus event ( That is, keyboard event and command events) and broadcast events (broadcast events and user-defined information). Event always passes from the current modal view. Under normal circumstances, the current modal view is a Tapplication. When a modal dialog is executed, the dialog is the current modal view. The transfer process of the event is in the TGroup :: Handleevent function, its source and corresponding secondary functions are as follows: void Tgroup :: Handleevent (TEVENT & Event) {tview :: HandleEvent (event); // Handle the Mouse Selection HandleStruct HS (Event) , * this); // Pack the event, the view is packaged into a structure IF ((Event.What & FocusedEvents)! = 0) {// Consider the focus event Phase = phpreProcess; Foreach (DohandleEvent, & HS); Phase = phfocused; dohandleevent Current, & HS

Phase = phpostProcess; Foreach (Dohandleevent, & HS);} else {phase = phfocused; // Considering location event IF ((Event.What & Positionalevents)! = 0) Dohandleevent (Firstthat (Hasmouse, & Event), & HS); ELSE / / Consider the broadcast event Foreach (DohandleEvent, & HS);}} // end_of_handleevent

Struct Handlestruct {// The event, the view forms a processing structure Handlestruct (TGROUP & G): Event (E), GRP (g) {} tevent & Event; tgroup & grp;

Static void dohandleevent (TView * p, void * s) {// subview P complete the processing of the focus event Handlestruct * Ptr = (Handlestruct *) s; // If the view P does not exist, or the view P is disabled and the event is position Event or focus event if (p == 0 || ((p-> state & sfdisabled)! = 0 && (Ptr-> Event.What & (Positionalevents | FocusedEvents))! = 0)) Return;

Switch (PTR-> Grp.phase) {CASE TView :: phpreprocess: IF ((p-> options & appreprocess) == 0) Return; Break; Case TView :: phpostProcess: IF ((P-> Options & OffstProcess) == 0) Return; Break;} // If this view can handle this event, call your own handleevent to process IF ((Ptr-> Event.What & P-> Eventmask)! = 0) P-> Handleevent PTR-> Event;} void TGroup :: Foreach (void (* func) (TView *, void *), void * args) {// Call the FUNC function in each view in the z-order view chain, parameter is Args TView * term = last; TView * temp = last; if (temp == 0) Return; TView * next = Temp-> next; do {temp = next; next = temp-> next; func (Temp, args) WHILE (TEMP! = Term);

TView * TGroup :: firstthat (tView *, void *), void * args) {// In the view chain, find the first call FUNC in the z-order, parameter is args, // return value For a true subview TView * temp = last; if (temp == 0) Return 0;

DO {TEMP = TEMP-> Next; // Get the first subview IF (FUNC (TEMP, ARGS) == true) Return Temp;} while (Temp! = last); return 0;} Source code, we can take three types of events: 1: PositionalAlevent starts from the modal view, in the sub-view chain, search in Z-order, find the first subview of the event location, then The modal view passes the event to the subview, which is handled by itself. Since the view can overlap, there may be a plurality of sub-views that overlap the front and rear overlapping include the position of this mouse event, and search for the z-order to ensure that the view is received at the forefront (closest user), ie the user is A view pressing the mouse. This process has been carried down until the terminal view is reached or is stopped when there is no view of the event. If there is a receiving view, the receiving view will handle the event; if there is no view, the event has reached an object that generates the event, and this object will handle the event generated. 2: Focus Event (FocusedEvents) Modal View First Focus Event, then send the focus event in the following three stages: (1) Focus events in the z-order to give each option in each option in each option in each option in each option in each of the options 1 View (focus event is not processed in the front subview); (2) If the focus event is not processed, it is transmitted to a sub-view that is currently focusing in the program; (3) If the focus event is still not Processing, the sub-view of the OFPOSTPROCESS flag in each option in the view chain is still sent in the z-order. The procedure finds a sub-view with focus: Starting from the modal view, looking for its selected sub-view, the process has been going to the terminal view, which is a view with focus. 3: The delivery of the broadcast event broadcast event is relatively easy to understand, pass each sub-view of the z-order to the modal view, such as the sub-view itself is a group, then recursively, guarantee all sub-views of the modal view to receive This broadcast event. For user-defined new events, default, Turbo Vision broadcasts these events, but users can also modify TGroup :: handleevent, customize their delivery. 3.3: The process of events should be said that the objects in the application do not belong to the incidents they receive, but they are discussed in this article, but because some objects are handled in the process, they will call PuteVent generating suspend events, or calls The Message function is sent to send a message event, so only TSTATUSLINE is a simple discussion with TSTATUSLINE. TSTATUSLIN HANDEVENT (...) and the auxiliary function are extracted as follows: void TSTATUSLINE :: Handleevent (TEVENT & Event) {TView :: Handleevent (event); // Handling the selection operation of the view

Switch (Event.What) {Case evmousedown: {tstatusitem * t = 0; do {tpoint mouse = makelocal (event.mouse.where); if (t! = itemmouseisin (mouse)) DrawSelect (t = itemmouseisin (mouse)) WHILE (MouseEvent (Event, Evmousemove)); // Detached a choice action if a loosening mouse event appears (t! = 0 && commandenabled (t-> command)) {// If the mouse click status item Not disabled.what = evcommand; event.Message.command = t-> command; event.Message.infoptr = 0; PuteVent (event); // convert mouse event into hangs} clearEvent (Event) // mouse event is complete, clear drawview (); break;} case evkeydown: {for (tstatusitem * t = items; t! = 0; t = t-> next) {if (Event.keyDown.KeyCode == T-> Keycode && Commandenabled (T-> Command) {Event.What = evcommand; Event.Messa Ge.command = t-> command; event.Message.infoptr = 0; return; // For button events, convert events directly into a command event return}} Break;} Case Evbroadcast: if (event.Message.command == CMCommandSetChanged) DrawView (); // For broadcast, change the command set, then re-displays the status line Break;}}

Boolean TView :: MouseEvent (TEVENT & Event, USHORT MASK) {// Always take the event until any one of Mask, Evmouseup appears. DO {getEvent (event);} while (! (esk | evmouseup))); // Returns 0 if an evmouseUp event occurs; otherwise, returns 1 return boolean (Event.What! = evmouseup); } The source code of the non-related function is no longer detailed here, but gives a simply introduced to help the reader can understand the process of the program, because the naming of its functions is quite clear, when it does not affect the reader's understanding of the program. Mainly want to explain the use of Putevent: TSTATUSLIN Inherits Self-view class TView, in its event handler, first call the selection operation of the class class's Handleevent processing view; then, turn the mouse event, the keyboard event into the corresponding command event, In the static variable pending of TPROGRAM, return to the next GetEvent call (ie, the corresponding mouse action or button action); call the display member function DrawView to re-displays the status line for the command set changes. At this point, the event driver mechanism is clear, and it is clear that the white white is presented in front of the reader. Finally, at a simple example end: In an environment such as BC 3.1, press the left mouse button on a status line (for example: alt-x), the flow cycle process is as follows (assuming this time Hanging events): At this point, the objects in the program have Application, which has three sub-objects: MenuBar, Desktop, Statusline, where Desktop includes two Window objects, each Windows object includes a frame, two scrollbar, a Scroller. The cycle of the event is as follows (in the case where the figure is not expressed, I hope to be able to explain): In TGroup :: execute () cycle, getEventTrogram :: getEvent (Event1) TEvent :: getMouseEvent (event1) TEVENTQUEUE: : getMouseEvent (Event1), Event1 is set to press Event (evmousown), then the original road returns to tprogram :: getEvent, because this action of the mouse is on TSTATUSLINE, before returning to tgroup :: execute, first Call TSTATUSLINE :: HandleEvent (Event1) Converts the mouse event; in TSTATUSLINE :: Handleevent (Event1), the mouse is taken out by a series of EVMouseAuto events generated by the mouse until the evMouseUp event is removed (the response to the mouse button action " At this time, Event1 is evmseup event; then generates a pending command event, the command cmquit is the command bound to the status item ALT X, and clear this button event (Event1 is empty), exit TSTATUSLINE :: Handleevent (Event1), returned to TProgram :: getEvent (Event1).

转载请注明原文地址:https://www.9cbs.com/read-23299.html

New Post(0)