PotatoSoup Ответов: 4

В C++11 можно ли предварительно обработать пользовательскую область формы?


C++11. Нет, нет. Не VC++.

Я могу создать область со следующими параметрами и выбрать ее части для использования в качестве пользовательской области формы для диалогового окна.

Я использую большой графический bmp, который занимает следующее долгое время, чтобы преобразовать в пользовательскую область формы, которую я использую для пользовательского диалогового окна формы.

Мой вопрос заключается в следующем

void createSomeRegion(HWND hwndDlg) // This handle is of the DialogBox.
    {
        //Get the destination device context
        hdcDestDC = GetDC(hwndDlg);

        //Create a memory DC
        hdcMem_001 = CreateCompatibleDC(nullptr);

//        //To Load from resource.rc as a DIB Device Independent Bitmap
//            HANDLE hBitmap__001 = LoadImage (GetModuleHandle(nullptr), MAKEINTRESOURCE( IDB_TestMasked02), IMAGE_BITMAP, 0, 0, LR_CREATEDIBSECTION);
//
//            if(hBitmap__001 == NULL)
//                {
//                    MessageBox(hwndDlg, L"Could not load BITMAP from resource!", L"Error", MB_OK | MB_ICONEXCLAMATION);
//                }

        //To Load from a file.
            // HANDLE hBitmap__001 = (HBITMAP)LoadImage(GetModuleHandle(nullptr), L"a.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION);
            //if(!hBitmap__001)
            //    {
            //        //handle error here
            //        return;
            //    }

        //Get information about the bitmap..
        GetObject(hBitmap__001, sizeof(bmpInfo_001), &bmpInfo_001);	// Get info about the bitmap

        //Select the bitmap into the dc
        SelectObject(hdcMem_001, hBitmap__001);

        //Create an empty region
        hRgn_001 = CreateRectRgn(0,0,0,0);

        //Create a region from a bitmap with transparency color of white
        //change the pixel values for a different transparency color
        //ex - RGB(0,0,0) will mean a transparency color of black.. so the areas
        //of the bitmap not used to create the window will be black

        COLORREF crTransparent = RGB(255, 255, 255);  // To be transparent.

        int iX = 0;
        int iY = 0;
        int iRet = 0;

        for ( iY = 0; iY < bmpInfo_001.bmHeight; iY++)
            {
                do
                    {
                        //skip over transparent pixels at start of lines.
                        while (iX < bmpInfo_001.bmWidth && GetPixel(hdcMem_001, iX, iY) == crTransparent)
                            {
                                iX++;
                            }

                        //remember this pixel
                        int iLeftX = iX;

                        //now find first non transparent pixel
                        while (iX < bmpInfo_001.bmWidth   && GetPixel(hdcMem_001, iX, iY) != crTransparent)
                            {
                                ++iX;
                            }

                        //create a temp region on this info
                        HRGN hRgnTemp = CreateRectRgn(iLeftX, iY, iX, iY+1);

                        //combine into main region.
                        //    int CombineRgn
                        //        (
                        //            HRGN hrgnDst,     // A handle to a new region with dimensions defined by combining two other regions. (This region must exist before CombineRgn is called.)
                        //            HRGN hrgnSrc1,    // A handle to the first of two regions to be combined.
                        //            HRGN hrgnSrc2,    // A handle to the second of two regions to be combined.
                        //            int  iMode        // A mode indicating how the two regions will be combined.
                        //
                        iRet = CombineRgn(hRgn_001, hRgn_001, hRgnTemp, RGN_OR);

                        if(iRet == ERROR)
                            {
                                return;
                            }
                        //delete the temp region for next pass
                        DeleteObject(hRgnTemp);
                    }
                while(iX < bmpInfo_001.bmWidth);    // Completing a Do While loop.
                                                // This is not a "while for the next line".

                iX = 0;
            }
//////
//////        //Center it on current desktop
//////        iRet = SetWindowRgn(hwndDlg, hRgn_001, TRUE);
//////
//////        if(!iRet)
//////            {
//////                // messagebox stating that this did not work...
//////                return;
//////            }


//// Create a reusable rectangular region.
//hReusableRectangularRegion = CreateRectRgn(0,0,100,100);
//
//// Create a temporary brush for a temporary rectangular region.
//HBRUSH hBrushTmporary1 = CreateSolidBrush(RGB(255, 0, 0));

//BOOL FillRgn(
//  HDC    hdc,
//  HRGN   hrgn,
//  HBRUSH hbr
//);

//FillRgn(HDC_of_MainWindow, hReusableRectangularRegion, hBrushTmporary1);
//
//// The temporary brush is no longer needed. Delete it to free the allocated memory that it is using.
//DeleteObject(hBrushTmporary1);


///


int x = 0;
int y = 4;
//int i = OffsetRgn(hReusableRectangularRegion, (n*47)+(n),(n*47)+(n));
int i = OffsetRgn(hReusableRectangularRegion, (x*47)-x,(y*47)-y);
//int i = OffsetRgn(hReusableRectangularRegion, 0,0);


iRet = CombineRgn(hRgn_001, hRgn_001, hReusableRectangularRegion, RGN_AND);



        //Center it on current desktop
        iRet = SetWindowRgn(hwndDlg, hRgn_001, TRUE);

        if(!iRet)
            {
                // messagebox stating that this did not work...
                return;
            }


//        iX = ((GetSystemMetrics(SM_CXSCREEN)) / 2) - (bmpInfo_001.bmWidth / 2 + 50);
//        iY = ((GetSystemMetrics(SM_CYSCREEN)) / 2) - (bmpInfo_001.bmHeight / 2 + 50);

//        iRet = SetWindowPos(hwndDlg, HWND_TOPMOST, iX, iY, bmpInfo_001.bmWidth, bmpInfo_001.bmHeight, 0);
        iRet = SetWindowPos(hwndDlg, HWND_TOPMOST, 300, 300, bmpInfo_001.bmWidth, bmpInfo_001.bmHeight, 0);

        //Copy the memory dc into hdcDestDC
        paintRegion_001();

        //delete the bitmap
        DeleteObject(hBitmap__001);
    }


Что я уже пробовал:

C++11. Нет, нет. Не VC++.

Я попытался найти более быстрое создание пользовательского региона, но не нашел его.

Я попробовал проверить время, которое требуется для преобразования большого растрового изображения в пользовательскую область и использования для немодального диалога, и это выглядит примерно 10-15 секунд. Это слишком долго.

Я попытался выяснить, как предварительно обработать пользовательский регион, но мне не ясно, как это сделать.

Я попробовал #void createSomeRegion(HWND hwndDlg), но это не сработало.

Я хочу иметь возможность обрабатывать большую графику (bmp) в пользовательскую область и включать эту уже обработанную область в мой окончательный автономный исполняемый файл, который я могу использовать без необходимости идти пиксель за пикселем при запуске exe-файла.

Я бродил по разным пустошам .net и VC++, изголодавшись по настоящему C++ - коду.

Спасибо за вашу помощь с ответами на C или до C++11.

Patrice T

Какой вид формы вы ожидаете для пользовательского региона ?
Прямоугольный? Вогнутая ? Выпуклая? с дырками? Пузырь? Морская звезда?

4 Ответов

Рейтинг:
32

Rick York

Вот еще одна возможность : Функция MaskBlt (wingdi.h) - приложения Win32 | Microsoft Docs[^]

Эта функция выполняет растровые операции с растровыми изображениями. Для определения области можно использовать растровую маску. Что касается графики, то она выполняет эту операцию очень быстро и включает в себя только один вызов функции для региона, а не один на пиксель.

Вы можете создать монохромное растровое изображение в памяти, чтобы использовать его для тестирования хитов, если хотите. Единица может находиться в этом регионе, а ноль-вне его.


PotatoSoup

Ответ на решение 4:

Часы попыток заставить это работать. Я теряюсь в примерах и получаю ошибки, такие как не удается преобразовать растровое изображение в HBITMAP и т. д. Это выглядит как лучший вариант, но я чувствую, что сдаюсь и просто использую длинный путь проверки на пиксель.

Спасибо, но мой компилятор снова и снова убеждает меня, что я некомпетентен в этом процессе.

Я попробовал использовать следующее с различными настройками:

HBITMAP CreateBitmapMask(HBITMAP hbmColour, COLORREF crTransparent)
    {
        HDC hdcMem;
        HDC hdcMem2;
        HBITMAP hbmMask;
        BITMAP bm;

        GetObject(hbmColour, sizeof(BITMAP), &bm);
        hbmMask = CreateBitmap(bm.bmWidth, bm.bmHeight, 1, 1, nullptr);

        hdcMem = CreateCompatibleDC(nullptr);
        hdcMem2 = CreateCompatibleDC(nullptr);

        SelectObject(hdcMem, hbmColour);
        SelectObject(hdcMem2, hbmMask);

        SetBkColor(hdcMem, crTransparent);

        BitBlt(hdcMem2, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCCOPY);

        BitBlt(hdcMem, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem2, 0, 0, SRCINVERT);

        DeleteDC(hdcMem);
        DeleteDC(hdcMem2);

        //MessageBox(Handle_of_MainWindow, L"Created a bitmap mask", L"Created a bitmap mask", MB_OK | MB_ICONEXCLAMATION);

        return hbmMask;
    }


Я попытался заменить процесс per pixel этим, но нет.

Я попытался создать черно-белую двухцветную маску вручную, а затем загрузить ее и использовать следующим образом (заменив процесс на пиксель, но нет.

//////        for ( iY = 0; iY < bmpInfo_001.bmHeight; iY++)
//////            {
//////                do
//////                    {
//////                        //skip over transparent pixels at start of lines.
//////                        while (iX < bmpInfo_001.bmWidth && GetPixel(hdcMem_001, iX, iY) == crTransparent)
//////                            {
//////                                iX++;
//////                            }
//////
//////                        //remember this pixel
//////                        int iLeftX = iX;
//////
//////                        //now find first non transparent pixel
//////                        while (iX < bmpInfo_001.bmWidth   && GetPixel(hdcMem_001, iX, iY) != crTransparent)
//////                            {
//////                                ++iX;
//////                            }
//////
//////                        //create a temp region on this info
//////                        HRGN hRgnTemp = CreateRectRgn(iLeftX, iY, iX, iY+1);
//////
//////                        //combine into main region.
//////                        //    int CombineRgn
//////                        //        (
//////                        //            HRGN hrgnDst,     // A handle to a new region with dimensions defined by combining two other regions. (This region must exist before CombineRgn is called.)
//////                        //            HRGN hrgnSrc1,    // A handle to the first of two regions to be combined.
//////                        //            HRGN hrgnSrc2,    // A handle to the second of two regions to be combined.
//////                        //            int  iMode        // A mode indicating how the two regions will be combined.
//////                        //
//////                        iRet = CombineRgn(hRgn_001, hRgn_001, hRgnTemp, RGN_OR);


                        HBITMAP hSkinMBmp = NULL;

                                                
                        iRet = CombineRgn(hRgn_001, hRgn_001, hBitmap_SOME_MASK_001, RGN_OR);

                        if(iRet == ERROR)
                            {
                                return;
                            }

//////
//////                        if(iRet == ERROR)
//////                            {
//////                                return;
//////

PotatoSoup

Продолжающийся:

Помогите. Что я делаю не так? Кажется логичным, чтобы программа создала маску или загрузила предварительно созданную маску, а затем использовала ее. Я меня возникли проблемы с этим.

Не мог бы кто-нибудь исправить мой код (с объяснением того, что они сделали), пожалуйста?

PotatoSoup

Я попробовал это с большим растровым изображением со многими очень многими маленькими прозрачными областями и использовал готовую маску. Это было быстро. Я изучал, почему это сработало, и пытался извлечь из этого урок.

Спасибо.

Rick York

Я очень рад прочесть, что вы заставили его работать. Я вовсе не эксперт в таких вещах. Я только что вспомнил кое-что об этой конкретной функции. Желаю удачи с этим.

Рейтинг:
2

PotatoSoup

Я отвечал на каждое решение вопросом: "Есть ли у вас вопрос или комментарий?" кнопка, и ни один из этих ответов не появляется. Для чего эта кнопка, если не для того, чтобы задавать вопросы или комментировать?


Richard MacCutchan

Я вижу оба ваших комментария.

PotatoSoup

Не могла бы администрация удалить решение 3, Как я теперь вижу ответы. Теперь это замечание, которое я сделал, просто занимает место. Спасибо.

Рейтинг:
1

KarstenK

В Статья CContourBitmap - Создатель Региона это хорошая информация о регионах.

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

Разве BitBlt с прозрачными пикселями не возможен?


PotatoSoup

В упомянутой статье говорится, что у него есть известная ошибка: "требуется преобразование из 24-битного цветового пространства в 16-битное цветовое пространство."

Мой код хорошо работает с 8 битами на пиксель. Я использую 256-цветную модель 8 bpp, чтобы я мог вручную быстро настроить части изображения, выбрав один цвет в шаблоне. Я ценю ваше предложение о помощи. Вы не знали этого ограничивающего фактора, и я не ожидал, что это будет проблемой. Спасибо.

Мне нравится ваша идея ограничить GetPixel. Я, вероятно, буду работать над этим. Я не знаю, смогу ли я это сделать, но мне нравится эта идея.

"дорогостоящий CreateRegion и CombineRegion", работающий над этим, выглядит многообещающе.

"Разве передача битового блока с прозрачными пикселями возможно?" Я не знаю, можно ли его использовать в этом процессе. И альфа-смешивание (которое, как я думаю, требуется) было трудным для меня, поэтому я отказался от него на данный момент.

Вы не дали мне код, но вы дали мне логику, чтобы применить ее к моему коду, который может быть почти лучше. Я подумаю над вашим советом. Спасибо.

Рейтинг:
0

PotatoSoup

Спасибо тебе, Рик Йорк.

Ваша первая ссылка гласит на странице: "диалог не имеет реальной формы, то есть тестирование попадания не основано на форме и прозрачности диалога. Это означает, что области диалогового окна, которые имеют цветовую маркировку или значение альфа равно нулю, не будут пропускать сообщения мыши." Я хочу иметь возможность щелкать мышью по прозрачным областям. Поэтому я, возможно, не смогу использовать этот пример. Но все равно спасибо. Сейчас я его изучаю.

Спасибо за вторую (множественную) ссылку. Сейчас я его изучаю.

Я не нашел того, что просил в это время по этим ссылкам, поэтому я не могу в это время принять этот ответ, кроме как сказать спасибо за предложение.