Отладка приложений в Lazarus
- |
- Post By : sergey
- |
- Опубликовано : 10 декабря 2024
Отладка — важнейший этап разработки программного обеспечения. В процессе создания приложений на языках программирования, особенно на Pascal с использованием среды Lazarus, разработчикам необходимо уметь находить и устранять ошибки. Lazarus предоставляет мощные инструменты для отладки, которые облегчают эту задачу. В этой статье я покажу на примерах основные аспекты отладки приложений в Lazarus. Также рассмотрим советы для повышения эффективности этого процесса.
Основные инструменты отладки Lazarus
В Lazarus есть несколько инструментов, которые помогают в процессе отладки:
- Встроенный отладчик, который позволяет устанавливать точки останова, просматривать значения переменных и контролировать выполнение программы.
- Вывод информации: Возможность использования метода
writeln
,ShowMessage
или ведения журналов для отслеживания состояния программы. - Просмотр переменных: Отладчик позволяет видеть значение переменных во время выполнения, что помогает находить ошибки и их причины.
Подготовка тестового приложения
Давайте подготовим приложение, на котором мы сможем посмотреть, как работает отладчик. Пусть это приложение калькулятор. Конечно, это будет не полноценный калькулятор с вводом любых выражений. Наша цель скорее посмотреть на возможности отладки, поэтому мы добавим на форму два текстовых поля ввода, разместим 4 кнопки: плюс, минус, умножить, разделить, — и добавим метку для вывода результата(рисунок 1).
Перед тем, как начать писать код непосредственно для кнопок-действий, давайте добавим 3 вспомогательных метода (две функции и процедуру), для работы с компонентами формы. Объявим их в секции private нашего класса формы. Полный листинг модуля с добавленными функциями и процедурой приведен ниже.
unit umain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, uPSComponent; type { TForm1 } TForm1 = class(TForm) btPlus: TButton; btMinus: TButton; btMult: TButton; btDiv: TButton; Edit1: TEdit; Edit2: TEdit; Label1: TLabel; lbResult: TLabel; private function arg1: Double; function arg2: Double; procedure OutActionResult(sAction:string;resultValue:Double); public end; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } function TForm1.arg1: Double; begin result:=StrToFloat(Edit1.Text); end; function TForm1.arg2: Double; begin result:=StrToFloat(Edit2.Text); end; procedure TForm1.OutActionResult(sAction: string; resultValue: Double); begin lbResult.Caption := Edit1.Text+' '+sAction+' '+Edit2.Text+' = '+FloatToStr(resultValue); end; end.
Функция arg1 будет возвращать нам значение из текстового поля Edit1, аналогично arg2 будет возвращать значение из Edit2. Процедура OutActionResult будет выводить результат в метку lbResult. Таким образом, при написании кода кнопок нам уже не нужно будет обращаться к компонентам формы напрямую. Мы будем использовать подготовленные для этого методы.
Теперь добавим код для каждой из кнопок. Каждая кнопка должна выполнять действия над числами, которые пользователь введет в Edit1 и Edit2. Добавление обработчика для конкретной кнопки происходит при двойном клике по этой кнопке.
procedure TForm1.btPlusClick(Sender: TObject); begin OutActionResult('+',arg1+arg2); end; procedure TForm1.btMinusClick(Sender: TObject); begin OutActionResult('-',arg1-arg2); end; procedure TForm1.btMultClick(Sender: TObject); begin OutActionResult('x',arg1*arg2); end; procedure TForm1.btDivClick(Sender: TObject); begin OutActionResult(':',arg1/arg2); end;
Как видите, благодаря зараннее подготовленным функциям, код методов выглядит достаточно лаконично. Запустим приложение, введем числовые значения в текстовые поля и убедимся, что программа работает (Рисунок 2).
Приступаем к отладке
Теперь давайте попробуем в одно из полей ввода вписать не число, а строку. При попытке выполнить какое-либо действие (например +), мы сразу получим ошибку, которая показана на рисунке 3.
Как определить, в каком месте в нашем коде эта ошибка происходит? Давайте закроем режим выполнения проекта и вернемся в режим разработки. Ошибка у нас возникла, когда мы нажали на кнопку «+» (на самом деле она возникнет при нажатии на любое из действий, если мы ввели не число). Откроем обработчик кнопки «+» и поставим там точку останова: для этого нужно кликнуть мышью по левой (серой) части редактора кода, расположенной за вертикальной шкалой нумерации строк (см. рисунок 4). При этом на месте клика должна появиться красная точка, а строка, на которую установлена точка останова подсвечивается красным.
После установки точки останова снова запустим наше приложение, введем вместо первого числа какую-то строку и нажмем кнопку «+». Теперь наше приложение остановит выполнение на точке останова, которую мы установили, а мы сможем продолжить это выполнение пошагово в отладчике (Рисунок 5).
Находясь на этапе, который показан на рисунке 5, нажмите на кнопку F7 (на клавиатуре). Мы «проваливаемся» сначала в функцию arg1. Находясь в функции arg1, нажмите кнопку F8 несколько раз, пока не появится ошибка. Ошибка возникает на строке «result:=StrToFloat(Edit1.Text);» (в моем коде на рисунке 5, это 45-я строка). Теперь мы точно знаем, где ошибка и понимаем, что функция StrToFloat не может правильно преобразовать передаваемое в нее значение. Для того чтобы поймать и обработать исключение, в синтксисе FreePascal существует конструкция «try … except». Ниже приведен измененный код функции arg1.
function TForm1.arg1: Double; begin try result:=StrToFloat(Edit1.Text); except result:=0; end; end;
Теперь функция arg1 возвращает число из Edit1, но если введенные данные не удается преобразовать в число, то arg1 вернет 0 и дальнейший расчет корректно отработает, ошибка не возникнет. Не трудно догадаться, что такой же перехват ошибки нужно добавить и в функцию arg2. Результат работы программы с обработанной ошибкой показан на рисунке 6.
Полезные горячие клавиши для отладки
- F7 — шаг со входом в процедуру/функцию
- F8 — шаг в обход (будет выполнена строка полностью, на которой стоит курсор выполнения
- Shift+F8 — шаг с выходом из процедуры/функции
В этой статье мы немного познакомились с процессом отладки. Обычно на практике всё гораздо проще. Главное начать. Кстати, в рассмотренной нами программе осталась еще по крайней мере одна необработанная ситуация. Попробуйте найти ее и описать в комментариях к этой статье, а также обработать ее самостоятельно. Ниже привожу итоговый листинг главного модуля программы.
unit umain; {$mode objfpc}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, uPSComponent; type { TForm1 } TForm1 = class(TForm) btPlus: TButton; btMinus: TButton; btMult: TButton; btDiv: TButton; Edit1: TEdit; Edit2: TEdit; Label1: TLabel; lbResult: TLabel; procedure btDivClick(Sender: TObject); procedure btMinusClick(Sender: TObject); procedure btMultClick(Sender: TObject); procedure btPlusClick(Sender: TObject); private function arg1: Double; function arg2: Double; procedure OutActionResult(sAction:string;resultValue:Double); public end; var Form1: TForm1; implementation {$R *.lfm} { TForm1 } function TForm1.arg1: Double; begin try result:=StrToFloat(Edit1.Text); except result:=0; end; end; function TForm1.arg2: Double; begin try result:=StrToFloat(Edit2.Text); except result:=0; end; end; procedure TForm1.OutActionResult(sAction: string; resultValue: Double); begin lbResult.Caption := Edit1.Text+' '+sAction+' '+Edit2.Text+' = '+FloatToStr(resultValue); end; procedure TForm1.btPlusClick(Sender: TObject); begin OutActionResult('+',arg1+arg2); end; procedure TForm1.btMinusClick(Sender: TObject); begin OutActionResult('-',arg1-arg2); end; procedure TForm1.btMultClick(Sender: TObject); begin OutActionResult('x',arg1*arg2); end; procedure TForm1.btDivClick(Sender: TObject); begin OutActionResult(':',arg1/arg2); end; end.