31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
1

Activex перенести на задний план (позиция по оси z)

20.01.2016, 15:01. Показов 1653. Ответов 13
Метки нет (Все метки)

Author24 — интернет-сервис помощи студентам
Здравствуйте!
Проблема состоит в следующем... При добавлении в СКАДу (omron cx-supervisor) мой activex (написан в MFC C++) в RunTime режиме всегда идет поверх объектов, которые созданы в СКАДе (например Ellipse), даже если для объекта СКАДы я указываю Rise -> To Top, хотя в режиме разработки все нормально (axtivex можно передвинуть на задний план). Как сделать так чтобы мой activex оказался "ниже" объекта созданного в СКАДе (т.е. задать его положение по оси z)? В крайнем случае, как можно сделать чтобы он всегда был на заднем плане? Для другого activex (написан на VB6, но его писал не я) все нормально, его позиция по оси z сохраняется в runtime, значит такая возможность есть.

Добавлено через 9 минут
Хотя нет, сейчас проверил насчет activex написанного на VB6, все то же, что и для моего. На задний план не уходит.
Вопрос остается, можно ли сделать так, чтобы activex перенесся на задний план при runtime?
0
Programming
Эксперт
94731 / 64177 / 26122
Регистрация: 12.04.2006
Сообщений: 116,782
20.01.2016, 15:01
Ответы с готовыми решениями:

Поместить контролл на передний план, на задний план "по уровням"
Доброго времени суток :) В VS при создании есть 2 функции "на передний план " и "на задний...

На задний план
Надо шар(.absolute) за прямоугольниками(.left/.rigth) сделать , я уже все перепробовал , ничего не...

Графика, задний план
Здравствуйте, задали сделать программу-открытку поздравления с новым годом, где падает снег и...

Задний план. (Фон)
Люди, плз помогите мне! На моем TForm стоит TImage. Он стоит на 2 месте, и закрывает (гадость)...

13
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
21.01.2016, 17:08  [ТС] 2
Пришла мне одна идея в голову... А если взять изображение того, что под activex находится и накладывать сверху на то, что я рисую в activex? Добраться до формы на которой находится контейнер с моим activex могу. Только как захватывать все кроме заднего фона формы на которой расположен activex?
0
Модератор
3401 / 2172 / 353
Регистрация: 13.01.2012
Сообщений: 8,410
21.01.2016, 20:09 3
Могу ошибаться но наверняка активикс это какое нибудь дочернее окно и ему можно послать сообщение передвинуться назад
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
21.01.2016, 23:21  [ТС] 4
C++
1
2
3
4
5
6
7
8
9
10
11
12
CWnd* pWndContainer = GetParent(); //Добираемся до контейнера
        CWnd* pWndPage = pWndContainer->GetParent(); //Добираемся до формы на которой расположен activex
        pWndContainer->SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); //На экране activex появляется и пропадает много раз
 
        //pWndContainer->SetWindowPos(pWndPage, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE); //Результата вообще никакого
 
 
        CBrush bkBrush(TranslateColor(GetBackColor()));
        pdc->FillRect(rcBounds, &bkBrush);
 
        default_pic.Render(pdc, rcBounds, rcBounds);
        bkBrush.DeleteObject();
Это код рисования из OnDraw. Я сразу попытался воспользоваться SetWindowPos, но если данный способ вообще приемлем, то как правильно сделать?
0
Модератор
3401 / 2172 / 353
Регистрация: 13.01.2012
Сообщений: 8,410
22.01.2016, 10:07 5
Цитата Сообщение от korochinskiy Посмотреть сообщение
как правильно сделать
попробуйте
C++
1
SetWindowPos(hwnd_of_activex_control, (HWND)1, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
22.01.2016, 11:07  [ТС] 6
К сожалению результата никакого, т.е. activex все равно остался поверх того, что я нарисовал в СКАДе непосредственно, но ушел вниз еще одного activex который я на него наложил для эксперимента.
0
Модератор
3401 / 2172 / 353
Регистрация: 13.01.2012
Сообщений: 8,410
22.01.2016, 13:02 7
Цитата Сообщение от korochinskiy Посмотреть сообщение
К сожалению результата никакого, т.е. activex все равно остался поверх того, что я нарисовал в СКАДе непосредственно, но ушел вниз еще одного activex который я на него наложил для эксперимента.
хм.. ну тогда перебрать все дочерние окна того окна на котором лежит activex и послать их на передний план

Добавлено через 46 секунд
кроме самого activex естественно
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
22.01.2016, 13:38  [ТС] 8
В том то и дело, что activex это, по ходу, дочернее окно, а кнопки и рисунки на форме это контролы формы... (я не уверен, если не прав, то поправьте). GetAccessibleChildCount для формы выводит только количество моих activex на форме, а кнопки и рисунки не считает. Хотя странно, что в редакторе СКАДы (когда я рисую, добавляю кнопки и т.д.) можно activex на задний план отправить, а когда запускаю весь проект на выполнение, то activex`ы все вперед вылазят.
0
Модератор
3401 / 2172 / 353
Регистрация: 13.01.2012
Сообщений: 8,410
22.01.2016, 14:36 9
Цитата Сообщение от korochinskiy Посмотреть сообщение
странно
может скадовские кнопки и прочие элементы реализованы не на базе окна. тогда вилы.
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
24.01.2016, 00:10  [ТС] 10
Я вернулся к варианту, при котором беру изображение из под activex и накладываю его поверх того, что рисую в activex`е. Вот код OnDraw который у меня получился.
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
    void CStatusContainerCtrl::OnDraw(
    CDC* pdc, const CRect& rcBounds, const CRect&  /*rcInvalid*/ )
{
 
    CRgn    rgn;
    CDC     dcMem;
    CBitmap bmpMem;
    CBitmap* pOldBmp = NULL;
 
    if (!pdc)
        return;
    // TODO: Замените следующий код собственным кодом рисования.
 
    //Если находимся в RunTime режиме
    if (AmbientUserMode())
    {
        CWnd* pWndContainer = GetParent(); //Добираемся до контейнера
        CWnd* pWndPage = pWndContainer->GetParent(); //Добираемся до формы на которой расположен activex
 
        CDC* main = pWndPage->GetDC();
 
        int cx = GetDeviceCaps(main->m_hAttribDC, HORZRES); //Определяем размеры страницы x
        int cy = GetDeviceCaps(main->m_hAttribDC, VERTRES); //Определяем размеры страницы y
 
        CRect rectangle;
        pWndContainer->GetWindowRect(rectangle); //вычисляю координаты контейнера
        pWndPage->ScreenToClient(rectangle); //подгоняю координаты под форму
 
        rgn.CreateRectRgnIndirect(rcBounds);
        pdc->SelectClipRgn(&rgn);
 
        dcMem.CreateCompatibleDC(main);
        bmpMem.CreateCompatibleBitmap(main, cx, cy);
        pOldBmp = (CBitmap*)dcMem.SelectObject(&bmpMem);
 
        (*pic).Render(&dcMem, rectangle, rcBounds);
 
        //dcMem.BitBlt(0, 0, cx, cy, main, 0, 0, SRCCOPY); //тут картинка того, что расположено под activex выводится, но полностью перетирает мою картинку
 
        dcMem.TransparentBlt(0, 0, cx, cy, main, 0, 0, cx, cy, TranslateColor(GetBackColor())); //Тут моя картинка отображается на черном фоне
 
        pdc->BitBlt(0, 0, rcBounds.Width(), rcBounds.Height(), &dcMem, rectangle.TopLeft().x, rectangle.TopLeft().y, SRCCOPY);
        pdc->SelectClipRgn(NULL);
 
        rgn.DeleteObject();
 
        dcMem.SelectObject(pOldBmp);
        bmpMem.DeleteObject();
        dcMem.DeleteDC();
    }
    else
    {
        CBrush bkBrush(TranslateColor(GetBackColor()));
        pdc->FillRect(rcBounds, &bkBrush);
 
        default_pic.Render(pdc, rcBounds, rcBounds);
        bkBrush.DeleteObject();
    }
 
    DoSuperclassPaint(pdc, rcBounds);
}
Наткнулся на проблему. TransparentBlt не работает как надо. По идее он должен делать прозрачным фон и накладывать его на то, что я уже нарисовал в activex, но выводится картинка (которую я нарисовал до наложения) на черном фоне. Как сделать правильно?

Добавлено через 10 минут
Такое впечатление, что TransparentBlt вообще ничего не делает.

Добавлено через 8 часов 47 минут
Сделал я копирование участка формы на свой activex. Проблема с TransparentBlt оказалась в несоответствии размеров того, что копирую к тому куда копирую. Но проблема возникла в другом. Если я копирую область формы на свой activex то он тоже копируется (в картинке отображается и activex и если открыть окно над activex, то его изображение тоже захватывается). Как сделать чтобы в картинку захватывалось изображение только того, что находится под моим activex?
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
void CStatusContainerCtrl::OnDraw(
    CDC* pdc, const CRect& rcBounds, const CRect&  /*rcInvalid*/ )
{
 
    CRgn    rgn;
    CDC     dcMem;
    CBitmap bmpMem;
    CBitmap* pOldBmp = NULL;
    CDC* main = NULL;
 
    if (!pdc)
        return;
    // TODO: Замените следующий код собственным кодом рисования.
 
    //Если находимся в RunTime режиме
    if (AmbientUserMode())
    {
        CWnd* pWndContainer = GetParent(); //Добираемся до контейнера
        CWnd* pWndPage = pWndContainer->GetParent(); //Добираемся до формы на которой расположен activex
 
        CRect rectangle;
        pWndContainer->GetWindowRect(rectangle); //вычисляю координаты контейнера
        pWndPage->ScreenToClient(rectangle); //подгоняю координаты под форму
 
        rgn.CreateRectRgnIndirect(rcBounds);
        pdc->SelectClipRgn(&rgn);
 
        main = pWndPage->GetDC();
 
        //Создаем буфер в которой будем рисовать
        dcMem.CreateCompatibleDC(pdc);
        bmpMem.CreateCompatibleBitmap(pdc, rcBounds.Width(), rcBounds.Height());
        pOldBmp = (CBitmap*)dcMem.SelectObject(&bmpMem);
        //Заполняю задний фон в буфере
        CBrush bkBrush(TranslateColor(GetBackColor()));
        dcMem.FillRect(rcBounds, &bkBrush);
        bkBrush.DeleteObject();
        //Рисую картинку в буфере
        (*pic).Render(&dcMem, rcBounds, rcBounds);
        //Копирую часть изображения формы в буфер здесь специально указал координаты левого верхнего угла экрана, 
        //чтобы не копировать изображение в activex само на себя.
        dcMem.TransparentBlt(0, 0, rcBounds.Width(), rcBounds.Height(), main, 0, 0, rcBounds.Width(), rcBounds.Height(), TranslateColor(GetBackColor()));
        //отпускаю форму
        ReleaseDC(main);
        //Копирую буфер в мой activex
        pdc->BitBlt(0, 0, rcBounds.Width(), rcBounds.Height(), &dcMem, 0, 0, SRCCOPY);
 
        pdc->SelectClipRgn(NULL);
        rgn.DeleteObject();
 
        //Удаляю объекты буфера
        dcMem.SelectObject(pOldBmp);
        bmpMem.DeleteObject();
        dcMem.DeleteDC();
    }
    else
    {
        CBrush bkBrush(TranslateColor(GetBackColor()));
        pdc->FillRect(rcBounds, &bkBrush);
 
        default_pic.Render(pdc, rcBounds, rcBounds);
        bkBrush.DeleteObject();
    }
 
    DoSuperclassPaint(pdc, rcBounds);
}
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
25.01.2016, 11:42  [ТС] 11
Продолжаем разговор Посмотрел я тут про WM_PRINT и написал следующий код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
void CStatusContainerCtrl::PrintWindow(HWND hWnd)
{
    HDC hDCMem = CreateCompatibleDC(NULL);
 
    RECT rect;
 
    ::GetWindowRect(hWnd, &rect);
 
    HBITMAP hBmp = NULL;
 
    {
        HDC hDC = ::GetDC(hWnd);
        hBmp = CreateCompatibleBitmap(hDC, rect.right - rect.left, rect.bottom - rect.top);
        ::ReleaseDC(hWnd, hDC);
    }
 
    HGDIOBJ hOld = SelectObject(hDCMem, hBmp);
    ::SendMessage(hWnd, WM_PRINT, (WPARAM)hDCMem, PRF_CHILDREN | PRF_CLIENT | PRF_ERASEBKGND | PRF_NONCLIENT | PRF_OWNED);
 
    SelectObject(hDCMem, hOld);
    DeleteObject(hDCMem);
 
    ::OpenClipboard(hWnd);
 
    EmptyClipboard();
    SetClipboardData(CF_BITMAP, hBmp);
    CloseClipboard();
}
Теперь я захватываю изображение которое находится на форме (точнее вижу только фон), но элементы которые на ней расположены вообще не отображаются (даже те, которые нарисованы в СКАДе).
По идее, как я это все понимаю, надо захватить все элементы кроме дочерних окон, так как GetAccessibleChildCount выдает только количество отображенных на форме activex. Вопрос, можно ли с помощью WM_PRINT это сделать и, если можно, то как это сделать? Если нельзя, то подскажите куда копать дальше?

Добавлено через 10 минут
Забыл написать, в эту функцию посылаю HWND окна которое под моим activex находится.
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
25.01.2016, 12:47  [ТС] 12
И еще в догонку скрин того, что Spy++ показывает. Как я и думал, activex это дочерние окна...
Миниатюры
Activex перенести на задний план (позиция по оси z)  
0
183 / 181 / 66
Регистрация: 15.02.2015
Сообщений: 515
28.01.2016, 13:12 13
Похоже так и есть, все контролы СКАДы главное окно рисует само в своём обработчике WM_PAINT, а отрисовка дочерних окон выполняется после пользовательской обработки WM_PAIN. Поэтому как уже заметили выше:
Цитата Сообщение от vxg Посмотреть сообщение
...тогда вилы.
Дело в том, что для вашего ActiveX отрисовка всего содержимого родительского окна (не включая другие дочерние окна) является "неделимой" операцией и вклиниться между какими-то контролами не получится. Сначала я предположил что поможет посылка WM_PRINTCLIENT главному окну из WM_PAINT ActiveX окна, но наверняка также будет перерисован и фон окна, тогда ваш элемент будет совсем невидим.
0
31 / 27 / 8
Регистрация: 25.05.2015
Сообщений: 113
29.01.2016, 20:19  [ТС] 14
Кстати, почитал я статью feng yuan`я насчет установки хука на BeginPaint и EndPaint, попробовал, в принципе получаю скриншет именно того, что надо (контролы СКАДы + фон), но только один раз, после СКАДа падает с ошибкой, хотя окна типа блокнот и т.д. нормально выживают (пробовал на x32 винде). Да и вызывать по его методу перерисовку всего экрана скады хотя бы раз в секунду, для получения изображения из под каждого activex как то "не комельфо"... Думаю это внесет тормоза в работу системы, что плохо. Пришел к решению завести еще activex типа "лампочка" для вывода значений датчиков над моим activex и сделать фон моего activex прозрачным (это получилось). Я понимаю, что это тоже не красивый выход из положения, но лучше чем постоянно перерисовывать главный экран СКАДы, тем более, что таких датчиков, которые надо показывать поверх моих activex не очень много.
0
29.01.2016, 20:19
IT_Exp
Эксперт
87844 / 49110 / 22898
Регистрация: 17.06.2006
Сообщений: 92,604
29.01.2016, 20:19
Помогаю со студенческими работами здесь

Слайдер на задний план
Поставил, я слайдер FLEXSLIDER, и он у меня закрывает, всплываешее меню, на сайте, можно ли как то...

Картинка на задний план
Можно как-то при помощи свойств компонента TImage переместить картинку на задний план, чтобы было...

Как поместить на задний план?
Необходимо создать навигационное меню и на заднем плане должен быть фон. Но когда я создаю...

Компонент StringGrid на задний план
Хочу Label поверх компонента StringGrid(таблица) поставить. Упорно проваливается под него. Пробовал...

Картинка на задний план groupbox
Как присвоить картинку groupbox или сделать его полупрозрачным?

Рисунок на задний план в Excel
Здрасти У меня есть рисунок (Овал)прозрачный, необходимо поместить овал на задний план т.е. за...


Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
14
Ответ Создать тему
Опции темы

КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin
Copyright ©2000 - 2024, CyberForum.ru