Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Делфи _ Контролы, API

Автор: Unconnected 28.06.2010 21:20

Привет всем. smile.gif

Сейчас начал переводить одно своё приложение на api, весёлое занятие) С механизмами всё понятно, часть проги портировал, а вот с отображением контролов на окне не очень ясно.. Во-первых - всегда ли обязательно создавать, например, label таким образом (для себя в ф-ю обернул):

Procedure createstatic(caption:string;x,y,wid,hei:integer);
begin
CreateWindow('static', pchar(caption), WS_CHILD or WS_VISIBLE,x,y,wid,hei,hwndmain,10000, hInstance, 0);
end;

, или есть какой-то более простой способ внешнего проектирования? Я читал про добавление информации о контролах в ресурсы; это, в принципе, довольно удобно, если сделать быструю компиляцию .rc в .res батником (ну когда нужно быстро что-то изменить там), но вроде как он (способ) нестабильный какой-то.. Во-вторых - где задавать такие параметры static, как шрифт, цвет, размер текста?
Плохо, что вся инфа в msdn по api во-первых, на английском, а во-вторых, там сишный синтаксис. Вот в msdn, например, было написано ShowWindow(hwndMain, nCmdShow);, а делфи второй параметр не принимает такой, а принимает CmdShow (хотя в мсдн вроде и было указано, что от платформы зависит). И ещё, вот, допустим, в процессе исполнения надо мне изменить что-то, например цвет формы. Для этого достаточно вызвать функцию с параметрами, или надо в оконной функции описывать обработку сообщения CTL_COLOR, а потом когда надо отправлять это сообщение?

Автор: Client 28.06.2010 21:51

Цитата
всегда ли обязательно создавать
по-моему - да.
Цитата
где задавать такие параметры static, как шрифт
var
Font: HFONT;
...
Font := CreateFont( -30, 15, 25, 10, 1000, 1, 1, 0,
DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
DEFAULT_PITCH or FF_DONTCARE, 'Courier New' );
...
SendMessage( Btn, WM_SETFONT, Font, 0 );

Примерно так

Добавлено через 2 мин.
Цитата
nCmdShow
Тип то у него int - целый smile.gif

Автор: volvo 28.06.2010 22:18

Цитата
или есть какой-то более простой способ внешнего проектирования?
RC-файл - достаточно простой способ? Тогда используй его. Описание (какие контролы как описываются) есть в MSDN... А на FirstSteps - так и по-русски есть наверняка. В чем нестабильность - не знаю, сколько программ написано - всегда создавали сложные формы в RC-файле, и линковали его к программе (даже не линковали, а просто включали в проект, Дельфи сама сделает, что нужно)...

Цитата
а делфи второй параметр не принимает такой, а принимает CmdShow
А ты не путай формальный параметр с именем переменной, которую ты передаешь в функцию (формальный параметр и в Дельфи тоже называется nCmdChow, а вот переменная, которая содержит значение, указывающее, как было запущено твое окно - называется CmdShow)

Автор: Unconnected 29.06.2010 3:14

Присоединил .rc, вписал там такое:

form
CONTROL "WinAPI. Урок 2. Создание контролов с помощью ресурсов", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 8, 10, 180, 30
CONTROL "Закрыть", 51, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 126, 88, 60, 14



, что-то не кушает.. На firststeps не нашел инфы по ресурсам, нашел только http://www.vr-online.ru/?q=content/winapi-urok-vtoroj-sozdanie-kontrolov-s-pomoshh-resursov-502 Убрал описание формы, но пробовал и с ней - результат тот же (и фигурные скобки на begin/end тоже заменять пробовал). И ещё, при создании вручную контрола (окна) мы хоть хэндл можем получить и отправить ему стили например, как Client показал, а при таком способе у нас вроде только текстовый идентефикатор и будет.. Кстати, это наверное удобный способ для переноса с VCL, открываешь блокнотом .dfm и переносишь)

Added: сделал через .res, работает. Яндексом нашёл структуру такого диалога в .rc (можно объявлять несколько шаблонов). Только вот почему-то когда вызываю dialogbox, помимо моего основного окна появляется это новое окно, а мне надо, чтобы то менялось..

Автор: volvo 29.06.2010 7:50

Цитата
И ещё, при создании вручную контрола (окна) мы хоть хэндл можем получить и отправить ему стили например, как Client показал, а при таком способе у нас вроде только текстовый идентефикатор и будет..
Ну да, ну да...

А что, вот это сделать тебе какая-то внутренняя преграда запрещает:
// новая функция, которая обрабатывает все команды
// от элементов управления диалога
function DlgProc(hWin: HWND; uMsg: UINT; wp: WPARAM; lp: LPARAM): bool; stdcall;
begin
Result := False;
case uMsg of
// инициализация окна
WM_INITDIALOG:
begin
SendMessage(GetDlgItem(hWin, 51), WM_SETFONT, WPARAM(myFont), 0); // Вот оно, чудо чудное !!!
end;

//обрабатываем команды получаемые от пользователя
WM_COMMAND:
begin
case LoWord(wp) of
// а вот и наша кнопка, с идентификатором 51...
51: EndDialog(hWin, 0);
end;
end;
end;
end;
?

Я сделал диалог, который описал полностью в RC-файле, и запускаю его по нажатию кнопки на своей форме. Вот результат:
Прикрепленное изображение

Сам диалог описан вот так:
TestDialog DIALOG  10, 10, 300, 110
STYLE WS_POPUP | WS_BORDER
CAPTION "Test"
{
CONTROL "WinAPI. Lesson 2", -1, STATIC, SS_LEFT | WS_CHILD | WS_VISIBLE | WS_GROUP, 8, 10, 180, 30
CONTROL "Close", 51, BUTTON, BS_PUSHBUTTON | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 126, 88, 60, 14
}


Никакой перекомпиляции диалога через brcc32.exe на фиг не надо - при внесении изменений в RC-файл Дельфи сама перекомпилирует все, что надо. Для этого нужно самую малость: чтобы RC-файл был корректным, и в правильной кодировке. У меня сложилось впечатление, что если сохранить RC-файл в UTF8, то он компилироваться из Дельфи не будет (надо будет попробовать, а будет ли из ком. строки с использованием brcc32)

Так что ты говоришь нельзя сделать? smile.gif Сообщение послать? Сравни шрифт на Статик-контроле и на кнопке, ага...

Что там у тебя с изменением чего-то не получается? Ты б приаттачил проект полностью (тестовый, который не отрабатывает так, как нужно) - было бы проще посмотреть, в чем проблема...

Автор: Unconnected 29.06.2010 20:13

Цитата
У меня сложилось впечатление, что если сохранить RC-файл в UTF8,


Я сохранял в ANSI, и добавлял в проект через Add.. Ну это уже очень важно, я организовал через батник, пару лишних кликов не критичны smile.gif Я вот не пойму, в контексте api диалог и окно это одно и то же, что ли?

Цитата
Так что ты говоришь нельзя сделать? smile.gif Сообщение послать?


Да, и и правда можно, всё дело в GetDlgItem) А можно шрифт для удобства прямо в .rc вписывать при описании статика?
Цитата

Что там у тебя с изменением чего-то не получается?


Да даже толком попробовать не вышло) Я изначально создаю примитивное окно (CreateWindow), что-то с ним делаю, а потом надо то окно убрать и показать форму со статиками и кнопками. И вот я не знаю, нужно ли переделывать старое окно, или можно его спрятать и отрисовать этот новый диалог..

Автор: volvo 29.06.2010 21:14

Цитата
Я вот не пойму, в контексте api диалог и окно это одно и то же, что ли?
Никогда не говори этого своей программе, потому как http://msdn.microsoft.com/en-us/library/ms645469%28v=VS.85%29.aspx и http://msdn.microsoft.com/en-us/library/ms633573%28v=VS.85%29.aspx - это совершенно разные вещи. По-русски о функции диалога можно почитать http://www.firststeps.ru/mfc/winapi/dialog/r.php?48

Обратил внимание, что в конце DlgProc отсутствует вызов DefWindowProc? Это не ошибка, в функции диалогового окна вызова этой функции быть не должно:
Цитата
Although the dialog box procedure is similar to a window procedure, it must not call the DefWindowProc function to process unwanted messages. Unwanted messages are processed internally by the dialog box window procedure.


Есть еще несколько отличий функции окна-диалога от функции обычного окна. Если интересно - напишу...

Цитата
А можно шрифт для удобства прямо в .rc вписывать при описании статика?
Можно описать шрифт, который будет установлен для всего диалога, если этого недостаточно - то придется слать сообщение. По отдельности задавать шрифт для каждого контрола в RC нельзя. Это, кстати, совершенно совпадает с поведением CreateWindow... Если ты создаешь контрол, и его шрифт тебя чем-то не устраивает - ты вправе его изменить посылкой сообщения этому контролу. Но прямо при создании (в вызове CreateWindow) ты задать шрифт не можешь.

Для удобства работы с RC-файлами я бы посоветовал тебе скачать http://www.wasm.ru/toollist.php?list=2 (у меня - ResEd 2.0.0.0 для таких нужд). Если надо подправить окошко - очень удобно, он визуальный...

Автор: Unconnected 29.06.2010 22:58

Цитата
Есть еще несколько отличий функции окна-диалога от функции обычного окна. Если интересно - напишу...


Я так понял, диалоги призваны не замещать основные окна, а быть именно диалогами.. Конечно интересно smile.gif
Цитата

Можно описать шрифт, который будет установлен для всего диалога, если этого недостаточно - то придется слать сообщение. По отдельности задавать шрифт для каждого контрола в RC нельзя. Это, кстати, совершенно совпадает с поведением CreateWindow... Если ты создаешь контрол, и его шрифт тебя чем-то не устраивает - ты вправе его изменить посылкой сообщения этому контролу. Но прямо при создании (в вызове CreateWindow) ты задать шрифт не можешь.


На данный момент я буду использовать createwindow. У меня там много тех же Label'ов, и каждый со своими параметрами цвета, размера и шрифта. Поэтому я завёл массив hwnd и создал структуру, где для каждого статика будет храниться соответствующая ему информация, буду создавать в цикле и отправлять информацию о шрифте и т.п. Хотя, с диалогами, конечно, удобнее, когда не надо много атрибутов задавать контролам, возьму на вооружение. Кстати, а можно сделать свой визуальный "класс", ну или как это ещё назвать, типа TPanel ?

Автор: volvo 30.06.2010 2:45

Цитата
Кстати, а можно сделать свой визуальный "класс", ну или как это ещё назвать, типа TPanel ?
Ну, началось. Ты зачем на WinAPI программу пишешь? Чтобы сляпать самодельную VCL? У тебя не получится, уверяю... Велосипед будет на 24-х колесах, из которых 16 - квадратных, 4 треугольных, а остальные - овальные. Не приедешь ты на таком велосипеде никуда.

Нужны визуальные компоненты - используй VCL. Где-то видел я статью, как писать на WinAPI, используя ООП - извращение еще то, я попробовал, но забросил это дело.

Чуть позже напишу о диалоговых окнах...

Автор: Unconnected 30.06.2010 14:37

Цитата
Где-то видел я статью, как писать на WinAPI, используя ООП - извращение еще то, я попробовал, но забросил это дело.


Аа, что-то типа KOL&MCK, плавали, знаем ) Не такое уж извращение, если сильно не увлекаться этим делом) Что ж, Client, volvo, спасибо за советы smile.gif

Автор: Unconnected 1.07.2010 4:49

Ещё одну свою заморочку с api вспомнил. Там есть функция для рисования на устройстве ("в контексте устройства") jpg-картинки? Например, имея хэндл формы, отрисовать там что-то. Пол-инета перерыл, получилось отобразить битмап с помощью loadimage и ещё пары функций, а для jpg нету ничего (loadimage тянет битмапы, курсоры и иконки только).

Автор: volvo 1.07.2010 5:27

Либо вот такой бред: http://forum.sources.ru/index.php?showtopic=208869 , либо берешь http://www.progdigy.com/?page_id=7 библиотеку GDI+, и рисуешь через GdipLoadImageFromFile (да в принципе, там много чего есть: http://msdn.microsoft.com/en-us/library/ms533799%28v=VS.85%29.aspx).

Добро пожаловать в WinAPI smile.gif

Автор: Unconnected 1.07.2010 6:05

В бреде я был, только что-то сильно много там всего и непонятного) Библиотеку скачал, посмотрел демки, выбрал вроде как нужное, для открытия gif (ну я так понял, и jpeg тоже должно жевать). Вытащил следующее:

Procedure OnPaint(DC: HDC);
var
graphics : TGPGraphics;
Image: TGPImage;
destinationRect: TGPRectF;
begin
graphics := TGPGraphics.Create(DC);
Image:= TGPImage.Create('vol.gif');
graphics.DrawImage(image, 0, 0);
Image.Free;
graphics.Free;
end;

procedure TForm1.FormPaint(Sender: TObject);
var handle:hdc;
ps:paintstruct;
begin
Handle := BeginPaint(form1.form.Handle, ps);
OnPaint(Handle);
EndPaint(form1.form.handle, ps);
end;


По нажатию кнопки шлю sendmessage(form1.handle,WM_PAINT,0,0);. Что не так?

Автор: volvo 1.07.2010 14:41

Итак, результаты экспериментов с отрисовкой JPG без использования доп. библиотек: GDI+ у меня на D2009 не завелся, там что-то поменялось, а качать версию, которая специально предназначена для D2009 мне лень, поэтому возиться с этим не стал.

Способ с OLE. Отработал, но я опять же не стал делать чистое API-приложение, положил на форму TPanel, и отрисовал на ней. Все прекрасно отобразилось:

// В интерфейсной части модуля
function OleLoadPicturePath(szUrlorPath: PWideChar;
unkCaller: IInterface; dwReserved: Integer; drReserved: Cardinal;
const iid: TGUID; ppvRet: Pointer): HRESULT; stdcall;


// а это - в Implementation
uses ActiveX, ComObj;

// Если не описать этого, то получишь ошибку, что OleLoadPicturePath отсутствует в модуле
// olepro32.dll ... Но оно действительно не там, а в oleaut32.dll, и это надо объяснить программе...
function OleLoadPicturePath; external 'oleaut32.dll' name 'OleLoadPicturePath';


const
IID_IPicture: TGUID = '{7BF80980-BF32-101A-8BBB-00AA00300CAB}';

procedure TForm1.Button5Click(Sender: TObject);
var
pic: IPicture;
f_name: WideString;

picWidth, picHeight: Integer;
bounds: TRect; // Здесь оно на фиг не надо. но Render требует...
begin
f_name := 'F:\Test\av-1235.jpg';
Pic := nil;

OleCheck( OleLoadPicturePath(PWideChar(f_name), nil, 0, 0, IID_IPicture, @Pic) );
OleCheck( pic.get_Width(picWidth) );
OleCheck( pic.get_Height(picHeight) );

pic.Render(GetWindowDC(Panel1.Handle), 0, 0, Panel1.Width, Panel1.Height,
0, picHeight, picWidth, -picHeight, bounds);
end;


Не думаю, что будет сложно сделать то же самое на чистом API smile.gif


Автор: volvo 1.07.2010 16:46

Кстати, завёлся GDI+ и на 2009-ой Дельфи (достаточно было в Project -> Options -> Delphi Compiler -> Conditional Defines добавить COMPILER5_UP, тогда модули GDIPOBJ/GDIPAPI прекрасно компилируются).

И вот это:

Procedure myOnPaint(DC: HDC);
var
graphics : TGPGraphics;
Image: TGPImage;
destinationRect: TGPRectF;
begin
Image:= TGPImage.Create('F:\Test\av-1235.jpg');
graphics := TGPGraphics.Create(DC);
graphics.DrawImage(image, 0, 0);
Image.Free;
graphics.Free;
end;

procedure TForm1.FormPaint(Sender: TObject);
var ps:paintstruct;
begin
BeginPaint(form1.Handle, ps);
myOnPaint(Form1.Canvas.Handle);
EndPaint(form1.handle, ps);
end;

очень даже рисует JPG-файл на канве формы. Обрати внимание: я не передаю в myOnPaint тот DC, который получен от BeginPaint-а, я передаю хендл канвы формы. Возможно в API-проекте и нужно будет передавать так, как делаешь ты, но мне все еще лень ( smile.gif ) делать все ручками, я проверил на VCL-проекте. Может, попозже вечером, соберусь и сделаю API-проект, и там все проверю... Или ты проверь и выложи результаты.

Автор: Unconnected 1.07.2010 17:38

Сейчас как раз ковырялся с gdi, хорошо, что обновил форум smile.gif Просто не хотелось отдавать 20 кб на откуп activex и comobj (хотя способ, конечно, рабочий). У меня на D2007, кстати, тоже не завелась gdi - видела ошибку в коде, поэтому пишу под семёркой сейчас.

Цитата
Обрати внимание: я не передаю в myOnPaint тот DC, который получен от BeginPaint-а, я передаю хендл канвы формы.


Вот это немного странно, в демо-примере наоборот, я делал всё так же, и не работало. Всё не мог с этим смириться) Почему-то в BeginPaint передаётся хэндл формы, а в MyOnPaint - хэндл канвы формы. Кстати, на VCL название процедуры OnPaint действительно нужно менять smile.gif

Да, в api-проекте нужно делать, как делал я. Прикрепляю демо-пример.

Автор: Unconnected 1.07.2010 18:05

Там в этой GDI есть тип непонятный какой-то, называется IStream, якобы поток. С T<...>Stream его ассоциировать никак не получается, да даже и описать переменную такого типа тоже нельзя. Он используется во многих функциях загрузки изображений. Поползал по юнитам, нашёл только что он является интерфейсом от некого ISequentialStream (которого, впрочем, моя программа тоже не видит, наверное, это всё приватные структуры). Это я так картинки из ресурсов гружу:

Function LoadJpegRes(const ID: string): TStream;
var
RS: TResourceStream;
begin
RS:=TResourceStream.Create(HInstance, ID, 'JPEG');
result:=TStream.create;
try
RS.Seek(0, soBeginning);
Result.CopyFrom(rs,rs.size);
finally
RS.Free;
end;
end;

Procedure myOnPaint(DC: HDC;x,y:integer;stream:TStream);
var
graphics : TGPGraphics;
Image: TGPImage;
destinationRect: TGPRectF;
begin
Image:= TGPImage.Create();
GdipLoadImageFromStream(stream,image); //<-тут ошибка
graphics := TGPGraphics.Create(DC);
graphics.DrawImage(image, x, y);
Image.Free;
graphics.Free;
end;

Procedure getimage(id:string;x,y:integer); //<--изначально собираюсь вызывать её с ID ресурса и координатами
var ps:TPaintStruct;
begin
BeginPaint(form1.form.Handle, ps);
myOnPaint(Form1.form.Canvas.Handle,x,y,loadjpegres(id));
EndPaint(form1.handle, ps);
end;


Автор: volvo 1.07.2010 18:23

Цитата
ам в этой GDI есть тип непонятный какой-то, называется IStream, якобы поток.
Не тип, а интерфейс. http://msdn.microsoft.com/en-us/library/aa380034%28VS.85%29.aspx

Вот тут посмотри: http://www.delphikingdom.com/asp/answer.asp?IDAnswer=48264

Автор: Unconnected 1.07.2010 19:21

Спасибо за ссылку, сопоставил коды, получилось:


procedure TForm1.Button1Click(Sender: TObject);
var stream:IStream;
image:TGPImage;
graphics:TGPGraphics;
begin
with TResourceStream.Create(hInstance,'PIC1','JPEG') do try
OleCheck(CreateStreamOnHGlobal(0,True,Stream));
OleCheck(Stream.Write(Memory,Size,nil));
Image:=TGPBitmap.Create(Stream);
graphics:=TGPGraphics.Create(form1.Canvas.Handle);
graphics.DrawImage(image, 0, 0, 100,100);
finally
Free;
image.free;
graphics.Free;
end;
end;