Помощь - Поиск - Пользователи - Календарь
Полная версия: Контролы, API
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
Unconnected
Привет всем. 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
Цитата
всегда ли обязательно создавать
по-моему - да.
Цитата
где задавать такие параметры 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
Цитата
или есть какой-то более простой способ внешнего проектирования?
RC-файл - достаточно простой способ? Тогда используй его. Описание (какие контролы как описываются) есть в MSDN... А на FirstSteps - так и по-русски есть наверняка. В чем нестабильность - не знаю, сколько программ написано - всегда создавали сложные формы в RC-файле, и линковали его к программе (даже не линковали, а просто включали в проект, Дельфи сама сделает, что нужно)...

Цитата
а делфи второй параметр не принимает такой, а принимает CmdShow
А ты не путай формальный параметр с именем переменной, которую ты передаешь в функцию (формальный параметр и в Дельфи тоже называется nCmdChow, а вот переменная, которая содержит значение, указывающее, как было запущено твое окно - называется CmdShow)
Unconnected
Присоединил .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 не нашел инфы по ресурсам, нашел только здесь. Убрал описание формы, но пробовал и с ней - результат тот же (и фигурные скобки на begin/end тоже заменять пробовал). И ещё, при создании вручную контрола (окна) мы хоть хэндл можем получить и отправить ему стили например, как Client показал, а при таком способе у нас вроде только текстовый идентефикатор и будет.. Кстати, это наверное удобный способ для переноса с VCL, открываешь блокнотом .dfm и переносишь)

Added: сделал через .res, работает. Яндексом нашёл структуру такого диалога в .rc (можно объявлять несколько шаблонов). Только вот почему-то когда вызываю dialogbox, помимо моего основного окна появляется это новое окно, а мне надо, чтобы то менялось..
volvo
Цитата
И ещё, при создании вручную контрола (окна) мы хоть хэндл можем получить и отправить ему стили например, как 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
Цитата
У меня сложилось впечатление, что если сохранить RC-файл в UTF8,


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

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


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

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


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

Обратил внимание, что в конце 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-файлами я бы посоветовал тебе скачать какой-нибудь из редакторов (у меня - ResEd 2.0.0.0 для таких нужд). Если надо подправить окошко - очень удобно, он визуальный...
Unconnected
Цитата
Есть еще несколько отличий функции окна-диалога от функции обычного окна. Если интересно - напишу...


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

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


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

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

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


Аа, что-то типа KOL&MCK, плавали, знаем ) Не такое уж извращение, если сильно не увлекаться этим делом) Что ж, Client, volvo, спасибо за советы smile.gif
Unconnected
Ещё одну свою заморочку с api вспомнил. Там есть функция для рисования на устройстве ("в контексте устройства") jpg-картинки? Например, имея хэндл формы, отрисовать там что-то. Пол-инета перерыл, получилось отобразить битмап с помощью loadimage и ещё пары функций, а для jpg нету ничего (loadimage тянет битмапы, курсоры и иконки только).
volvo
Либо вот такой бред: [C++,WinAPI]Загрузка картинки , либо берешь тут библиотеку GDI+, и рисуешь через GdipLoadImageFromFile (да в принципе, там много чего есть: MSDN -> GDI+ Reference).

Добро пожаловать в WinAPI smile.gif
Unconnected
В бреде я был, только что-то сильно много там всего и непонятного) Библиотеку скачал, посмотрел демки, выбрал вроде как нужное, для открытия 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
Итак, результаты экспериментов с отрисовкой 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
Кстати, завёлся 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
Сейчас как раз ковырялся с gdi, хорошо, что обновил форум smile.gif Просто не хотелось отдавать 20 кб на откуп activex и comobj (хотя способ, конечно, рабочий). У меня на D2007, кстати, тоже не завелась gdi - видела ошибку в коде, поэтому пишу под семёркой сейчас.

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


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

Да, в api-проекте нужно делать, как делал я. Прикрепляю демо-пример.
Unconnected
Там в этой 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
Цитата
ам в этой GDI есть тип непонятный какой-то, называется IStream, якобы поток.
Не тип, а интерфейс. IStream Interface

Вот тут посмотри: http://www.delphikingdom.com/asp/answer.asp?IDAnswer=48264
Unconnected
Спасибо за ссылку, сопоставил коды, получилось:

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;

Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.