Цитата(alux @ Mar 12 2008, 12:48)

Согласен. Мой способ мне самому не нравится. Процессов не хватит на каждый пункт меню. В TEditTime и TKeyMenu используются одинаковые конструкции
...
Как бы использовать один процесс TKey, только для редактирования времени выполнять одно действие, а для навигации меню - другое.? Подозреваю, что здесь напрашивается создать класс... Но пока не знаю, как это реализовать. Опыта с ++ маловато.
Вы тут углубились в вещи, которые к осям имеют очень опосредованное отношение - проектирование и разработка пользовательского интерфейса. Для пользовательского интерфейса идеально подходит та часть С++, которая реализует ООП. Вкратце: чтобы не городить мегатонны кода и запутаться в конце концов, применяется тот самый ОО подход - создается абстрактрый класс пункта меню, например, TMenuItem, в нем определяется интерфейс - набор чисто виртуальных функций, которые и будут реализовывать функциональность. Далее, от этого абстрактного класса наследуете уже конкретные классы пунктов меню, в которых определяете конкретное наполнение тех виртуальных функций.
Код
class TMenuItem // абстрактрый базовый класс пункта меню
{
public:
TMenuItem(const char * str);
virtual void draw() = 0; // чисто виртуальная фукнция
virtual void change(int x) = 0;
private:
const char* caption;
...
};
class TMenuItem1 : public TMenuItem
{
public:
TMenuItem1(const char * str) : TMenuItem(str) { ... }
...
};
...
Таких классов надо родить столько, сколько у вас разных пунктов меню. В каждом из этих классов переопределяете фукнции draw и change (или какие там у вас будут функции).
Код
void TMenuItem1::draw() { ... } // конкретная реализация данной функции - отрисовка этого конкретного пункта меню.
void TMenuItem1::change(int x) { ... } // изменение данного конкретного пункта меню
Для остальных классов тоже определить точно так же эти функции. Если есть одинаковые куски кода, то можно их использовать - например, у меня все пункты меню отрисовываются одинаково, поэтому у меня функция draw() невиртуальная и общая для всех классов потомков. А change() - виртуальная, т.к. содержимое пункта меню в каждом случае индивидуально и изменяется, соответственно, тоже индивидуально (к примеру, часть пунктов задает числовые параметры, а часть - строковые).
Теперь организуете сами пункты меню в группы - например, создав массив указателей на объекты этих типов.
Код
TMenuItem1 MenuItem1;
TMenuItem2 MenuItem2;
...
TMenuItemN MenuItemN;
TMenuItem *Menu[] =
{
&MenuItem1,
&MenuItem1,
...
&MenuItemN,
}
Теперь в соответствии с событиями, получаемыми от кнопок, выполняете действия над объектами (тут для простоты использую частью псевдокод):
Код
byte index;
if( RIGHT )
{
Menu[++index]->draw(); // проверка перехода границы массива для простоты опущена
}
else if( LEFT )
{
Menu[--index]->draw(); // проверка перехода границы массива для простоты опущена
}
else if ( UP )
{
Menu[index]->change(1);
}
else if ( DOWN )
{
Menu[index]->change(-1);
}
Т.е. тут события LEFT/RIGHT задают перемещение по пунктам меню, UP/DOWN - изменение значения пункта. Конечно, это все кратко, для иллюстрации только. На практике, обычно, все сложнее - все упирается в конкретную организацию меню и требуемую функциональность. Но схема построения будет та же и она, как видно, достаточно проста.
В каждом случае будут вызываться разные функции draw и change - для каждого объекта своя. Для всех пунктов меню общим является то, что они являются пунктами меню и то, что с ними можно делать - а именно: отображать и изменять. Но уже сами эти фукнции (отображение и изменение) для каждого пункта разные. Все это реализуется на основе полиморфизма (поведение, получаемое с помощью виртуальных фукнций), что вышеприведенный пример и иллюстрирует.
Тут вы можете теперь добавлять сколько угодно пунктов меню, все они будут обрабатываться этим кодом. Если нужны еще какие-то функции, завязанные на другие события от кнопок (или другого источника входной информации), то добавляете их и пишете код, который их вызывает (по аналогии). Но уже не запутаетесь в этом разнообразии пунктов меню - все будет четко и единообразно.
Вообще, наверное, GUI - одна из самых подходящих областей для применения ООП, где преимущества ООП перед процедурным программированием являются просто гиганскими.

Что касается конкретно ОС, то вот этот код обработки пунктов меню имеет смысл поместить в один процесс (как правило, низкоприоритетный), который получает сообщения от источников входной информации - кнопок и др. Процесс висит в саспенде, ждет сообщения. Получил сообщение, проснулся, обработал его, упал в ожидание следующего.