Войти

Показать полную графическую версию : [решено] GDI+ рисование на статике-перерисовка "заново"


crashtuak
25-01-2010, 10:43
Как можно нарисовав на статике одно изображение с прозрачностью, зарисовать его другим, тоже с прозрачностью, тоесть удалить первое изображение?
(если рисовать сразу поверх первого изображения, то прозрачные части первого совмещаются с прозрачными второго)
Я думаю, может сначала зарисовать белым фоном, но то как то кустарно выйдет...

pva
25-01-2010, 13:33
но то как то кустарно »
Если имеется ввиду мелькание при заливке, то можно включить двойную буфферизацию. Либо сделать изображение непрозрачным сразу

crashtuak
25-01-2010, 14:00
Нет, не мерцание. Вот вся ситуация: на окне программы я нарисовал картинку, положил на окно программы Static, далее в статике я нарисовал полупрозрачное изображение. Далее я хочу стереть нарисованное изображение в Static, и на его место нарисовать другое полупрозрачное изображение(если не стереть старое, то два изображения просто накладываются одно на другое).

pva
25-01-2010, 15:52
В смысле UpdateWindow сделать (перерисовать фон перед отрисовкой изображения на нём)? я не понял, можно кусочек кода? (со скриншотом)

crashtuak
25-01-2010, 17:48
hdc = BeginPaint(hhstatic1, &ps);
OnPaint(hdc, 2);
OnPaint(hdc, 3);
EndPaint(hhstatic1, &ps);
Ф-ция OnPaint:
VOID OnPaint(HDC hdc, int imagee)
{

if (imagee==2){
Graphics graphics(hdc);
Image image(L"E:\\TMP2\\button.png");
graphics.DrawImage(&image, 0, 0);
}
if (imagee==3){
Graphics graphics(hdc);
Image image(L"E:\\TMP2\\button2.png");
graphics.DrawImage(&image, 0, 0);
}

}
Скриншот(как выходит):
http://img710.imageshack.us/img710/3572/16527576.png (http://img710.imageshack.us/i/16527576.png/)
Скриншот(как должно быть):
http://img690.imageshack.us/img690/1705/2222wd.png (http://img690.imageshack.us/i/2222wd.png/)
Тоесь мне надо отрисовать button.png, и по ходу выполнения программы на место button.png (именно на место, а не поверх) отрисовать button2.png.

pva
25-01-2010, 23:20
Понадобится объект, который ограничивает область действия.
Варианты:
1) использовать обрезку (clipping with region) - годится для простых форм (без прозрачности, с не сильно замысловатыми границами)
2) использовать чёрно-белое изображение смешивания (маску). Суть: в чёрный экран копируем A*image1 + (1-A)*image2, где A - изображение, на котором пиксели вне границ кнопки имеют белый цвет, в границах - чёрный; (1-A) - инвентированное A; image1 - изображение фона (кнопки); image2 - фон с наложенной сверху полупрозрачной картинкой (Скриншот "как выходит")
оказывается второй способ прокатывает только для GDI и Direct3D

crashtuak
26-01-2010, 07:52
pva, мне надо именно с прозрачностью, и с замысловатыми границами...

crashtuak
26-01-2010, 12:27
Придумал вот так-на форме два статика, в каждом своя картинка. По ходу выполнения кода я скрываю один статик, а показываю второй, НО нарисованное остается, надо либо перетянуть окно, либо изменить его размеры, что бы оно обновилось... А как можно окно обновить программно?

Admiral
26-01-2010, 13:47
crashtuak, например вызвать InvalidateRect в первом параметре указав хендл статика, который нужно перерисовать (тем самым форсировав событие WM_PAINT для этого окна). Или UpdateWindow, про который вспоминал pva в 4м сообщении темы. Ещё вариант с подмигиванием - скрыть и отобразить окно.

pva, если бы второй способ работал, это бы было бы решением для темы *GdiPlus*| маски прозрачности (http://forum.oszone.net/thread-154990.html)?
Считаю что для того, что б добиться результата со второго скрина от crashtuak, как раз и нужно применять маску. Да вот похоже такой встроенной функции в GDIplus нет, так что остаётся вариант по пиксельной обработки (а он достаточно медленный).
Два изображения имеют одинаковые размеры, во втором, где проходят чёрные линии (линии маски), в первом по этим же координатам пиксели должны становится прозрачными.
Вот только пока не знаю, как задать конкретному пикселю в изображении, что он должен быть прозрачным.

Понемногу осваиваюсь с прямой работой с GDIplus (до этого имел дело через .NET врапер).
Уже функцию с темы exe в скринсейвер (http://forum.oszone.net/thread-157335.html) на GdiPlus перенёс. void GeneratorTsvetnyhPolos_GdiPlus(HDC *hDc, RECT *rectBar, int OffSet)
{
Graphics g(*hDc);
g.SetPageUnit(UnitPixel);

g.FillRectangle(new SolidBrush(Color(255, 255, 255, 255)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 196, 196, 0)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 0, 196, 196)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 0, 196, 0)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 196, 0, 196)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 196, 0, 0)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 0, 0, 196)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
rectBar->left = rectBar->right;
rectBar->right += OffSet;
g.FillRectangle(new SolidBrush(Color(255, 0, 0, 0)), Rect (rectBar->left, rectBar->top, rectBar->right, rectBar->bottom));
}

crashtuak
26-01-2010, 14:04
Admiral, ни InvalidateRect ни UpdateWindow не помогает. Отрисовывается как надо только, например, при расположении какого нибудь другого окна над окном нашей программы...
--------------------------------------------------------------------
Извеняюсь, InvalidateRect обновило окно...

crashtuak
26-01-2010, 14:29
Только вот при InvalidateRect появляется мерцание...

pva
26-01-2010, 20:17
Admiral, по поводу масок прозрачности, если принципиальна скорость выполнения и много работы с перемножением картинок, а также не жалко ресурсов, то можно использовать d3d (совместно с GDI+ можно через поверхности IDirect3DSurface7, а можно и без GDI+). Я делал проигрыватель видеороликов "картинка в картинке", а-ля назойливая реклама в телеке. 1280x1024@30fps, GDI+ полностью загружает одно ядро, а d3d (перебрал все виды альфаблендинга) процентов на 5-10.
Если требуется небольшая картинка и скорость смены кадров 1-2 fps, то врукопашную перемножить 2 массива сгодится.
С d3d алгоритм такой: на скрытую поверхность копируем часть экана, делаем что надо, копируем обратно. Окно, к которому привязан объект d3d - не показываем. В более поздних directX это сделано в Direct2D
Только вот при InvalidateRect появляется мерцание... »
с мерцанием борются WS_EX_COMPOSITED - двойная буферизация

crashtuak
26-01-2010, 20:47
pva, c WS_EX_COMPOSITED вообще ничего не рисуется на форме... но то уже другая история:). Все мои запросы удовлетворила InvalidateRect(перерисовываю только нужную область, а не весь экран, потому и мерцания невидно).

pva
26-01-2010, 23:49
А, вот ещё вспомнил, у борланда своё понимание корректности работы с WinAPI и скорости выполнения кода. В билдере

__fastcall TForm1::TForm1(TComponent* Owner)
: TForm(Owner)
{
DoubleBuffered = true;
}

если с GDI+ не сработает, то я сдаюсь




© OSzone.net 2001-2012