Помощь - Поиск - Пользователи - Календарь
Полная версия: WinAPI для простой графики
Форум «Всё о Паскале» > Современный Паскаль и другие языки > Делфи
KljaGGsa
Как практически с помощью функций WinAPI нарисовать мячик, который бы двигался горизонтально в прямоугольнике вправо-влево, "отскакивая" от боковых стенок, "пинг-понг" - ? smile.gif
volvo
Что именно вызывает затруднения? Рисуем шарик с помощью Ellipse, сам прямоугольник - Rectangle. Написать программу, которая будет проверять, не выходит ли шарик за пределы прямоугольника, и если выходит - изменить направление движения - не должно составить большой проблемы.

Начинай, если что непонятно - говори, что именно.
KljaGGsa
В обычном пейнтбоксе и канвасе это действительно несложно, а вот как применить API сколько литературы не читаю, и бумажной и электронной, найти не могу . . . (((
volvo
Так тебе совсем WinAPI-шное приложение надо, без VCL? Ну, тогда так, к примеру:
program Project1;

uses
Windows, Messages;

const
WM_SETUP = 500;

WinName = 'MainWClass';
R = 5;

var
myTimer: THandle;
delta: integer;
Rec: TRect;
posX, posY: integer;

function MainWndProc(Window: HWnd; AMessage: UINT; WParam: WPARAM; LParam: LPARAM): INT_PTR; stdcall;
var
myDC: HDC;
ps: PAINTSTRUCT;
begin
case AMessage of
WM_CREATE: // Создание окна
begin
myTimer := SetTimer(Window, 0, 1, nil);
Result := 0; Exit;
end;
WM_SETUP: // "Установка" начальных значений
begin
myDC := GetDC(Window);
GetClientRect(Window, Rec);
posX := 0; posY := (Rec.Bottom - Rec.Top) div 2; delta := 5;
ReleaseDC(Window, myDC);
Result := 0; Exit;
end;
WM_SIZE: // Изменение размеров окна
begin
PostMessage(Window, WM_SETUP, 0, 0); // Просто вызываем "установку"
Result := 0; Exit;
end;
WM_PAINT:
begin
myDC := BeginPaint(Window, ps);
PostMessage(Window, WM_SETUP, 0, 0); // Тоже "установка"
EndPaint(Window, ps);
Result := 0; Exit;
end;
WM_TIMER: // Событие таймера
begin
myDC := GetDC(Window);
// стираем старое изображение шарика
SelectObject(myDC, GetStockObject(WHITE_PEN));
Ellipse(myDC, posX - R, posY - R, posX + R, posY + R);

if ((delta > 0) and (posX + delta + R > (Rec.Right - Rec.Left)))
or
((delta < 0) and (posX - delta - R < 0))
then delta := -delta;
posX := posX + delta;

// и рисуем в новых координатах новое
SelectObject(myDC, GetStockObject(BLACK_PEN));
Ellipse(myDC, posX - R, posY - R, posX + R, posY + R);
ReleaseDC(Window, myDC);
Result := 0; Exit;
end;
WM_DESTROY: // Уничтожение окна
begin
KillTimer(Window, myTimer);
PostQuitMessage(0);
Result := 0; Exit;
end;
else
Result := DefWindowProc(Window, AMessage, WParam, LParam);
end;
end;

function InitApplication: Boolean;
var
wcx: TWndClass;
begin
wcx.style := CS_HREDRAW or CS_VREDRAW;
wcx.lpfnWndProc := @MainWndProc;
wcx.cbClsExtra := 0;
wcx.cbWndExtra := 0;
wcx.hInstance := hInstance;
wcx.hIcon := LoadIcon(0, IDI_APPLICATION);
wcx.hCursor := LoadCursor(0, IDC_ARROW);
wcx.hbrBackground := COLOR_WINDOW;
wcx.lpszMenuName := nil;
wcx.lpszClassName := PChar(WinName);

Result := RegisterClass(wcx) <> 0;
end;

function InitInstance: HWND;
begin
Result := CreateWindow(
PChar(WinName),
'Ping-pong',
WS_OVERLAPPEDWINDOW,
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
Integer(CW_USEDEFAULT),
0, 0, hInstance, nil);
end;

var
hwndMain: HWND;
AMessage: msg;
begin
if (not InitApplication) then begin
MessageBox(0, 'Ошибка регистрации окна', nil, mb_Ok)
end
else begin
hwndMain := InitInstance;
if (hwndMain = 0) then begin
MessageBox(0, 'Ошибка создания окна', nil, mb_Ok)
end
else begin
ShowWindow(hwndMain, CmdShow);
UpdateWindow(hwndMain);
while (GetMessage(AMessage, 0, 0, 0)) do begin
TranslateMessage(AMessage);
DispatchMessage(AMessage);
end;
end;
end;

end.
Client
Это же не простой проект. Куда надо это скопировать?
volvo
Цитата
Это же не простой проект. Куда надо это скопировать?
blink.gif Это не простой, это простейший проект. Надо создать новое консольное приложение, и заменить код, предлагаемый Дельфями на код, приведенный выше.
Client
Цитата
Это не простой, это простейший проект
В смысле что там нету формы куда ложить кнопки, едиты....
volvo
Это WinAPI. Какие кнопки? Какие эдиты? VCL не используется.
KljaGGsa
а я в полном шоке от этого кода, совершенно растерялась и вчера даже в эфир не вышла . . . Где взять справочный и учебный материал, который мог бы хоть поверхностно объяснить откуда здесь ноги растут??? blink.gif
volvo
Цитата
Где взять справочный и учебный материал, который мог бы хоть поверхностно объяснить откуда здесь ноги растут???
Ну, начнем с самого начала. Ты знаешь, как Windows-приложение взаимодействует с ОСью? Про механизм сообщений слышала?
KljaGGsa
Нет, мне пока что это совсем незнакомо. Знаю только в первом приближении интерфейс оболочки Delphi7, основные свойства самых расхожих компонентов и простейшие алгоритмы их взаимодействия. Вот фрагмент вашего кода сразу бросился в глаза и удивил - какие-то сплошные сообщения, а не язык программирования: smile.gif

while (GetMessage(AMessage, 0, 0, 0)) do begin
TranslateMessage(AMessage);
DispatchMessage(AMessage);

KljaGGsa
Хм, но что-то цель не получилось достичь. Прямое обращение к функциям операционки по идее должно дать быструю и эффективную (плавную) работу, а шарик на экране движется явно не лучше, чем если бы я его нарисовала эллипсом в канвасе и закрашивала бы каждый раз при единичном перемещении. Дискретность и дрыганье - те же самые...
volvo
Цитата
сразу бросился в глаза и удивил - какие-то сплошные сообщения, а не язык программирования:
Вот именно это и есть основной цикл обработки сообщений. Перевожу на русский:
пока (есть_сообщения_для_окна)
транслировать_сообщение;
переслать_сообщение_оконной_функции;
А уже внутри оконной функции (та самая MainWndProc) анализируем, собственно, какое сообщение было получено, и что надо делать в связи с его получением.

P.S. А вот тут была? http://www.firststeps.ru/mfc/winapi/r.php?51 Там хоть и С рассматривается, но принцип работы Win-приложения прояснится...

Добавлено через 1 мин.
Цитата
шарик на экране движется явно не лучше, чем если бы я его нарисовала эллипсом в канвасе и закрашивала бы каждый раз при единичном перемещении. Дискретность и дрыганье - те же самые...
Тебе записать видео, или ты поверишь, что никакого дерганья я у себя не наблюдаю? И с чем оно связано - не знаю.

Добавлено через 14 мин.
Цитата
шарик на экране движется явно не лучше, чем если бы я его нарисовала эллипсом в канвасе и закрашивала бы каждый раз при единичном перемещении.
Кстати, вопрос на засыпку: с чего ты взяла, что на WinAPI должно быть ЛУЧШЕ? То же самое рисование на канвасе, то же самое перемещение (только не единичное, а 5-ти единичное, что может послужить причиной "дерганья", нет DoubleBuffered, что тоже не улучшает визуализацию). Ты меня извини, конечно, но писать здесь полный код, работающий идеально, я считаю нецелесообразным. По нескольким причинам. Главная из которых - если тебя ЭТО уже вводит в ступор, то я представляю, куда тебя введет более сложный код.

Цитата
что-то цель не получилось достичь
Целью было написание приложения, перемещающего изображение мяча горизонтально, от одной стенки к другой. Про плавность перемещения и его идеальность речи не было. Если тебя это не устраивает - делай сама, больше мешать тебе своими постами не буду.

Удачи.
Client
По той ссылке код для Си а примерах, а те функции и на Delphi работают? И только для консольного приложения или для VCL тоже?
KljaGGsa
Владимир, прямое обращение к функциям ОС меня заинтересовало потому что Вы здесь на форуме утверждали, что это принципиальная экономия тактов и загрузки процессора, а следовательно и увеличение быстродействия программы. Использовать WinAPI правильнее, чем пытаться оптимизировать алгоритмы в графических VCL. Теперь буду пытаться разобраться, на каком этапе возникает дискретность анимации. В моем варианте мячик пинг-понга движется с видимыми хотя и незначительными рывками примерно одинаково что в канвасе пейнтбокса, что в нарисованном Вами консольном поле. Процессор Core Duo Pro с соответствующей тактовой частотой, на который грех жаловаться, другие программы отключены, резидентно висит только самый необходимый минимум. И очень огорчаюсь, если Вас чем-то ненароком обидела .. blink.gif
Unconnected
Дерганье и правда присутствует, даже не дёрганье, а перемещение мячика как бы маленькими рывками. Это хорошо заметно, если поставить интервал таймера равным 500, например. Но для учебных целей этого более чем достаточно, по моему:) На WinAPI вроде бы программы ещё маленькие получаются...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.