Forum > Russian

Три вопроса новичка: OnPaint, ImageList и логика программы

(1/6) > >>

majolika:
Привет!
Имеется три новичковых вопроса о рисовании на контроле. Ради самообразования я пишу «сапёра».

Вопрос 1: OnPaint
Когда я нажимаю кнопку «старт», то показываю минное поле и заполняю его квадратами. Затем, когда я кликаю на минном поле и рисую мину. Но минное поле полностью перерисовывается, все квадраты — как ветром сдувает, и поверх рисуется мина, которая тоже исчезает при следующем клике.
Почему?

Вопрос 2: ImageList
ImageList — удобный контрол, но я обнаружил одну странную вещь: когда ярисую одну и ту же картинку при помощи ImageList и при помощи Canvas.Draw, это даёт разные результаты.
Почему?


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---ImageList1.Resolution[24].Draw(Bevel1.Canvas,  x, y, 0, True);
--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Field.Canvas.Draw(x, y, Picture_Loaded_From_TImage_Placed_On_The_Form);
На приаттаченной картинке показана разница минного поля:
фрагмент слева, более яркое минное поле — ImageList
фрагмент справа, более тёмное минное поле — Canvas.Draw

(просто на форму кидаю невидимый Timage, в Form.OnCreate подгружаю как TBitmap и рисую)
Пятой точкой чую, что собака зарыта в том, что TImage и TImageList как-то по-разному работают с загруженными изображениями, но, блин, где логика?!
«Изображение» и «список изображений» — исходя из названия, одно и то же, только в первом случае — в единственном экземпляре, во втором — в ассортименте, так сказать.

Вопрос 3: логика программы
Первый клик на кнопке «старт» работает отлично, а последующие — никак не работают.
Почему?

Ниже минимальный proof-of-concept код:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---unit test_unit1; {$mode objfpc}{$H+} interface uses  Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls; type   { TForm1 }   TForm1 = class(TForm)    Bevel1: TBevel;    Button1: TButton;    ImageList1: TImageList;    procedure Bevel1MouseUp(Sender: TObject; Button: TMouseButton;      Shift: TShiftState; X, Y: Integer);    procedure Bevel1Paint(Sender: TObject);    procedure Button1Click(Sender: TObject);  private   public   end; var  Form1: TForm1;  BoxSize: Integer = 24;  FieldRow: integer = 10;  FieldCol: integer = 10;  Button1Clicked: Boolean = False;  DrawABomb: Boolean = False;  CoordX, CoordY: Integer; implementation {$R *.lfm} { TForm1 } procedure TForm1.Button1Click(Sender: TObject);begin  Button1Clicked := True;  Bevel1.Width := FieldCol * BoxSize;  Bevel1.Height := FieldRow * BoxSize;  Bevel1.Show;end; procedure TForm1.Bevel1Paint(Sender: TObject);var  x, y: Integer;begin  if Button1Clicked then begin     for x := 0 to FieldCol - 1 do begin         for y := 0 to FieldRow - 1 do begin             ImageList1.Resolution[24].Draw(Bevel1.Canvas,             (x * BoxSize), (y * BoxSize), 0, True);         end;     end;     Button1Clicked := False;  end;  if DrawABomb then begin     ImageList1.Resolution[24].Draw(Bevel1.Canvas, CoordX, CoordY, 1, True);     DrawABomb := False;  end;end; procedure TForm1.Bevel1MouseUp(Sender: TObject; Button: TMouseButton;          Shift: TShiftState; X, Y: Integer);begin  if Button = mbLeft then begin     DrawABomb := True;     CoordX := X; CoordY := Y;     Bevel1.Repaint;  end;end; end. 

Seenkao:

--- Quote ---Но минное поле полностью перерисовывается, все квадраты — как ветром сдувает, и поверх рисуется мина, которая тоже исчезает при следующем клике.
--- End quote ---
При каждом клике, поле должно перерисовываться, это по сути правильно. Не хотите чтоб перерисовывалось поле, значит надо отрисовывать определённый квадрат (квадраты) который открыли. А это другая логика, отличная от той, что используете вы.

На вашу логику надо накладывать всё, что уже открыто.

majolika:
Спасибо, Seenkao!
Но мне уже помогли со всеми возникавшими вопросами в англоязычной части форума. Там всё несколько оживлённее, нежели тут, в русскоязычной разделе.
Я рисовал прямо на контроле, что в данном случае не очень-то правильно.
В общем, я уже почти со всем разобрался и почти завершил свою первую программу на Lazarus: вариацию Сапёра с элементами RPG. Сейчас навожу последние штрихи.

majolika:
Но с одной штукой я пока не разобрался. Может, у вас найдётся время помочь?

Я там рисую маленькую рукотворную анимацию при помощи таймера.
Конструкция базово такая:


--- Code: Pascal  [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---procedure StartAnimation;  AnimationFrame := 0;  Timer1.Enabled := True; procedure TForm1.Timer1Timer;  // рисуем кадр анимации  if AnimationFrame > AnimationFramesCount then     StopAnimation; procedure StopAnimation;  Timer1.Enabled := False;
И при определённых условиях в обработчике событий мыши вызывается StartAnimation.

Проблема в том, что после вызова StartAnimation цикл обработки событий спокойно продолжается. А мне надо как-то его притормозить, поставить на паузу, пока анимация не отрисуется, т.е. чтобы программа ждала конца анимации и уже потом продолжала работать.
Щас, пока писал, пришла в голову мысль, что, может, просто вставить пустой цикл, выполняющийся до тех пор, пока Timer.Enabled не станет False?
Но это какое-то топорное решение (если оно, вообще, будет работать). Может, есть какое-то более правильное решение?

Seenkao:
Надо создать флаг, который будет включаться, когда проигрывается анимация. Если флаг включен, то значит события ни какие не обрабатываем и выходим из обработки. Если выключен, то обработка событий происходит.

Navigation

[0] Message Index

[#] Next page

Go to full version