Александр Клюев - Обработка событий в С++

Тут можно читать онлайн Александр Клюев - Обработка событий в С++ - бесплатно полную версию книги (целиком) без сокращений. Жанр: comp-programming. Здесь Вы можете читать полную версию (весь текст) онлайн без регистрации и SMS на сайте лучшей интернет библиотеки ЛибКинг или прочесть краткое содержание (суть), предисловие и аннотацию. Так же сможете купить и скачать торрент в электронном формате fb2, найти и слушать аудиокнигу на русском языке или узнать сколько частей в серии и всего страниц в публикации. Читателям доступно смотреть обложку, картинки, описание и отзывы (комментарии) о произведении.
  • Название:
    Обработка событий в С++
  • Автор:
  • Жанр:
  • Издательство:
    неизвестно
  • Год:
    неизвестен
  • ISBN:
    нет данных
  • Рейтинг:
    3.8/5. Голосов: 101
  • Избранное:
    Добавить в избранное
  • Отзывы:
  • Ваша оценка:
    • 80
    • 1
    • 2
    • 3
    • 4
    • 5

Александр Клюев - Обработка событий в С++ краткое содержание

Обработка событий в С++ - описание и краткое содержание, автор Александр Клюев, читайте бесплатно онлайн на сайте электронной библиотеки LibKing.Ru

Обработка событий в С++ - читать онлайн бесплатно полную версию (весь текст целиком)

Обработка событий в С++ - читать книгу онлайн бесплатно, автор Александр Клюев
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать

Александр Клюев

Обработка событий в С++

Введение

Так уж исторически сложилось, что в языке С++ нет событий. Событием (event) является исходящий вызов (программисты на VB хорошо знакомы с ними) и в С++ их действительно нет. Иногда события путают с сообщениями (message), но это не верно. Сообщение это прямой вызов: например windows вызывает оконную процедуру для передачи собщения окну. Объект (система) вызывает функцию обькта(окна). Вызов происходит от объекта к объекту. В отличии от сообщения событие имеет другую механику. Объект инициирует событие и вызываются все объекты-обработчики. Т.е. от одного объекта к нескольким. Причем объект инициатор события может ничего не «знать» об его обработчиках, поэтому событие называют исходящим вызовом.

Раз уж в С++ события на уровне языка не поддерживаются, значит стоит организовать их на уровне библиотеки. Здесь приведена реализация такой библиотеки. В ней есть два класса signal и slot.

Итак, чтобы сделать какой нибудь класс источником события поместите в него переменную типа signal:

struct EventRaiser { // источник события

signal someEvent; // void – тип аргумента события

};

А чтобы сделать класс обработчиком поместите в него переменную типа slot, функцию обработчик и свяжите slot с обработчиком:

struct EventHandler { // обработчик события

slotsomeHandler; // переходник

void onEvent(void) {

// функция обработчик события

printf("event handled");

}

void connect (EventRaiser& er) {

someHandler. init(er.someEvent, onEvent, this); // установим связь события с обработчиком

}

};

Так как эти объекты являются частью своих хозяев, не нужно заботится о времени жизни связи. Ее разрыв произойдет во время разрушения одного из них. Событие же инициируется вызвовом метода signal::raise:

struct EventRaiser { // источник события

signal someEvent; // void – тип аргумента события

void someFunc() {

someEvent. raise(); // инициация события

}

};

Пример

В примере создаются два класса обработчик и инициатор события, устанавливается связь между ними и иллюстрируется обработка события в нескольких объектах одновременно:

#include "stdafx.h"

#include "sigslot.h"

struct EventRaiser { // источник события

signal event; // const char* – тип аргумента. может быть void

void raise(const char *eventName) {

printf("raising %s event\n", eventName);

event.raise(eventName);

}

} g_Raiser; // глобальный объект

struct EventHandler { // обработчик события

const char *color;

slot handler; // переходник

void onEvent(const char *eventName) { // обработчик события

printf("\t%s event handled in %s object\n", eventName, color);

}

EventHandler(const char *clr): color(clr) {

handler.init(g_Raiser.event, onEvent, this); // установим связь

}

};

int main(int argc, _TCHAR* argv[]) {

EventHandler red("Red");

g_Raiser.raise("Small"); // событие обработается в red

{

{

EventHandler blue("Blue");

g_Raiser.raise("Big"); // событие обработается в red и blue

}

EventHandler green("Green");

g_Raiser.raise("Medium"); // событие обработается в red и green.

// объект blue уничтожен, связь разорвана

}

return 0;

}

Краткое описание классов

signal– cобытие (детали реализации опущены)

template // Arg – тип аргумента функции обработчика

class signal{

public:

// Инициировать событие

void raise(

Arg arg // Арумент arg будет передан в обработчики события

);

};

slot– переходник для обработки события в классе-обработчике (детали реализации опущены)

class slot{

public:

// установить связь с событием и обработчиком

template <

class Owner, // класс-обработчик

class Arg // Тип аргумента события.

>

void init(

signal&sig, // событие

void (Owner::*mpfn)(Arg), // функция обработчик

Owner *This // обьект обработчик

);

// установить связь с событием и обработчиком для случая signal

template <

class Owner // класс-обработчик

>

void init(

signal&sig, // событие

void (Owner::*mpfn)(), // функция обработчик

Owner *This // обьект обработчик

);

// разорвать связь

void clear();

};

Исходный код

Весь код находится в файле sigslot.h

#ifndef _SIGSLOT_h_

#define _SIGSLOT_h_

// sigslot.h – autor Kluev Alexander kluev@pragmaworks.com

template class signal;

class slot {

friend class signal_base;

slot *_prev;

slot *_next;

struct Thunk {};

typedef void (Thunk::*Func)();

Thunk *_trg;

Func _mfn;

public:

slot(): _trg(0), _mfn(0), _prev(0), _next(0) {}

~slot() {clear();}

public:

void clear() {

if (_next) _next->_prev = _prev;

if (_prev) _prev->_next = _next;

_prev = _next = 0;

}

template

void init(signal&sig, void (Owner::*mpfn)(Arg), Owner *This) {

clear();

_trg = (Thunk*)This;

_mfn = (Func)mpfn;

sig._add(*this);

}

template

void init(signal&sig, void (Owner::*mpfn)(), Owner *This) {

clear();

_trg = (Thunk*)This;

_mfn = (Func)mpfn; sig._add(*this);

}

private:

template

void _call(Arg a) {

typedef void (Thunk::*XFunc)(Arg);

XFunc f = (XFunc)_mfn;

(_trg->*f)(a);

}

void _call() {

(_trg->*_mfn)();

}

};

class signal_base {

protected:

friend class slot;

slot _head;

void _add(slot&s) {

s._prev =&_head;

s._next = _head._next;

if (_head._next) _head._next->_prev =&s;

_head._next =&s;

}

template

void _raise(Arg a) {

slot *p = _head._next;

while (p) {

p->_call(a);

p = p->_next;

}

}

void _raise() {

slot *p = _head._next;

while (p) {

p->_call();

p = p->_next;

}

}

public:

~signal_base() {

clear();

}

public:

void clear() {

while (_head._next) _head._next->clear();

}

};

template

class signal: public signal_base {

public:

void raise(Arg);

};

typedef void VOID;

template <>

void signal::raise() {

signal_base::_raise();

}

template

void signal::raise(Arg a) {

signal_base::_raise(a);

}

#endif // _SIGSLOT_h_

Комментарии:

Не всегда корректный код

Вы приводите указатель на функцию-член класса клиента к указателю на функцию из конкрентного класса (slot::Thunk), это для некоторых классов может быть невозможно, ошибка компилятора, что-то типа "указатели имеют разную природу", наблюдатась для WTL проекта, я в свое время не стал углубляться, удалось обойтись.

Читать дальше
Тёмная тема
Сбросить

Интервал:

Закладка:

Сделать


Александр Клюев читать все книги автора по порядку

Александр Клюев - все книги автора в одном месте читать по порядку полные версии на сайте онлайн библиотеки LibKing.




Обработка событий в С++ отзывы


Отзывы читателей о книге Обработка событий в С++, автор: Александр Клюев. Читайте комментарии и мнения людей о произведении.


Понравилась книга? Поделитесь впечатлениями - оставьте Ваш отзыв или расскажите друзьям

Напишите свой комментарий
x