Помощь - Поиск - Пользователи - Календарь
Полная версия: Вызов события
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
Cheburashka
В общем я хочу чтобы у меня после какого-то действия вызывалась процедура OnDrawCell для StringGrid'a.
procedure TForm1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);

Подскажите пожалуйста как можно эту процедуру вызвать из какого-либо участка кода?
Unconnected
Ну так и вызываешь, form1.StringGrid1DrawCell(Sender: TObject; ACol, ARow: Integer; Rect: TRect; State: TGridDrawState);
Cheburashka
Так ему Sender не нравится...
Пишет следующее
Цитата(Delphi)
[Error] Unit1.pas(79): Undeclared identifier: 'Sender'
volvo
Цитата
я хочу чтобы у меня после какого-то действия вызывалась процедура OnDrawCell для StringGrid'a.
Налицо ошибка проектирования. Событие не должно вызываться, оно должно происходить. Как только событие произойдет - будет вызван и обработчик события.

Можно посмотреть код, зачем тебе понадобилось вызывать OnDrawCell вручную? А если в это время ячейка, для которой будет вызван OnDrawCell, невидима (не находится на экране, а прокручена, например, вверх)?
Cheburashka
Что касается видимости ячеек, то этого у меня не произойдет. Поле небольшое и всё размещено на форме под нужные размеры.
Я просто хочу сделать так, чтобы у меня сначала нарисовались в каких-либо ячейках изображения. А потом также продолжать их рисовать при определенных действиях.
Как я понял OnDrawCell для этого лучше не использовать? И можно ли каким-либо другим способом рисовать в ячейках StringGrid?
  For i := 1 to 5 do begin
XR := Random (9);
YR := Random (9);
BallR := Random (7);
While Field [XR, YR] = 1 do begin
XR := Random (9);
YR := Random (9);
end;
Field [XR, YR] := 1;
Rect := Form1.StringGrid1.CellRect(XR, YR);
Case BallR of
0 : Form1.StringGrid1.Canvas.Brush.Bitmap := Pink;
1 : Form1.StringGrid1.Canvas.Brush.Bitmap := Green;
2 : Form1.StringGrid1.Canvas.Brush.Bitmap := Yellow;
3 : Form1.StringGrid1.Canvas.Brush.Bitmap := Red;
4 : Form1.StringGrid1.Canvas.Brush.Bitmap := Blue;
5 : Form1.StringGrid1.Canvas.Brush.Bitmap := LightBlue;
6 : Form1.StringGrid1.Canvas.Brush.Bitmap := Brown;
end;
form1.StringGrid1DrawCell(Sender: TObject; XR, YR: Integer; Rect: TRect; State: TGridDrawState);
end;
volvo
Цитата
Как я понял OnDrawCell для этого лучше не использовать? И можно ли каким-либо другим способом рисовать в ячейках StringGrid?
Похоже, ты не понимаешь основ событийного программирования.

Смотри: для того, чтобы рисовать в ячейке Грида, нужно определить обработчик события OnDrawCell. Но вот когда это событие произойдет - не от тебя зависит. Оно произойдет тогда, когда система должна будет перерисовать ячейку. То есть, провел ты над своей программой окно блокнота, когда твое окно снова стало видимым - ячейки должны перерисоваться. Тогда происходит событие, которое вызывает обработчик, написанный тобой. Понимаешь? Не ты вызываешь что-то, а операционная система, зная, что участок окна был невидимым, а потом опять стал видимым, решает: "чтобы не потерять содержимое окна, надо его перерисовать", и делает то, что нужно для этого. Среди прочих действий системы вызывается и определенное тобой в OnDrawCell действие.

То есть, для того, чтобы инициировать перерисовку ячеек, тебе надо действовать другими методами, а не прямым вызовом обработчика OnDrawCell...

Еще раз: Что именно ты хочешь рисовать, и при каких именно (слово "определенных" меня не устраивает, чтобы дать тебе ответ, я просто не смогу ничего посоветовать) условиях ячейки должны перерисовываться, и как именно перерисовываться?
Cheburashka
Хорошо объясню ситуацию по конкретнее. Спасибо что рассказали про OnDrawCell, просто в интернете мало информации про это и у меня сложилось не правильное мнение о событие.

Когда-то я писал, что делаю небольшую игру.
В общем для начала мне нужно вывести несколько изображений в СтрингГрид - это при начальных условиях. А потом после выделения ячейки с изображением передвинуть его в свободное место. После этого действия может произойти две вещи:
1) Добавятся новые изображения на поле (рандом).
2) Часть изображений исчезнут.

Как мне лучше это осуществить?
volvo
Цитата
Как мне лучше это осуществить?
Не использовать StringGrid для работы с изображениями - это во-первых.

Я бы сделал проще: сгенерировал бы (автоматически, разумеется, тебе же известны размеры изображений, раз у тебя "всё размещено на форме под нужные размеры") нужное количество панелей (TPanel), на каждую из которых опять же автоматически положил бы TImage. Вот и все, собственно. TImage приспособлен для работы с изображениями, вот и пусть работает. В любую секунду можно обратиться к любому изображению напрямую, и перенести его с одного места в другое. И не надо извращаться с событиями...
Cheburashka
Вы везде употребляете слово "автоматически". А как это сделать? Просто опыта пока, что маловато smile.gif
Unconnected
Ну наверное имелось в виду при запуске программы создать нужное количество панелей и на них закинуть картинки. Если количество картинок заранее известно, можешь создать панели при проектировании вручную, если неизвестно - динамически.
volvo
Когда я говорю "автоматически" - подразумевается, конечно, "во время работы программы". То есть, я не стал бы бросать все эти панели и изображения в режиме редактирования формы, потом с ними замучаешься разбираться, что где. А сделал бы вот так:

Тут код (Показать/Скрыть)


Вот чего получается на форме после того, как я сначала нажал кнопку "Создать", а потом - "Изменить":
Нажмите для просмотра прикрепленного файла

К тому же, как ты заметил я показал еще и как обрабатывать клик по панельке (или по изображению), если понадобится...

По-моему, этот способ гораздо проще, чем кидать компоненты на форму, выравнивать их, да еще и запоминать, какой компонент как называется, или пользоваться неподходящими компонентами типа StringGrid-а.

Добавлено через 3 мин.
Цитата
Если количество картинок заранее известно, можешь создать панели при проектировании вручную
И ты туда же... Ну, брошу я эти 100 картинок вручную. А как потом к ним обращаться? Мне вот надо перенести первую картинку во втором ряду на 4 ряда ниже. Я что, должен помнить, как пронумерованы картинки? А оно мне надо, если можно обращаться к любому изображению, как к обычному элементу массива?
Cheburashka
Действительно, оказывается всё настолько просто smile.gif Спасибо за код, но у меня есть ещё пара вопросов по данному коду.
Во-первых, что такое SetLength? И для чего он нужен?
  img := (ArrPanels[2, 2].Components[0] as TImage);
if img <> nil then img.Picture := nil;

Зачем мы пишем Components[0]? И что мы делаем во второй строке?
И ещё, вот в процедурах myPanelClick и myImageClick, что мы в них делаем?
В myPanelClick, как я понял, мы меняем рамку панели, или я не прав?
Client
Цитата
И ещё, вот в процедурах myPanelClick и myImageClick, что мы в них делаем?
Думаю, что этот обработчик надо установить для всех форм и имеджей на щелчок
volvo
Цитата
Зачем мы пишем Components[0]?
Комментарии к коду читал? Там все написано.

А во второй строке - если у нас уже есть изображение в TImage, то перед тем, как заносить новую картинку, надо прежнюю-то удалить (для этого в img.Picture присваивается nil.)

Цитата
И ещё, вот в процедурах myPanelClick и myImageClick, что мы в них делаем?
Это пример того, как обрабатывать события. Если ты положил на форму панель, то там все просто, заходишь в список обработчиков, щелкаешь на нужный тебе, и вписываешь нужное действие. А если делаешь все во время выполнения? Как назначить обработчик? Выбрать-то не из чего, форма - пустая в дизайнере... Вот я и показал, как назначить обработку событий. Попробуй, запусти мой код и щелкни мышью на какой-нибудь картинке. Увидишь, что событие обработается...

Цитата
этот обработчик надо установить для всех форм и имеджей на щелчок
Не форм, а панелей.
Cheburashka
Спасибо!
Cheburashka
А вот еще один вопрос по поводу первых процедур - Допустим, я нажал на определенный компонент TImage, и как в этих процедурах узнать какие координаты имеет TImage (в массиве ArrPanels)?
volvo
Ну, например, написать вот такую вот функцию:

// В классе формы:
private
{ Private declarations }
function GetIndexes(AImage: TImage; var ALine, ACol: Integer): Boolean;

// ...

// Реализация: пробегаем по всей матрице Panel-ей, и проверяем
// хранящееся в каждой из них изображение (выше мы уже выяснили,
// что Image хранится в списке дочерних компонентов под нулевым номером)
// на равенство тому изображению, по которому щелкнули мышью.

// Если такое изображение найдено - немедленно возвращаем
// его координаты (Line/Col) и выходим. Если ни одно изображение
// не соответствует - функция вернет False, как признак неудачи.
function TForm1.GetIndexes(AImage: TImage;
var ALine, ACol: Integer): Boolean;
var i, j: integer;
begin
result := True;
for i := 0 to Length(arrPanels) - 1 do
for j := 0 to Length(arrPanels[0]) - 1 do
if (arrPanels[i, j].Components[0] as TImage) = AImage then
begin
ALine := i; ACol := j;
Exit;
end;
result := False;
end;

// Вызывать - вот так:
procedure TForm1.myImageClick(Sender: TObject);
var
myParent: TPanel;
Line, Col: integer;
begin
myParent := (Sender as TImage).Parent as TPanel;

// Вызываем функцию с учетом того, что может быть неудача - это нужно делать
// всегда, даже если тебе это кажется невероятным. Мало ли что может произойти,
// лучше добавить if ... then, чем потом сидеть и думать, где ошибка.

// Теперь о том, что передается первым параметром. Как известно, в обработчик
// OnClick передается указатель на тот объект, на котором произошел щелчок мышью.
// Соответственно, и в myImageClick тоже будет передан адрес того объекта (а точнее -
// того изображения), на котором пользователь щелкнул мышью. Вот именно потому, что
// я уверен: "Объект - это именно изображение, и ничего кроме него" (почему я уверен
// в этом - попробуй догадаться и рассказать мне), я и передаю в GetIndexes адрес
// объекта, приведенный к типу TImage... Что произойдет, если вдруг Sender будет
// другого типа - это тоже ты мне расскажешь, договорились?

if GetIndexes(Sender as TImage, Line, Col) then
Memo1.Lines.Add(Format('i = %d, j = %d', [Line, Col])); // Для теста - вывожу в мемо

myParent.OnClick(myParent);
end;

Читай комментарии внимательно. Там есть два вопроса для тебя smile.gif Я очень хотел бы, чтобы ты на них ответил. Это важно.
Cheburashka
А как сделать обмен таких изображений, зная координаты обоих TImage?

И как Sender может быть другого типа в данном случае? blink.gif Мы же ведь обращаемся конкретно по клику на изображение. И мне кажется, что он не может быть другим smile.gif
Client
Цитата
А как сделать обмен таких изображений, зная координаты обоих TImage?
А что ты делаешь если надо поменять 2 переменные целого типа? добавляешь 3 переменную того же типа и с ее помощью меняешь первые две. В данном случае - TImage smile.gif
Cheburashka
b1 := arrPanels[x,y].Components[0] as TImage;    
arrPanels[x,y].Components[0] as TImage := arrPanels[i, j].Components[0] as TImage;
arrPanels[i, j].Components[0] as TImage := b1;

пытался сделать что-то типа этого... не вышло в итоге smile.gif
Client
свойство Picture тоже поменяй
volvo
Цитата
пытался сделать что-то типа этого... не вышло в итоге
Этого недостаточно. Такой способ сработает только при простых типах (копирование Integer-ов, строк всяких). А Picture - это сложный тип, его надо копировать по-другому:

procedure TForm1.Button3Click(Sender: TObject);

// Чтоб не таскать за собой все время эту длинную строку - сокращаем:
function GetPic(i, j: integer): TPicture;
begin
result := (ArrPanels[i, j].Components[0] as TImage).Picture;
end;

// Это процедура копирования изображения из CopyFrom в CopyTo.
// При этом CopyFrom затирается...
procedure CopyPic(CopyTo: TPicture; CopyFrom: TPicture);
begin
CopyTo.Assign(CopyFrom);
CopyFrom := nil;
end;

var
Pic: TPicture;
begin
// А вот теперь - сам обмен, как и с целыми. Только сначала
// надо создать класс нужного типа, а потом его удалить. А так - все как и обычно...
Pic := TPicture.Create;
CopyPic(Pic, GetPic(4, 4));
CopyPic(GetPic(4, 4), GetPic(2, 2));
CopyPic(GetPic(2, 2), Pic);
Pic.Free;
end;



Цитата
И как Sender может быть другого типа в данном случае?
Не надо отвечать вопросом на вопрос. Я тебя спросил, почему Sender не может быть другого типа. И что будет, если это произойдет.
Cheburashka
volvo, в общем-то я затрудняюсь ответить на Ваши вопросы smile.gif
А за код спасибо smile.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.