Эта глава содержит несколько дополнительных предложений о том, как использовать Turbo Vision более эффективно. Поскольку объектно-ориентированное программирование и программирование, управляемое событиями - это новая концепция даже для опытных программистов, мы попробуем предоставить некоторые советы по использованию новых парадигм.Отладка программ на Turbo Vision.
Если Вы попытаетесь трассировать какой-нибудь из примеров этого руководства, Вы, вероятно, заметите, что Вы не можете зайти очень далеко. Поскольку программы на Turbo Vision управляются событиями, большая часть программного времени тратится на цикл в TGroup.Execute ожидая когда произойдет какое-либо событие. В результате трассировка этой точки имеет мало смысла. Примечание: Ключем к отладке программ на Turbo Vision являются точки прерывания и только точки прерывания. Давайте посмотрим как лучше разместить точки прерывания, чтобы обнаружить проблемы в программе на Turbo Vision.Это здесь не получить.
Одна из проблем при отладке Вашей программы может заключаться в том, что какая-то часть Вашего кода не будет выполняться. Например, Вы можете отметить элемент строки статуса или выбрать опцию меню, которая должна вызвать окно, но этого не происходит. Обычно Вы пошагово проходите программу до тех пор, пока не дойдете до этой команды, а затем смотрите что происходит вместо того что должно происходить. Но если Вы попробуете сделать это, это Вам не поможет. Когда Вы сделаете следующий шаг, Вы вернетесь обратно в то место, где Вы были. Лучший подход в этой ситуации - установить точку прерывания в метод HandleEvent, который должен вызывать код не получающий управления. Установите точку прерывания в начале метода HandleEvent и когда программа остановится в нем, проверьте запись события, чтобы убедиться, что это именно то событие, которое Вы ожидали. Вы так же можете выполнить трассировку с этой точки, поскольку HandleEvent и код, откликающийся на Ваши команды, - это тот код, который Вы написали, и следовательно Вы можете его оттрассировать.Проверьте маску.
Запомните, что существуют причины, по которым Ваш объект может никогда не увидеть событие, которое Вы хотите ему передать. Первая и простейшая ошибка - это неустановленный тип события в маске событий Вашего объекта. Если Вы не сказали своему объекту, что ему разрешено обработать определенный вид события, он даже не увидит этих событий!Украденные события.
Вторая возможность, которую необходимо рассмотреть - это то, что другой объект мог "украсть" событие. Т.е. событие обработано и очищено не тем объектом, которому Вы намеревались передать событие. Это может происходить по нескольким причинам. Первая - это дублирование объявлений команд: если две команды назначены одному константному значению, они могут обрабатываться взаимозаменяемо. Вот почему необходимо отследивать, каким константам назначаются какие значения, особенно в ситуации, когда Вы повторно используете код модулей. Вторая возможная причина в дублировании меток команд, особенно при повторном использовании кода. Так, если Вы назначаете команду cmJump и существует метод HandleEvent в каком-то другом объекте, который уже откликается на команду cmJump и о котором Вы забыли, это может привести к конфликтам. Всегда просматривайте не используют ли другие объекты события, которые кажутся "потерянными".Вина Ваших предков.
Наконец убедитесь, что событие не было обработано в вызове предка объекта. Часто метод HandleEvent порожденного типа вызывает обработчик событий его предка для обработки большинства событий, который может неожиданно обработать одно из событий. Попытайтесь перехватить событие до вызова HandleEvent предка.Делается не то, что ожидалось.
Предположим, Ваше окно отображается, но выводит грязь или что- то отличное от того, что Вы ожидали. Это указывает на то, что событие обработано правильно, но код, который откликается на событие некорректен или перекрыт. В этом случае лучше всего установить точку прерывания в программе, которая вызывается при этом событии. После прерывания выполнения Вы можете трассировать Ваш код.Зависания.
Ошибки, приводящие к зависаниям, наиболее трудно отслеживать, но они могут быть найдены. Для начала Вы можете попробовать комбинацию точек прерывания, предложенную ранее для локализации места, в котором происходит зависание. Затем посмотрите, не освобождаются ли указатели дважды. Это может произойти когда видимый элемент освобождается своим владельцем, а затем Вы пытаетесь освободить его напрямую. Например: { Этот код приводит к зависанию системы } var Bruce, Pizza: PGroup; R: TRect; begin R.Assign(5, 5, 10, 20); Pizza := New(PGroup, Init(R)); R.Assign(10, 10, 20, 20); Bruce := New(PGroup, Init(R)); Bruce^.Insert(Pizza); Dispose(Bruce, Done); Dispose(Pizza, Done); end; Освобождение группы Bruce так же освобождает подэлементы Pizza. Если Вы попытаетесь освободить Pizza, Ваша программа зависнет. К зависанию может так же приводить чтение данных потока в ошибочный тип объекта и некорректное приведение типа данных из коллекций.Встраивание программ в Turbo Vision.
Если Вы хотите встроить существующую программу в Turbo Vision, Вы можете попытаться встроить интерфейс Turbo Vision в программу или поместить слой Turbo Vision над Вашей программой. Это будет неудачная попытка. Программы Turbo Vision управляются событиями и большинство существующих программ будет не просто (если вообще возможно) преобразовать к этой парадигме.Удаление "мусора" из старого кода.
Есть простой путь. Сейчас Вы знаете, что сущность программирования отдельной программы на Turbo Vision сконцентрирована в методах Init, Draw и HandleEvent программы. Наилучший подход к встраиванию существующей программы - это вначале написать интерфейс Turbo Vision, который заменит существующий, а затем выбрать необходимый код из старой программы. Большинство этого кода попадет в методы Init, Draw и HandleEvent новых видимых элементов. Вам потребуется определенное время, чтобы осмыслить сущность Вашей программы так, чтобы Вы могли отделить код интерфейса от кода, выполняющего работу Вашей программы. Это может быть непросто, поскольку Вы привыкли представлять программу по-другому. Работа по переносу будет включать определенное переписывание для того, чтобы научить новые объекты представлять самих себя, а так же приведет к отбрасыванию большого количества старого интерфейсного кода. Это не должно приводить к новым ошибкам и Вы будете делать это с удовольствием. Если Вы переносите программу, Вы будете удивлены, обнаружив как много кода предназначено для управления пользовательским интерфейсом. Когда Вы позволите Turbo Vision работать за Вас, большая часть работы пользовательского интерфейса, которую Вы делали раньше, просто исчезнет. Мы обнаружили это, когда переносили интегрированную среду Turbo Pascal в Turbo Vision. Мы освободили компилятор, редактор и отладчик от старого пользовательского интерфейса и перенесли их в пользовательский интерфейс, написанный на Turbo Vision.Переосмысление проекта.
В традиционном программировании мы думали о программе с точки зрения кода. Теперь мы можем попытаться организовать программу так же, как интегрированная среда Turbo Pascal окружает объект редактора. Большую часть времени в интегрированной среде Вы тратите на редактирование. Редактор будет редактировать, а в промежутках от вызывает компилятор. Но требуется изменить перспективу, чтобы правильно использовать мощь ООП. Имеет смысл в случае интегрированной среды сделать саму программу объектом. Когда необходимо редактировать, программа вызывает редактор. Когда необходимо компилировать, программа вызывает компилятор, инициализируя его и говоря какие файлы компилировать. Если компилятор встретил ошибку как пользователь вернется на точку ошибки в исходном коде? Программа вызывает компилятор и получает результат от него. Если компилятор возвращает ошибочный результат, он так же возвращает имя файла и номер строки. Программа смотрит, открыт ли редактор для этого файла, и если нет - открывает его. Он передает информацию об ошибке, включая номер строки в редактор и конструирует строку сообщения об ошибке для редактора.Использование побитовых полей.
Видимые элементы Turbo Vision используют поля с побитовым отображением. Т.е. они используют отдельные биты байта или слова для указания различных свойств. Отдельные биты обычно называются флагами, поскольку они устанавливаются (1) или очищаются (0), указывая, является ли данное свойство активным. Например, каждый видимый элемент имеет поле Options типа слово. Каждый отдельный бит слова имеет различное значение в Turbo Vision.Значения флагов.
В диаграмме, описывающей биты поля Options (рис.4.14 главы 4) msb указывает старший бит, а lsb указывает младший бит. Так например 4-ый бит называется ofFramed. Если бит ofFramed установлен в 1, это означает, что видимый элемент имеет видимую рамку. Если бит равен 0, видимый элемент не имеет рамки. Обычно Вас не интересуют значения флагов, если Вы не собираетесь определить свои и даже в этом случае Вас будет интересовать только то, чтобы Ваши определения были уникальными. Например, 6 старших бит в слове Options не определены в Turbo Vision. Вы можете определить любой из них с необходимым Вам смыслом.Битовые маски.
Маска - это просто удобный способ обработки группы флагов вместе. Например, Turbo Vision определяет маски для различных видов событий. Маска evMouse просто содержит все 4 бита, устанавливаемые для различных видов событий от мышки. Поэтому если видимому элементу необходимо проверить событие от мышки, он может сравнить тип события с маской вместо того, чтобы проверять каждый из видов событий от мышки.Побитовые операции.
Turbo Pascal предоставляет ряд полезных операций для манипуляции битами. Вместо детального объяснения каждой из операций, этот раздел просто говорит что Вы должны сделать, чтобы выполнить работу.Установить бит.
Чтобы установить бит используйте оператор or. Например, чтобы установить бит ofPostProcess в поле Options для кнопки MyButton используйте: MyButton.Options := MyButton.Options or ofPostProcess; Вы можете использовать сложение для установки битов, только если Вы абсолютно уверены что делаете. Например, если вместо предыдущего кода Вы используете MyButton.Options := MyButton.Options + ofPostProcess; Ваша операция будет работать если и только если бит ofPostProcess не был установлен. Если бит уже был установлен, двоичное сложение приведен к переносу в следующий бит (ofBuffered), устанавливая или очищая в зависимости от его значения. Другими словами: прибавление битов может привести к неожиданным эффектам. Вместо этого используйте операцию or. Заметим, что Вы можете установить несколько бит в одной операции. Следующий код будет устанавливать 2 различных флага: MyScroller.GrowMode := MyScroller.GrowMode or (gfGrowHiX + gfGrowHiY);Очистить бит.
Очистить бит так же просто, как и установить. Вы просто используете другую операцию. Лучший способ сделать это - использовать комбинацию двух побитовых операций and и not. Например, чтобы очистить бит dmLimitLoX в поле DragMode метки АLabel используйте ALabel.DragMode := ALabel.DragMode and not dmLimitLoX; Как и при установке Вы можете очистить несколько бит в одной операции.Проверить биты.
Часто необходимо проверить, установлен ли определенный флаг. При этом используется операция and. Например, для того, чтобы проверить, может ли окно AWindow быть размещенным черепицей на панели экрана, проверьте флаг ofTileable: if AWindow.Options and ofTileable = ofTileable then .Использование масок.
Так же, как при проверке отдельных бит, Вы можете использовать and для проверки, установлен ли один или более битов маски. Например, для того, чтобы посмотреть, содержит ли запись события событие от мышки, Вы можете проверить: if Event.What and evMouse <> 0 then .Итоги.
Следующий список содержит все побитовые операции: Установить бит: field := field or flag; Очистить бит: field := field and not flag; Проверить, установлен ли флаг: if field and flag = flag then . Проверить, установлен ли флаг в маске: if flag and mask <> 0 then .
Назад | Содержание | Вперед