Хочу проконсультироваться на счет одной проблемы. Пишу одно приложение, которое представлет из себя что-то вроде расписания движения поездов (Направление поезда -> Время). Информация о движении выводится в такое табло, которое раньше можно было наблюдать на железнодорожных вокзалах и аэропортах: каждая буква и цифра в отдельной ячейке на табло. При изменении информации (меняется только Время) цифры начинают перелистываться на подобие того, как это имело бы место при перелистывании страниц книги. Вид этого табло можно посмотреть здесь: http://podonok-studio.jino-net.ru/screen.jpg
Для реализации этого табло я использовал класс TDrawGrid, в ячейки объекта класса TDrawGrid выводил буквы и цифры. Объект DrawGrid1 занимает весь экран. Все цифры и все промежуточные состояния при их перелистывании (при изменении времени движения поездов) прорисовал в CorelDraw, получил кучу *.bmp файлов и засунул их в ImageList1, из которого потом методом ImageList1.Draw(DrawGrid.Canvas,R.Left,R.Top,i) по событию Timer1Timer выводил информацию на табло (т.е. вся эта мультипликация реализована в виде спрайтов). Так вот, изображения из ImageList1 в DrawGrid1 должны выводиться достаточно быстро, чтобы создавалась иллюзия перелистывания цифр. Максимальное число полей, которое может одновременно меняться (перелистываться) 30. При этом меня бы устроило, если бы следующее движение (изображение) выводилось через 30 ms. Однако по моим замерам при изменении изображений в 30 полях время составляет 90 ms (и это на моем достаточно новом ноутбуке: WinXP, Pentium 1.7 GHz mobile, RAM 512 MB, 256 MB video NVIDIA GeForce Go 6200, 798 MHz шина).
В связи с этим вопрос: как ускорить вывод изображений в табло? Создается впечатление, что это можно сделать только, используя DirectX или OpenGL, с которыми я не знаком. В частности, я не могу найти статей, которые бы описывали работу с DirectX при выводе спрайтов на какую либо форму (т.е. работу НЕ в полноэкранном режиме). Буду рад ЛЮБЫМ ИДЕЯМ по поводу создания данного приложения и ссылкам на статьи по работе с DirectX НЕ в полноэкранном режиме.
Уважаемые авторы вопросов! Большая просьба сообщить о результатах решения проблемы на этой странице. Иначе, следящие за обсуждением, возможно имеющие аналогичные проблемы, не получают ясного представления об их решении. А авторы ответов не получают обратной связи. Что можно расценивать, как проявление неуважения к отвечающим от автора вопроса.
Если кому еще интересно, проблема была решена простой оптимизацией,
следующим образом:
procedure TForm2.Timer2Timer(Sender: TObject);
var
i, j: integer;
Source, Dest, R: TRect;
MainBm, Template: TBitmap;
begin
inc(Frame);
if Frame > 79 then Frame := 0;
procedure TForm1.Timer2Timer(Sender: TObject);
var
r: trect;
begin
begin
R:=DrawGrid1.CellRect(1,j);
DrawGrid1.Canvas.Draw(R.Left,R.Top,b); //это я взял bitmap
Для измерения точного времени я использовал функции из статьи http://www.delphikingdom.com/asp/articles_forum.asp?ArticleID=455
В данном случае можно выводить 10 букв на одну большую картинку, а в таблицу выводить уже её.
У меня это дало самые хорошие результаты. Вот как я попробовал:
T := 0;
Bmp := TBitmap.Create;
try
Bmp.Height := ImageListCep1.Height;
Bmp.Width := ImageListCep1.Width*ImageListCep1.Count;
for j := 1 to 1000 do
begin
//ImageListCep1.Count = 35;
//размер 32x32
CountCPU(C);
Bmp.Canvas.Brush.Color := Color;
Bmp.Canvas.FillRect(Rect(0,0,Bmp.Width,Bmp.Height));
for I := 0 to ImageListCep1.Count - 1 do
begin
ImageListCep1.Draw(Bmp.Canvas,i*ImageListCep1.Width,0,i);
end;
Canvas.Draw(10,50,Bmp);
T := T + CountCPU(C);
end;
finally
FreeAndNil(Bmp);
end;
Label3.Caption := CountCPUtoSTR((T)div(1000*ImageListCep1.Count)); //9 мкс
Здесь просили фрагмент кода отрисовки DrawGrid. Привожу его ниже.
В коде видно каким образом измерялось время прорисовки.
//-----срабатывает на все ячейки DrawGrid!---------
procedure TForm2.DrawGrid1DrawCell(Sender: TObject; ACol, ARow: Integer;
Rect: TRect; State: TGridDrawState);
var
Symbol, index: integer;
begin
//1) выяснить необходимый символ по массиву Goods
//2) найти порядковый номер изображения в ImageList
//3) вывести изображение с помощью ImageList1.Draw
//Goods[ARow+1][ACol+1] - это дает символ, если Length(Goods[ARow+1])>=ACol
//последние три поля заполняем НУЛЯМИ
//все остальное заполняем пустым полем BLANK
//далее используем конструкцию case, предварительно переведя буквы в коды
procedure TForm2.Timer2Timer(Sender: TObject);
var
j: integer;
//t1, t2: comp; //это используется для измерения скорости прорисовки
begin
inc(i);
if i>79 then i:=0;
//t1:=TimeStampToMSecs(DateTimeToTimeStamp(Time)); //это используется для измерения скорости прорисовки
for j:=0 to 10 do
begin
R:=DrawGrid1.CellRect(22,j);
ImageList2.Draw(DrawGrid1.Canvas,R.Left,R.Top,i);
//t2:=TimeStampToMSecs(DateTimeToTimeStamp(Time)); //это используется для измерения скорости прорисовки
//Timer2.Enabled:=False; //это используется для измерения скорости прорисовки
//Panel1.Caption:=FloatToStr(t2-t1); //это используется для измерения скорости прорисовки
//RESUME: чтобы перевернуть все цифры, требуется 94 ms, против 30 ms нужных
//полей с цифрами 11(рядов)x3(колонки)=33, на одно поле примерно 3 ms
//размер поля 49x61 пикселей, черно-белое изображение
end;
20-09-2006 09:41 | Комментарий к предыдущим ответам
Мне тут сказали что чушь во втором ответе написал, с чем вобщем-то полностью согласен. Более того - кроме первого ответа не собирался больше и писать. Ради интереса попробовал с Thread'ами посмотреть как будет... Вобщем жуть, забыли.
20-09-2006 01:48 | Вопрос к автору: запрос дополнительной информации
Хорошо бы увидеть кусок кода отрисовки. Возможно всё дело в том, что TDrawGrid при каждой перерисовке обновляет все ячейки строки.
У меня получилось скорость отрисовки одного изображения (32x32)
ImageList: 13мкс
Bitmap: 11мкс
Даже учитывая возможную разницу скорости компов, время отрисовки в 100 раз меньше необходимого.
TForm1 = class(TForm)
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
{ TMyThread }
constructor TMyThread.Create(CreateSuspended: Boolean);
begin
inherited Create(CreateSuspended);
Y := 0;
b:= tbitmap.Create;
b.LoadFromFile('D:\2.bmp'); //?acia?u 32x32
end;
destructor TMyThread.Destroy;
begin
b.Free;
inherited;
end;
procedure TMyThread.DrawBitmap;
begin
form1.canvas.Draw(x, y, b);
//windows.BitBlt(form1.Canvas.Handle, x,y,32,32, b.Canvas.Handle, 0, 0, srccopy);
end;
procedure TMyThread.Execute;
begin
while (not Terminated) and (y<1000) do
begin
Synchronize(DrawBitmap);
Inc(Y, 1);
//sleep(3);
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
i: integer;
h: array[0..30] of TMyThread;
begin
for I := 0 to 30 do
begin
h[i] := TMyThread.Create(True);
h[i].x := i*32;
h[i].FreeOnTerminate := true;
end;
А как такой вариант: создать единственный битмап, где по порядку по горизонтали расположены все картинки, к примеру 16х16 пиксел -->
тобишь получается 200 мелких картинок будут помещены в битмап 320х16 пиксел. А для быстрого рисования я бы использовал такую штуку:
X:=i*16; //i - индекс нужной картинки
BitBlt(DrawGrid1.Canvas.Handle,Rect.Left,Rect.Top,16,16,Bmp.Canvas.Handle,X,0,SRCCOPY);
Естественно, что для других размеров битмаиов нужно подставить свои числа
Если вы заметили орфографическую ошибку на этой странице, просто выделите ошибку мышью и нажмите Ctrl+Enter. Функция может не работать в некоторых версиях броузеров.