Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > Низкоуровневое программирование > Win Api
Регистрация

Восстановить пароль
Повторная активизация e-mail

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 25.11.2022, 14:38   #11
apofioz
Форумчанин
 
Регистрация: 22.01.2014
Сообщений: 313
По умолчанию

Интересно, в секции сообщения windows WM_CREATE я правильно рисую в bimap-е или нужно иначе рисовать? Вроде бы работает, но не знаю, работает так как нужно или нет..
Код:
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	static int cxClient, cyClient, cxChar, cyChar;
	PAINTSTRUCT ps;
	
	TCHAR szString[] = TEXT("Interesting, how are you name");

	static HBITMAP hBitmap;
	static HDC memDC, hdc;

	switch (msg)
	{
	case WM_CREATE:
	{
		if (!SetTimer(hwnd, ID_TIMER, 50, NULL))
			return FALSE;
		TEXTMETRIC tm;
		HDC hdc = GetDC(hwnd);
		SelectObject(hdc, GetStockObject(SYSTEM_FIXED_FONT));

		GetTextMetrics(hdc, &tm);
		cxChar = tm.tmAveCharWidth;
		cyChar = tm.tmHeight + tm.tmExternalLeading;

		memDC = CreateCompatibleDC(hdc);
		hBitmap = CreateCompatibleBitmap(hdc, lstrlen(szString) * cxChar,
			(cyChar << 1));
		//SetBitmapBits(hBitmap, lstrlen(szString), (LPVOID)&szString);

		//BITMAP bm;
		//GetObject(hBitmap, sizeof(bm), (LPVOID)&bm);

		SelectObject(memDC, hBitmap);
		TextOut(memDC, 0, 0, szString, lstrlen(szString));

		ReleaseDC(hwnd, hdc);

		return 0;
	}
	case WM_SIZE:
	{
		cxClient = LOWORD(lParam);
		cyClient = HIWORD(lParam);

		return 0;
	}
	
	case WM_PAINT:
	{
		BeginPaint(hwnd, &ps);
		EndPaint(hwnd, &ps);
		return 0;
	}
	case WM_TIMER:
	{
		switch (wParam)
		{
			case ID_TIMER:
			{
				//InvalidateRect(hwnd, NULL, FALSE);
				static int idx = 0 /*(lstrlen(szString) * cxChar) - 1*/;
				hdc = GetDC(hwnd);
				//HBRUSH hBrush = CreateSolidBrush(RGB(255, 0, 0));
				//HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush);
				
				
				BitBlt(hdc, 10, 30, idx /*lstrlen(szString)* cxChar*/,
					cyChar, memDC, 0, 0, SRCCOPY);
			

				
				idx++;
				if (idx >= (lstrlen(szString) * cxChar))
				{
					idx = 0 /*(lstrlen(szString) * cxChar) - 1*/;
					BitBlt(hdc, 10, 30, lstrlen(szString)* cxChar,
						cyChar, hdc, 0, 0, WHITENESS);
					
					
				}
				
				ReleaseDC(hwnd, hdc);
				break;
			}
			default:
				break;

		}
		return 0;
	}
	case WM_DESTROY:
	{
		DeleteDC(memDC);
		DeleteObject(hBitmap);
		KillTimer(hwnd, ID_TIMER);
		PostQuitMessage(0);
		return 0;
	}
	}
	return DefWindowProc(hwnd, msg, wParam, lParam);
}
apofioz вне форума Ответить с цитированием
Старый 25.11.2022, 18:09   #12
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Цитата:
Сообщение от apofioz Посмотреть сообщение
Так? Это, что вы имели ввиду под: "Вычисляете размер области полностью напечатанного текста и создаете bitmap размером с 2 строки этого текста. Далее на bitmap рисуете текст постепенно уменьшая координату x у букв, а на экран копируете часть bitmap содержащую только верхнюю строку."
Насколько я понял, то вам необходимо создать анимацию всплывания текста. Тогда у вас есть шкала времени t и уравнение движения текста в зависимости от времени (y = y0 - dy * t). Это реализуется последовательной перерисовкой по таймеру, а t можно отслеживать через GetTickCount.

Далее реализация анимации. Для начала подготовка: при создании формы вычисляете DrawText(..., DT_CALCRECT) - ширину в высоту текста, который будет нарисован и увеличиваете размеры этой области в два раза по высоте. Создаете bitmap по этим размерам и будете использовать его как back-буфер для создания анимации (вторым способом можно включить двойную буферизацию на форме, чтобы не мерцало).

При перерисовке для начала весь текст (после можно сделать каждый символ в отдельности) рисуете на этом bitmap при этом вычисляя его положение в зависимости от времени. А затем BitBlt копирует верхнюю половину bitmap в нужную позицию экрана. Таким образом часть символов обрезается по этой границы и создается эффект плавного всплытия.

Когда получится со строкой целиком, то можете добавить массив координат для каждого отдельного символа и используя все те же формулы усложнить работу анимации добавив задержку всплытия между каждым отдельным символом. Таким образом текст будет всплывать последовательно.
macomics вне форума Ответить с цитированием
Старый 26.11.2022, 06:33   #13
apofioz
Форумчанин
 
Регистрация: 22.01.2014
Сообщений: 313
По умолчанию

Цитата:
Сообщение от macomics Посмотреть сообщение
Насколько я понял, то вам необходимо создать анимацию всплывания текста.
Текст медленно "выплывает" слева направо.

Таймер я создал, но хоть убей не понимаю, как функцию написать, чтобы всё работало, да ещё с таймером, не понимаю... т.е. если я захочу использовать эту функцию, прежде, мне нужно создать таймер, так получается, а не просто вызвать её с заданными аргументами, как обычно и делают. Ну да ладно, это всё лирика.


Цитата:
Сообщение от macomics Посмотреть сообщение
Тогда у вас есть шкала времени t и уравнение движения текста в зависимости от времени (y = y0 - dy * t). Это реализуется последовательной перерисовкой по таймеру, а t можно отслеживать через GetTickCount.
Получить время GetTickCount() сравнить с чем-то его, сохранить как текущее время, но не ясно, зачем таймер вызывается, что ещё надо...


Цитата:
Сообщение от macomics Посмотреть сообщение
при создании формы вычисляете DrawText(..., DT_CALCRECT) - ширину в высоту текста,
Я вычисляю с помощью GetTextExtentPoint32(), есть какая-то разница? Я использую для вывода TextOut, как вы могли увидеть из моих сообщений.

Цитата:
Сообщение от macomics Посмотреть сообщение
Создаете bitmap по этим размерам и будете использовать его как back-буфер для создания анимации (вторым способом можно включить двойную буферизацию на форме, чтобы не мерцало).
Я это сделал, разве нет, про двойную буферизацию, тут всё сложно, не понимаю я этого. Но BITMAP создал.


Цитата:
Сообщение от macomics Посмотреть сообщение
При перерисовке для начала весь текст (после можно сделать каждый символ в отдельности) рисуете на этом bitmap при этом вычисляя его положение в зависимости от времени.
Я вообще ничего не понял) Рисуете на bitmap - это как, с помощью функции TetxOut и тому подобных, если так, то получется я должен рисовать часть текста(или букву или часть буквы) в BITMAP-е только по обработчику сообщения WM_TIMER? иЛИ, КАК ВСЁ ЭТО ДОЛЖНО ПРОИСХОДИТЬ и самое главное где, в функцию я это не запихну, как мне кажется, короче говоря я не знаю с чего начинать. я запутался.
apofioz вне форума Ответить с цитированием
Старый 26.11.2022, 10:37   #14
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Цитата:
Сообщение от apofioz Посмотреть сообщение
Текст медленно "выплывает" слева направо.

Таймер я создал, но хоть убей не понимаю, как функцию написать, чтобы всё работало, да ещё с таймером, не понимаю... т.е. если я захочу использовать эту функцию, прежде, мне нужно создать таймер, так получается, а не просто вызвать её с заданными аргументами, как обычно и делают. Ну да ладно, это всё лирика.
Таймер вам нужен один и только для постоянной перерисовки окна. GetTickCount при каждой перерисовке обеспечит прирастающий счетчик времени (ось t). Надо лишь выделить переменную на каждый объект со всплывающим текстом, в которой запоминать значение GetTickCount для начала анимации.

Цитата:
Сообщение от apofioz Посмотреть сообщение
Получить время GetTickCount() сравнить с чем-то его, сохранить как текущее время, но не ясно, зачем таймер вызывается, что ещё надо...
Чтобы обеспечить периодические вызовы обработчика перерисовки окна. В противном случае об будет вызываться лишь изредка при изменениях размеров окна или перерисовке перекрытой ранее области. Так вы не увидите анимацию, которой надо чтобы обработчик перерисовки отрисовывал несколько кадров в секунду.

Цитата:
Сообщение от apofioz Посмотреть сообщение
Я вычисляю с помощью GetTextExtentPoint32(), есть какая-то разница? Я использую для вывода TextOut, как вы могли увидеть из моих сообщений.
Это не важно, просто DrawText работает со структурой TRect и мне она больше нравится. Если вы можете вычислить размеры текста другими средствами, тогда дело ваше. Главное добиться описанного: создать задний буфер, в котором поместиться по размеру две строки текста.

Цитата:
Сообщение от apofioz Посмотреть сообщение
Рисуете на bitmap - это как, с помощью функции TetxOut
Да. Для этого надо сначала еще создать временный HDC через CreateCompatibleDC и при помощи SelectObject соединить его с bitmap. Потом можно будет использовать этот hdc для рисования на bitmap и переносе пикселей с нее на hdc формы (через BitBlt(hSrcDC <- в качестве этого параметра, ...)).

Цитата:
Сообщение от apofioz Посмотреть сообщение
если так, то получется я должен рисовать часть текста(или букву или часть буквы) в BITMAP-е только по обработчику сообщения WM_TIMER?
Нет. Это все уже надо рисовать в WM_PAINT. А одну bitmap можно использовать для вывода всех параллельных анимаций текста. Отсечение букв произойдет за счет частичного копирования bitmap на форму, поэтому рисовать часть символов не надо. См. картинку.

Код:
TPoint textPos[textCount];
char *textArray[textCount];
int startTime[textCount]; // Естественно все эти три массива можно объединить в структуру. Но я преследую цель показать как сделать, а не сделать как лучше написать за вас.

void drawAnimatedText(HDC wnd, // dc окна (или другого объекта) для вывода анимации
    HDC bmp, // dc back-буфера для рисования текста
    int x, int y, // Координаты в окне для левого верхнего угла анимации
    DWORD start, // Время старта анимации. Переназначая это значение в новое значение GetTickCount можно перезапускать анимацию
    char *text) { // Текст для анимации
// Это для всего текста. Для анимации каждого символа это надо повторить в цикле и соблюсти промежутки в движении каждого символа.
  int copy_width = GetMaxTextWidth(bmp, &text, 1), copy_height = GetMaxTextHeight(bmp, &text, 1);
  int pos = 5 + copy_height - (GetTickCount + start) / 10;
  TextOut(bmp, 0, min(pos, 0), text); // Когда пройдет времени больше чем нужно для анимации текст остановится на y = 0 (замрет в верхней точке).
// (GetTickCount + start) / 10 = 100 кадров в секунду и 1 пиксель на кадр т.е. скорость 100 пикселей в секунду
// (GetTickCount + start) / 40 = 25 кадров в секунду и 1 пиксель на кадр т.е. скорость 25 пикселей в секунду
  BitBlt(wnd, x, y, copy_width, copy_height, bmp, 0, 0, SRCCOPY);
}
...
switch (uMsg) {
  case WM_CREATE: dc = GetDC(hWnd);
// Лень писать, но по названию понятно, что функции GetMaxTextWidth и GetMaxTextHeight должны вычислить максимальные размеры текста в пикселях для массива textArray
    tmp = CreateCompatibleDC(dc);
    bmp = CreateCompatibleBitmap(tmp, GetMaxTextWidth(dc, textArray, textCount), 2 * GetMaxTextHeight(dc, textArray, textCount) + 5); 
    SelectObject(tmp, bmp); // Старый объект можно не сохранять и не высвобождать. Он все равно равен nil
    ReleaseDC(hWnd, dc);
    SetTimer(hWnd, 1, 10, nil); // Не более 100 кадров в секунду. Вызов каждую 0,01 секунды.
    break;
  case WM_TIMER: InvalidateRect(hWnd, nil, FALSE); break;
  case WM_PAINT:
    dc = BeginPaint(hWnd, ps);
// Столько анимированного текста сколько размещено элементов в массивах. (т.е. textCount штук)
    for (int i = 0; i < textCount; ++i)
       drawAnimatedText(dc, tmp, textPos[i].x, textPos[i],y, startTime[i], textArray[i]);
    EndPaint(hWnd, ps);
    break;
}
Надеюсь с видимостью переменных и их типами вы разберетесь.

Последний раз редактировалось macomics; 26.11.2022 в 10:56.
macomics вне форума Ответить с цитированием
Старый 26.11.2022, 14:27   #15
apofioz
Форумчанин
 
Регистрация: 22.01.2014
Сообщений: 313
По умолчанию

Цитата:
Сообщение от macomics Посмотреть сообщение
Таймер вам нужен один и только для постоянной перерисовки окна.
По моему вы меня не поняли я имел ввиду, что функция, даже, если я её напишу будет требовать таймера при использовании, а это заведомо , плохо т.е. как я хочу использовать функцию:
Код:
DrawPopUpTetx(hdc, 10, 10, "Тётя-мотя", 8)
и всё, не объявлять таймеры и прочие битмапы, контексты памяти... И, если скрыть объявление инициализацию всего вышеперечисленного можно, то, как поступить с задержкой т.е. таймер в функцию не запихнёшь.

TPoint textPos[textCount]; //позиции и где их вычислять, с этим не разобраться
char *textArray[textCount]; //Здесь текст
int startTime[textCount]; //здесь что, забить значениями GetTickCount();

Кроме как массив текста остальное не очевидно от слова совсем. Значения для массива startTime тоже вычислять в БЛОКЕ СООБЩЕНИЯ WM_CREATE:?
textPos - я так и не понял, зачем этот массив, для каждого символа вычислять позицию? А если мне нужно вызвать функцию раз десять в программе т.к. нужно вывести результаты участников некоторого события, тогда что, для каждого участника заполнять всё это, не слишком ли много работы...

Код:
case WM_CREATE:
			
			hdc = GetDC(hwnd);
			int x = 10, y = 10, NextChar;
			for(int i = 0; i < STRINGSIZE; ++i)
			{
				startTime[i] = GetTickCount();
				textPos[] = { x, y };
				GetTextWidth32(hdc, lpString[i], lpString[i], &NextChar); //вычисляю позицию следующего символа
				x += NextChar;
			}
			ReleaseDC(hwnd, hdc);
			return 0;
Думаю, так, хотя по startTime не уверен.
apofioz вне форума Ответить с цитированием
Старый 26.11.2022, 14:37   #16
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Цитата:
Сообщение от apofioz Посмотреть сообщение
и всё, не объявлять таймеры и прочие битмапы, контексты памяти... И, если скрыть объявление инициализацию всего вышеперечисленного можно, то, как поступить с задержкой т.е. таймер в функцию не запихнёшь.
Вы мой пример видели. У меня таймер инициализируется при WM_CREATE. А для запуска анимации достаточно в переменную startTime записать значение GetTickCount и анимация запустится. Закончится она когда разница между значением в переменной startTime и возвращаемым из GetTickCount превысит количество пикселей, на которое поднимается текст. Т.е. для прекращения анимации достаточно обнулить startTime.
macomics вне форума Ответить с цитированием
Старый 26.11.2022, 14:38   #17
apofioz
Форумчанин
 
Регистрация: 22.01.2014
Сообщений: 313
По умолчанию

Цитата:
for (int i = 0; i < textCount; ++i)
drawAnimatedText(dc, tmp, textPos[i].x, textPos[i],y, startTime[i], textArray[i]);
EndPaint(hWnd, ps);
Вы же передаёте а функцию символ, как этот эффект должен проявиться я не вижу в функции особых манипуляций по этому поводу, если только здесь:
Код:
int pos = 5 + copy_height - (GetTickCount + start) / 10;
apofioz вне форума Ответить с цитированием
Старый 26.11.2022, 14:43   #18
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Цитата:
Сообщение от apofioz Посмотреть сообщение
TPoint textPos[textCount]; //позиции и где их вычислять, с этим не разобраться
Задавайте какие хотите. Где у вас на форме должна отображаться эта анимация такие координаты и задавайте.

Цитата:
Сообщение от apofioz Посмотреть сообщение
int startTime[textCount]; //здесь что, забить значениями GetTickCount();
Когда нужно запустить нужную анимацию, тогда записываете сюда значение GetTickCount и она стартует. Если ее надо прервать, тогда обнуляете.

Цитата:
Сообщение от apofioz Посмотреть сообщение
textPos - я так и не понял, зачем этот массив, для каждого символа вычислять позицию?
Нет. Для каждого анимированного текста на форме. Я вам изобразил не один текст, а набор текстов. Их может быть хоть 100500 и они все будут выводиться через один и тот же bitmap и SetTimer.


Цитата:
Сообщение от apofioz Посмотреть сообщение
for(int i = 0; i < STRINGSIZE; ++i)
{
startTime[i] = GetTickCount();
textPos[] = { x, y };
GetTextWidth32(hdc, lpString[i], lpString[i], &NextChar); //вычисляю позицию следующего символа
x += NextChar;
}
Можно конечно изобразить каждый символ строки как отдельную анимацию, но лучше это сделать в функции drawAnimatedText. А в массивы заполнить сразу строки.
macomics вне форума Ответить с цитированием
Старый 26.11.2022, 14:45   #19
macomics
Участник клуба
 
Регистрация: 17.04.2022
Сообщений: 1,833
По умолчанию

Цитата:
Сообщение от apofioz Посмотреть сообщение
Вы же передаёте а функцию символ, как этот эффект должен проявиться я не вижу в функции особых манипуляций по этому поводу, если только здесь:
Так это вычисляет координаты текста на bitmap. А textPos это координаты анимации в окне.

Я еще забыл вызвать FillRect(bmp, rct); для очистки bitmap от старого текста.

animation указывает на координаты задаваемые через textPos[i]
back bitmap это картинка, которая будет нарисована в памяти
pos это те самые вычисления координат
На форме нарисован текст частично всплывший после запуска анимации. Пока вся строка целиком. Возиться с каждым отдельным символом пока не хочу.
Изображения
Тип файла: png forma_anim.png (13.0 Кб, 11 просмотров)

Последний раз редактировалось macomics; 26.11.2022 в 15:09.
macomics вне форума Ответить с цитированием
Старый 26.11.2022, 14:48   #20
apofioz
Форумчанин
 
Регистрация: 22.01.2014
Сообщений: 313
По умолчанию

Цитата:
Сообщение от macomics Посмотреть сообщение
Вы мой пример видели.
Я его уже пересмотрел хз сколько раз и startTime это массив, а не переменная. Я не знаю, по-моему вы тоже мой вопрос не поняли, а то, что не понял я, спросил.
Ьл есть этот пример, который вы дали, он у вас работает?
apofioz вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Необходимо написать "таймер", который будет запускаться при нажатии кнопки "Start", приостанавливаться на "Pause", и сбрасываться на "Reset" billiejean78 JavaScript, Ajax 1 03.09.2021 08:58
Убрать папки "Pictures", "Music", "Видео", "Downloads" из "МОЙ КОМПЬЮТЕР" Бахтиёр1916 Windows 1 05.04.2017 12:53
Нужно пояснить/прокомментировать код программы, или коды функций "Добавить" "Удалить" "Обновить(редактировать" "Поиск" "Период") ZIRASS PHP 4 15.06.2016 14:23
Поиск компонента GroupBox с эффектом "спойлер" XerSon Компоненты Delphi 1 24.03.2011 09:59