#delphi #exception
#delphi #исключение
Вопрос:
У меня есть приложение, которое при запуске дома работает нормально, однако при запуске на школьных компьютерах (Windows XP) я получаю следующее сообщение. (Это перекомпиляция, а не просто запуск .exe)- В Delphi 2005
Исключение первой случайности в $ 7C81EB33. EAccessViolation класса исключений с сообщением «Нарушение доступа по адресу 0045E5E2 в модуле»Project2.exe ‘. Считывание адреса 00000198’. Процесс Project2.exe (440)
Код: игнорирование ненужного материала.
Image1: TImage; // Image(all the way to 72)
Timer1: TTimer; Timer2: TTimer;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure SomeOtherProcedure(Sender: TImage);
procedure Timer1Timer(Sender: TObject);
procedure Timer2Timer(Sender: TObject);
private
{ private declarations }
public
{ public declarations }
end;
var
Form1: TForm1;
left : integer;
top : integer;
gap : integer;
type
coordinates = record
row : integer ;
col : integer;
end;
var
picarray : array[0..5,0..5] of timage;
thiscover, midcover, lastcover : timage;
imageindex : array[0..5,0..5] of integer;
picloc: array[0..3] of coordinates;
clickcount, pairsfound, attemptcount : integer;
implementation
{$R *.lfm}
procedure initialise();
var
i, j, whichcol, whichrow : integer;
begin
for i := 0 to 5 do
for j := 0 to 5 do
imageindex[i,j] := -1; // not used
randomize;
for i := 0 to 11 do
for j := 1 to 3 do
begin
repeat
begin
whichcol := random(6) ;
whichrow := random(6) ;
end;
until imageindex[whichcol, whichrow] = -1;
picarray[whichcol, whichrow].Picture.LoadFromFile('C:UsersHaydenPictures' inttostr(I 1) '.jpg');
imageindex[whichcol, whichrow] := I ;
end;
clickcount := 0 ; //
pairsfound := 0 ;
attemptcount := 0 ;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
cpic : tcomponent;
whichcol: integer;
whichrow : integer;
begin
gap := image2.left - image1.left;
top := image1.Top;
left := image1.left;
for cpic in form1 do
begin
if (cpic.ClassType = timage) and (cpic.Tag = 10) then
begin
whichcol := (timage(cpic).left - left) div gap;
whichrow := (timage(cpic).Top - top) div gap;
picarray[whichcol, whichrow] := timage(cpic) ;
end;
end;
initialise;
end;
Строка >>> picarray[whichcol, whichrow].Рисунок.Загрузка из файла(‘C:UsersHaydenPictures ‘ inttostr(I 1) ‘.jpg’);
похоже, это вызывает ошибку. И если это ошибка кодирования, каков правильный способ сделать это?
Ответ №1:
Сначала я собираюсь немного почистить ваш код, потому что в его нынешнем виде очень сложно понять, что происходит. Я настоятельно рекомендую вам выработать привычку уделять несколько минут тому, чтобы ваш код был четко отформатирован — это сэкономит вам часы отладки.
Я применил только следующие простые изменения: отступ, пустые строки и широкое использование begin .. end;
var
picarray : array[0..5,0..5] of timage;
thiscover, midcover, lastcover : timage;
imageindex : array[0..5,0..5] of integer;
picloc: array[0..3] of coordinates;
clickcount, pairsfound, attemptcount : integer;
implementation
{$R *.lfm}
procedure initialise();
var
i, j, whichcol, whichrow : integer;
begin
for i := 0 to 5 do
begin
for j := 0 to 5 do
begin
//It's clear you're initialising the 36 entries of imageindex to -1
imageindex[i,j] := -1; // not used
end;
end;
randomize;
for i := 0 to 11 do
begin
for j := 1 to 3 do
begin
//This loop also runs 36 times, so it fills the whole of imageindex with new values
//It also loads all 36 entries of picarray with an image specfied by the current value of i
//The approach is dangerous because it depends on the 'loop sizes' matching,
//there are much safer ways of doing this, but it works
repeat
begin //This being one of the only 2 begin..end's you provided inside this is routine is pointless because repeat..until implies it.
whichcol := random(6) ;
whichrow := random(6) ;
end;
until imageindex[whichcol, whichrow] = -1;
//This line itself will throw an access violation if picarray[whichcol, whichrow] doesn't
//contain a valid TImage instance... we have to check other code to confirm that possibility
picarray[whichcol, whichrow].Picture.LoadFromFile('C:UsersHaydenPictures' inttostr(I 1) '.jpg');
imageindex[whichcol, whichrow] := I ;
end;
end;
clickcount := 0 ; //
pairsfound := 0 ;
attemptcount := 0 ;
end;
Переходим к следующему фрагменту кода:
procedure TForm1.FormCreate(Sender: TObject);
var
cpic : tcomponent;
whichcol: integer;
whichrow : integer;
begin
gap := image2.left - image1.left;
top := image1.Top;
left := image1.left;
for cpic in form1 do
begin
//This loop attempts to assign existing TImage instances to picarray
//However, the way you're going about it is extremely dangerous and unreliable.
//You're trying to use the position of a component on the form to determine its
//position in the array.
//There are many things that could go wrong here, but since this seems to be a
//homework excercise, I'll just point you in the right direction - you need
//to debug this code.
if (cpic.ClassType = timage) and (cpic.Tag = 10) then
begin
whichcol := (timage(cpic).left - left) div gap;
whichrow := (timage(cpic).Top - top) div gap;
picarray[whichcol, whichrow] := timage(cpic) ;
end;
end;
//Here you call initialise, which as I said before, will
//cause an Access Violation if picarray is not correctly 'set up'
//The previous code in this method certainly has a bug which is
//preventing one or more picarray entries from being assigned a
//valid TImage instance.
//You could write a simple for I := 0 to 5, for J := 0 to 5 loop
//here to check each of picarray entries and pinpoint which is
//incorrect to aid your debugging of the pevious loop.
initialise;
end;
Комментарии:
1. Вау, это было очень проницательно. Я скажу, что у меня не очень большой опыт работы с Delphi, и мне это не очень нравится. Но я хочу попробовать и продолжать в том же духе, пока не пойму все правильно. Спасибо, вы действительно приложили некоторые усилия.
2. @Skeela87 — просто из любопытства (больше ничего): почему вам не нравится Delphi? можете ли вы привести несколько наглядных примеров? возможно, вы привыкли к управляемым языкам?
Ответ №2:
Критическим разделом является инициализация picarray
. Вы не можете быть уверены, что каждому элементу массива присвоен компонент TImage. Если хотя бы одно изображение имеет неправильное left
или top
у вас двойное присвоение одному элементу, а другому оставлено значение nil. Это приведет к нарушению доступа при первом использовании, например, в picarray[whichcol, whichrow].Picture.LoadFromFile
.
Я бы рекомендовал переработать инициализацию picarray с помощью циклов for для каждого измерения. Чтобы получить правильное время, я бы назвал их как ‘Image_2_3’ и получил экземпляры в цикле по имени.
Ответ №3:
вы можете проверить, существует ли файл, и попытаться перехватить исключение, чтобы отобразить значимое сообщение
try
if FileExists('C:UsersHaydenPictures' inttostr(I 1) '.jpg') then
picarray[whichcol, whichrow].Picture.LoadFromFile('C:UsersHaydenPictures' inttostr(I 1) '.jpg');
else
ShowMessage("File not found");
except
on E : Exception do
ShowMessage(E.ClassName ' error raised, with message : ' E.Message);
end;
Комментарии:
1. Спасибо за ответ, но файл действительно существовал, обычно это все равно приводит к ошибке «файл не найден».
2. это правда, но try-catch предназначен для всех ошибок, а не только для ‘файл не найден’ .. E. Сообщение может быть полезным, помогало мне много раз.
3. Хорошо, я должен буду проверить завтра. Я вернусь к отчету здесь. Спасибо
4. Джордж, перехват исключения и отображение сообщения полезны только в том случае, если вы уже выпустили программное обеспечение для пользователей и не можете воспроизвести проблему локально (и даже тогда это не так хорошо, как использование реальной библиотеки исключений, такой как EurekaLog или MadExcept). В этом случае мы уже знаем, какая строка вызвала исключение, какой класс исключений был выдан и каково было его сообщение. Предложенный вами код не добавит никакой информации к расследованию.
5. На самом деле, такой стиль отлова исключения очень, очень плох ! 1) Ничего не делая (предполагая, что обработчик исключений приложения по умолчанию), в любом случае появляется сообщение. 2) Разница в том, что вы больше не находитесь в состоянии исключения, поэтому теперь, сообщив пользователю о проблеме, вы больше не сообщаете об этом остальной части программы. Что приводит к крайне неприятному потенциалу повторных ошибок в дальнейшем.