CreateDIBitmap в VCL компоненте
От: siniypin Россия http://bobbbloggg.blogspot.com/ http://robbbloggg.blogspot.com/
Дата: 14.11.05 16:45
Оценка:
Господа, у меня есть вопрос... Даже два. =(
Первый:
При написании VCL компонента столкнулся со странным поведением функции CreateDIBitmap — в некоторых случаях, возвращаемый хендл битмапа = 0, т.е. он попросту не создается...
Поясняю, компонент — эмулятор графического LCD дисплея. Его изображение хранится во внутреннем поле TBitmap и рисуется на канве компонента в методе Paint функцией Сanvas.StretchDraw(...) (компонент унаследован от TCustomControl)... Символы генерируются из массивов пикселов при разборе строки... Хранятся они вот так:
BigLetters : array['А'..'Я'] of TLetterPlace =
  (
   ((1,1,1,1,1,1,1,1),//строки выровнены все норм..
    (1,0,1,1,1,0,1,1),
    (1,0,1,1,1,0,1,1),
    (1,0,0,0,0,0,1,1),
    (1,0,1,1,1,0,1,1),
    (1,0,1,1,1,0,1,1),
    (1,1,0,1,0,1,1,1),
    (1,1,1,0,1,1,1,1))
  ,...............

Вот код метода компонента, который создает двухцветную картинку(символ) из массива значений пикселов:
procedure TbbLCD.MakeBMP(aSimb: PAnsiChar; IsScreen : Boolean; aInx : Integer; aBMP : TBitmap);//: TBitmap;
var
  lpbInit : PAnsiChar;
  pbi : PBitmapInfo;
  i : Integer;
  hBMP : HBITMAP;
begin
  GetMem(pbi, SizeOf(TBitmapInfo) + 2*Sizeof(TRGBQUAD));
  ZeroMemory(pbi, SizeOf(TBitmapInfo) + 2*Sizeof(TRGBQUAD));

  pbi^.bmiHeader.biSize := SizeOf(TBitmapInfoHeader);
  //блаблабла

  for i := 0 to 1 do begin
    pbi^.bmiColors[i].rgbBlue := i*180;
    pbi^.bmiColors[i].rgbGreen := i*180;
    pbi^.bmiColors[i].rgbRed := i*180;
  end;

 //блаблабла

  try
    hBMP := CreateDIBitmap(Canvas.Handle, pbi^.bmiHeader, CBM_INIT,
                           lpbInit, pbi^, DIB_RGB_COLORS);//<---------Вот здесь по непонятным мне причинам я получаю 0    if hBMP <> INVALID_HANDLE_VALUE then begin
      aBMP.Handle := hBMP;
    end;
  finally
    //блаблабла
  end;
end;

hBMP=0 я получаю в случаях, когда изменяю заданные по умолчанию значения количества строк, числа символов в строке, масштаба и т.д. По умолчанию у эмулятора 4 строки и 16 символов в строке. При изменении последних и появляются эти так сказать "артефакты", то есть некоторые символы-битмапы не создаются.. Какой-то закономерности или системы в этом я не обнаружил. =\

эти символы накладываются на основной битмап-экран (код метода разбора строки):
procedure TbbLCD.ParseLine(aIndex: Integer; const aLine: String; aCurPos1 : Integer = -1; aCurPos2 : Integer = -1);
var
  i, Bound : Integer;
  tmp, tmpSpace : TBitMap;
  Cursor{, PrevCursor} : Boolean;
  pLine : PChar;
begin
  pLine := PAnsiChar(aLine);

 //блаблабла

  tmpSpace := TBitmap.Create;
  MakeBMP(@Simbols[' '], False, aIndex, tmpSpace);
  if not Assigned(tmpSpace) then
    Raise Exception.Create('Can not create Bitmap!');

 try

    while (i < Bound) do begin

      tmp := TBitmap.Create;

      if (Length(pLine) < Pred(Bound)) and (i > Pred(Length(pLine))) then
        MakeBMP(@Simbols[' '], False, aIndex, tmp)
      else case pLine[i] of
        'А'..'Я':
          MakeBMP(@BigLetters[pLine[i]], False, aIndex, tmp);
       ///
      end;

      if Cursor then
        FScreen.Canvas.CopyMode := cmSrcInvert
      else
        FScreen.Canvas.CopyMode := cmSrcAnd;

      if (FScreenState <> ss1lines) and (aIndex = 0) then
        //
      else
        FScreen.Canvas.CopyRect(Rect(i*SimbW,(aIndex+Ord(FScreenState))*SimbH,
         (i+1)*SimbW,(aIndex+1+Ord(FScreenState))*SimbH),
          tmp.Canvas, Rect(0, 0, tmp.Width, tmp.Height));

      Inc(i);

      tmp.Free;

    end;

  finally
    tmpSpace.Free;
  end;
  
  Refresh;
end;

В чем тут может быть дело??? Я что не освобождаю ресурсы API? Вариант попиксельно созданному битмапу присваивать значения из хранимых матриц реализовать было лень (хотя это наверное и проще зато медленнее). Кстати эти матрицы хранятся в отдельном модуле. Может быть их можно хранить как-то компактнее без потери скорости доступа??

А теперь вопрос второй, если вы еще не очень от меня устали 8) ....
После создания из данного компонента ActiveX Control и регистрации в Дельфи он просто напросто отрисовывает свою рамку и больше ничего не отрисовывает , даже при условиях, когда VCL компонент работает отлично (без так сказать "артефактов")!!! Вай?....
Заранее спасибо тем кто откликнется!
Надеюсь я был не слишком назойлив...
З.Ы. D6, Win2000 & XP
Re: CreateDIBitmap в VCL компоненте
От: Dimonka Верблюд  
Дата: 14.11.05 17:25
Оценка:
Здравствуйте, siniypin, Вы писали:

S>Господа, у меня есть вопрос... Даже два. =(

S>Первый:
S>При написании VCL компонента столкнулся со странным поведением функции CreateDIBitmap — в некоторых случаях, возвращаемый хендл битмапа
BigLetters : array['А'..'Я'] of TLetterPlace =
  (
   ((1,1,1,1,1,1,1,1),//строки выровнены все норм..
    (1,0,1,1,1,0,1,1),
  ,...............


Каждую такую строчку можно было как в старые добрые времена сделать одним байтом.

S>Вот код метода компонента, который создает двухцветную картинку(символ) из массива значений пикселов:

procedure TbbLCD.MakeBMP(aSimb: PAnsiChar; IsScreen : Boolean; aInx : Integer; aBMP : TBitmap);//: TBitmap;
end;


S>В чем тут может быть дело??? Я что не освобождаю ресурсы API? Вариант попиксельно созданному битмапу присваивать значения из хранимых матриц реализовать было лень (хотя это наверное и проще зато медленнее). Кстати эти матрицы хранятся в отдельном модуле. Может быть их можно хранить как-то компактнее без потери скорости доступа??


Точно так же можно было обращаться к ScanLine битмапа, даже,.. наверное, чуток быстрее. В чем причина проблем с твоим кодом неохото разбираться..
Re: CreateDIBitmap в VCL компоненте
От: Danchik Украина  
Дата: 14.11.05 17:31
Оценка:
Здравствуйте, siniypin, Вы писали:

[Skip]

Упростите для начала свою задачу:

Создайте ImageList, в который и накидай таблицу символов — проще будет работать с таблицей, да и не надо будет имплементить собственный Stotage.
Попробуйте нарисовать всю таблицу для дебага.
Разберитесь почему CreateDIBitmap не работает. Может pbi^.bmiHeader.biBitCount <> 32 (вы ведь создали 32 битный буфер)...
Непонятно для чего вы создаете RGB картинку — вам проще было бы работать с Monohrome картинкой.
Re[2]: CreateDIBitmap в VCL компоненте
От: siniypin Россия http://bobbbloggg.blogspot.com/ http://robbbloggg.blogspot.com/
Дата: 16.11.05 12:11
Оценка:
Здравствуйте, Dimonka, Вы писали:

D> (

D> ((1,1,1,1,1,1,1,1),//строки выровнены все норм..
D> (1,0,1,1,1,0,1,1),
D> ,...............

D>Каждую такую строчку можно было как в старые добрые времена сделать одним байтом.

Критика уместна, но.. Каждую такую строчку мне все равно пришлось бы описать 4-мя байтами, 3 из которых были бы 0-ми... Так что объем хранимых данных уменьшился бы только в 2 раза, что по-моему не принципиально, вобщем что сделано то сделано...

D>Точно так же можно было обращаться к ScanLine битмапа, даже,.. наверное, чуток быстрее.

Согласен, что создавая VCL компонент логично пользоваться методами классов, которые эта самая VCL мне предоставляет...
Надо было бы сразу так и сделать.
А CreateDIBitmap корректно заработала, когда я явно указал, что я использую 2 цвета в полях biClrUsed = 2 и biClrImportant = 2. Забыл... =\

А вот второй вопрос все равно в силе.... Попробовал создать "тупой " ActiveX, который при создании заполняет битмап рандомными значениями и рисует его на своей канве в перегруженом методе Paint, и все работает... А этот компонент кроме рамки больше ничего не рисует... Есть ли какой-нить способ отлаживать ActiveX, расставив точки останова в исходном VCL классе? (я так подозреваю, что нет).
Да.. а при вызове в коде метода ParseLine(aIndex: Integer; const aLine: WideString; aCurPos1: Integer; aCurPos2: Integer); который автоматически транслирован Дельфи при создании AX,
например:

  bbLCDX1.ParseLine(0, '0123456', 0, 0);


ActiveX валится с "Разрушительным сбоем"! Тут-то в чем дело???

Заранее благодарен за ответ.
Re[3]: CreateDIBitmap в VCL компоненте
От: Danchik Украина  
Дата: 16.11.05 12:50
Оценка:
Здравствуйте, siniypin, Вы писали:

S>Есть ли какой-нить способ отлаживать ActiveX, расставив точки останова в исходном VCL классе? (я так подозреваю, что нет).


Почему же есть. И даже два.
Обьясню прицип одного, помоему самого простого:

1. Делаете ProgectGroup
2. Добавляете в нее ActiveX рrоject
3. Компилите ActiveX
4. Зарегистрируйте OCX файл (если еще не зарегистрен): regsvr32 MyActiveXControl.ocx
2. Создаете, так называемый, Loader.exe — проэкт который подымает вашу ActiveX. В него пожключаете Вашу MyActiveXControl_TLB.pas.
В лоадере пишем код создания ActiveX:
procedure TForm1.Button1Click(Sender: TObject);
begin
  FTestControl := TMyActiveX.Create(self); { TMyActiveX обьявлен в MyActiveXControl_TLB}
  FTestControl.Parent := Self;
  FTestControl.Align := alClient;
  FTestControl.AxBorderStyle := 0;
end;

Вот и дебажим

Удачи!
Re[2]: CreateDIBitmap в VCL компоненте
От: Dimonka Верблюд  
Дата: 16.11.05 13:17
Оценка:
Здравствуйте, Danchik, Вы писали:

D>[Skip]


D>Создайте ImageList, в который и накидай таблицу символов — проще будет работать с таблицей, да и не надо будет имплементить собственный Stotage.


А ImageList можно сделать доступным для пользователя, чтобы он свои картинки мог подгружать
Re[4]: CreateDIBitmap в VCL компоненте
От: siniypin Россия http://bobbbloggg.blogspot.com/ http://robbbloggg.blogspot.com/
Дата: 16.11.05 13:23
Оценка:
Я может быть неправильно выразился... Вопрос был можно ли дебажить исходный VCL код при использовании созданного из него ActiveX. В приведенном Вами методе я дальше вызова методов DefaultInterface не проникаю... То есть вся работа компонента остается скрытой от меня.. Отсюда и вопросов столько.. =\
Re[3]: CreateDIBitmap в VCL компоненте
От: siniypin Россия http://bobbbloggg.blogspot.com/ http://robbbloggg.blogspot.com/
Дата: 16.11.05 13:27
Оценка:
Здравствуйте, Dimonka, Вы писали:

D>Здравствуйте, Danchik, Вы писали:


D>>[Skip]


D>>Создайте ImageList, в который и накидай таблицу символов — проще будет работать с таблицей, да и не надо будет имплементить собственный Stotage.


D>А ImageList можно сделать доступным для пользователя, чтобы он свои картинки мог подгружать



Тогда это уже не эмулятор LCD экрана получится ))
Re[5]: CreateDIBitmap в VCL компоненте
От: Danchik Украина  
Дата: 16.11.05 14:43
Оценка:
Здравствуйте, siniypin, Вы писали:

S>Я может быть неправильно выразился... Вопрос был можно ли дебажить исходный VCL код при использовании созданного из него ActiveX. В приведенном Вами методе я дальше вызова методов DefaultInterface не проникаю... То есть вся работа компонента остается скрытой от меня.. Отсюда и вопросов столько.. =\


Посмотри в опции линковки твоего OCX:
Попробуй поключать Include TD32 debug info и Include remote debug symbols (оба на всякий пожарный). И сделай Build ALL.

Если у тебя Delphi 7 — проверь стоит ли у тебя update. В этой ветке
Автор: Denis_TST
Дата: 10.11.05
обсуждалась подобная проблема и как искать патч.
Re[4]: CreateDIBitmap в VCL компоненте
От: Dimonka Верблюд  
Дата: 16.11.05 14:50
Оценка:
Здравствуйте, siniypin, Вы писали:

S>Тогда это уже не эмулятор LCD экрана получится ))


Это будет эмулятор современного LCD экрана
Re[5]: CreateDIBitmap в VCL компоненте
От: PowerUserX  
Дата: 17.11.05 06:51
Оценка:
насчет CreateDIBitmap.
Ты неверно инициализируешь
вот пример на VC+

typedef struct tagBITMAPINFO_MY
{
BITMAPINFOHEADER bmiHeader;
RGBQUAD bmiColors[256];
}
BITMAPINFO_MY;

BITMAPINFO_MY m_bitInfo;
ZeroMemory(&m_bitInfo, sizeof(m_bitInfo));

m_bitInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
m_bitInfo.bmiHeader.biWidth = m_sizeTotal.cx;
m_bitInfo.bmiHeader.biHeight = m_sizeTotal.cy;
m_bitInfo.bmiHeader.biPlanes = 1;
m_bitInfo.bmiHeader.biBitCount = 8; // — т.е. 256 цветов (1,2,4,8,24,32)
m_bitInfo.bmiHeader.biCompression = BI_RGB;
m_bitInfo.bmiHeader.biSizeImage = ((m_bitInfo.bmiHeader.biWidth*m_bitInfo.bmiHeader.biBitCount+31)/32)*4*m_bitInfo.bmiHeader.biHeight;
memset(m_bitInfo.bmiColors, 0, sizeof(m_bitInfo.bmiColors));

// Init my colors
m_bitInfo.bmiColors[1].rgbBlue = 0;
m_bitInfo.bmiColors[1].rgbGreen = 0;
m_bitInfo.bmiColors[1].rgbRed = 0;
m_bitInfo.bmiColors[0].rgbBlue = 255;
m_bitInfo.bmiColors[0].rgbGreen = 255;
m_bitInfo.bmiColors[0].rgbRed = 255;

m_bitInfo.bmiColors[2].rgbBlue = 0;
m_bitInfo.bmiColors[2].rgbGreen = 255;
m_bitInfo.bmiColors[2].rgbRed = 0;
m_bitInfo.bmiColors[3].rgbBlue = 255;
m_bitInfo.bmiColors[3].rgbGreen = 0;
m_bitInfo.bmiColors[3].rgbRed = 0;

m_hBitmapSection = ::CreateDIBSection (m_dcMemoryToDraw.m_hDC, (BITMAPINFO*)&m_bitInfo.bmiHeader, DIB_RGB_COLORS, (PVOID*)&m_pvSection, 0, 0);
if ( !m_hBitmapSection ) exit(1);
//--------------------
Здесь создается секция, а по анологии создавай CreateDIBitmap
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.