Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   [решено] GDI+ рисование на статике-перерисовка "заново" (http://forum.oszone.net/showthread.php?t=164575)

crashtuak 25-01-2010 10:43 1329193

GDI+ рисование на статике-перерисовка "заново"
 
Как можно нарисовав на статике одно изображение с прозрачностью, зарисовать его другим, тоже с прозрачностью, тоесть удалить первое изображение?
(если рисовать сразу поверх первого изображения, то прозрачные части первого совмещаются с прозрачными второго)
Я думаю, может сначала зарисовать белым фоном, но то как то кустарно выйдет...

pva 25-01-2010 13:33 1329330

Цитата:

Цитата crashtuak
но то как то кустарно »

Если имеется ввиду мелькание при заливке, то можно включить двойную буфферизацию. Либо сделать изображение непрозрачным сразу

crashtuak 25-01-2010 14:00 1329358

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

pva 25-01-2010 15:52 1329456

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

crashtuak 25-01-2010 17:48 1329549

Код:

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);
        }
       
}

Скриншот(как выходит):

Скриншот(как должно быть):

Тоесь мне надо отрисовать button.png, и по ходу выполнения программы на место button.png (именно на место, а не поверх) отрисовать button2.png.

pva 25-01-2010 23:20 1329858

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

crashtuak 26-01-2010 07:52 1330052

pva, мне надо именно с прозрачностью, и с замысловатыми границами...

crashtuak 26-01-2010 12:27 1330191

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

Admiral 26-01-2010 13:47 1330272

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

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

Понемногу осваиваюсь с прямой работой с GDIplus (до этого имел дело через .NET врапер).
Уже функцию с темы exe в скринсейвер на 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 1330285

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

crashtuak 26-01-2010 14:29 1330311

Только вот при InvalidateRect появляется мерцание...

pva 26-01-2010 20:17 1330638

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

Цитата crashtuak
Только вот при InvalidateRect появляется мерцание... »

с мерцанием борются WS_EX_COMPOSITED - двойная буферизация

crashtuak 26-01-2010 20:47 1330668

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

pva 26-01-2010 23:49 1330853

А, вот ещё вспомнил, у борланда своё понимание корректности работы с WinAPI и скорости выполнения кода. В билдере
Код:

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

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


Время: 17:49.

Время: 17:49.
© OSzone.net 2001-