Проблемы с отрисовкой
От: intrex  
Дата: 08.12.01 08:31
Оценка:
Hi All!

Помогите разобраться, pls :(

Необходимо создать ActiveX control с возможностью прокрутки содержимого.
То есть если размер картинки больше клиенской области контрола,
то должна быть возможность зацепить картинку мышкой и прокручивать ee
(примерно как в ACDSee). При этом хочется устанавливать свой курсор во
время прокрутки.

ПРОБЛЕМА: Когда контрол имеет достаточно большой размер, прокрутка картинки сильно притормаживает.
Однако, если не устанавлить свой курсор (в строке Label_1), все нормально, ничего не тормозит.
Более того, не тормозит и тогда, если устанавливать не свой курсор а системный
/* например SetCursor(LoadCursor(NULL, IDC_SIZEALL)); тоже не тормозит. */
Совсем странно...

Я поступал так:

Создаем ATL Lite control и реализуем методы:

LRESULT OnLButtonDown(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
m_PrevMousePos = MAKEPOINTS(lParam);
m_spInPlaceSite->SetCapture(TRUE);
SetCursor(LoadCursor(_Module.m_hInstResource, IDC_CURSOR)); // Label 1: Set custom cursor
return 0;
}

LRESULT OnLButtonUP(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
SetCursor(LoadCursor(NULL, IDC_ARROW));
m_spInPlaceSite->SetCapture(FALSE);
return 0;
}

LRESULT OnMouseMove(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
{
if (m_spInPlaceSite->GetCapture() == S_OK)
{
POINTS MousePos = MAKEPOINTS(lParam);
m_ViewOrg.x += (MousePos.x — m_PrevMousePos.x);
m_ViewOrg.y += (MousePos.y — m_PrevMousePos.y);

m_PrevMousePos = MousePos;
FireViewChange();
}
return 0;
}

HRESULT OnDrawAdvanced(ATL_DRAWINFO& di)
{
RECT rc = *(RECT*)di.prcBounds;

OffsetRect(&rc, m_ViewOrg.x, m_ViewOrg.y);
Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);

return S_OK;
}


Подскажите плз, где копать ?

Best regards
Dns
Re: Проблемы с отрисовкой
От: OlegO Россия http://www.mediachase.ru
Дата: 08.12.01 09:13
Оценка:
Здравствуйте intrex, Вы писали:

I>Hi All!


I>Помогите разобраться, pls


I>Необходимо создать ActiveX control с возможностью прокрутки содержимого.

I>То есть если размер картинки больше клиенской области контрола,
I>то должна быть возможность зацепить картинку мышкой и прокручивать ee
I>(примерно как в ACDSee). При этом хочется устанавливать свой курсор во
I>время прокрутки.

Я делал подобное (правда на MFC) и у меня ничего не тормозило.

По подробней, прокрутка картинки сильно притормаживает?? что именно,
мигает при отрисовке, медленно перемещается ?

И еще кто-нибудь FireViewChange(); ловит ? может там тормозит.
С уважением, OlegO.
Re[2]: Проблемы с отрисовкой
От: intrex  
Дата: 08.12.01 10:07
Оценка:
Здравствуйте OlegO, Вы писали:

OO>Я делал подобное (правда на MFC) и у меня ничего не тормозило.


Да, я тоже делал подобное с помощью WinApi и все было в порядке.
Тут дело в том, что понадобилось написать такой компонент для
использования в Internet Explorer, и хочется, чтобы он был
windowless. Поэтому вместо обыкновенных API вызовов SetCapture()
и ReleaseCapture() я вызываю соответствующие методы контейнера
m_spInPlaceSite->....

Кстати, вот если в конструкторе объекта установить флаг
m_bWindowOnly = TRUE, и использовать стандартные
Set/Get/ReleaseCapture, то все работает нормально.
Только вот компонент в данном случае уже не windowless

OO>По подробней, прокрутка картинки сильно притормаживает?? что именно,

OO>мигает при отрисовке, медленно перемещается ?

Нет, не мигает, а прокручивается как бы рывками.

OO>И еще кто-нибудь FireViewChange(); ловит ? может там тормозит.


Я пробовал менять FireViewChange() на прямой вызов InvalidateRect() —
не помогает

Похоже тут все заморочки в том, как контейнер обрабатывает мышиные
события для своего windowless компонента. Вот тут мне не понятно где копать.
Самое убойное то, что если использовать стандартные курсоры — работает нормально,
а ставишь свои — хоть вешайся. Вот этого никак не могу понять
Что-нибудь посоветуешь ?

Спасибо за ответ,
Dmitry Stepanov aka \\DNS
Re: Проблемы с отрисовкой
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.12.01 13:32
Оценка: 4 (2)
Здравствуйте intrex, Вы писали:

I>Я поступал так:


I>Создаем ATL Lite control и реализуем методы:...


I> m_spInPlaceSite->SetCapture(TRUE);


1-е замечания. Ты используешь виндовлес-режим для целей где лучше использовать оконный. Или ты не правильно делаешь SetCapture. Для отдельного окна лучше это делать API-шниыми функциями.


I>...

I> FireViewChange();

Вот это приводит к основным тормозам. Погляди как реализован этот метод для оконных контролов! Он приводит к полной перерисовке окна. В твоем же случае нужно использовать ScrollWindow. Эта функция скролирует dc и помечает для отрисовки только ту область изображения которая ранее не присутствовала на экране. При этом лучше не пользоваться InvalidateRect-ом (или делать это с большой осторожностью).

I>HRESULT OnDrawAdvanced(ATL_DRAWINFO& di)

I>{
I> RECT rc = *(RECT*)di.prcBounds;

I> OffsetRect(&rc, m_ViewOrg.x, m_ViewOrg.y);

I> Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);

I> return S_OK;

I>}

Если будешь использовать оконный режим, то лучше перейти на отрисовку в WM_PAINT. Кстати, странное у тебя изображение (Rectangle). :) С таким изображением вообще не должно тормозить. Однако, функция тормозная. Если нужно закрашивать фон и программа (в основном) должна работать в хай- и труколор-режимах, то лучше исальзовать TextOutEx (или как там его) с пустой строкой.

I>Подскажите плз, где копать ?


Знамо где MSDN-е. ;)

PS

По поводу SetCursor... Так эту функцию использовать нельзя! SetCursor нужно устанавливать на сообщение WM_SETCURSOR (или что-то вроде того). Если контрол не оконный, то можно попробовать задавать его на движение мыши. Главное что операция эта не статическая. А тормоза при смене курсора могут быть связыны с тем, что курсор создан как-то не так. Например, он анимированный. При этом Windows (вернее, некоторые старые драйвера к картам) перестает акселерировать его отрисовку.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Re[2]: Проблемы с отрисовкой
От: intrex  
Дата: 09.12.01 22:03
Оценка:
Здравствуйте VladD2, Вы писали:

I>>Создаем ATL Lite control и реализуем методы:...

VD>1-е замечания. Ты используешь виндовлес-режим для целей где лучше использовать оконный.
Ты прав. Оконный режим для этого компонента удобнее, но изначально все компоненты для проекта
создавались как windowless, и в данном случае было желание поступить так же.
Хотя интересно, какие аргументы ты приведешь в пользу оконных контролов vs. windowless.

I>> m_spInPlaceSite->SetCapture(TRUE);

VD>>Или ты не правильно делаешь SetCapture. Для отдельного окна лучше это делать API-шниыми функциями.
Вот именно: "для отдельного окна", а в данном случае необходимо вызывать IOleInPlaceSiteWindowless::SetCapture() чтобы контейнер перенаправлял все мышиные события в windowless контрол. При использовании API функций этого не произойдет.

I>> FireViewChange();

VD>Вот это приводит к основным тормозам.
Неправда. В рабочей версии используется IOleInPlaceSiteWindowless::ScrollRect() — те же тормоза.
VD>>В твоем же случае нужно использовать ScrollWindow.
Пробовал, и напрямую ::ScrollWindowEx() — никак не влияет.
Так что причина не в этом. А здесь использован FireViewChange() для краткости, чтобы не загромождать код примера.

I>>HRESULT OnDrawAdvanced(ATL_DRAWINFO& di)

I>>{
VD>Если будешь использовать оконный режим, то лучше перейти на отрисовку в WM_PAINT.
В случае оконного режима метод CComControlBase::OnDrawAdvanced() вызывается непосредственно обработчиком события WM_PAINT. Он выполняет стандартную подготовку контекста рисования, /* BeginPaint() и т.д. */ и никаких критических вызовов там нет. Так что использование OnDrawAdvanced() равносильно использованию обыкновенного
обработчика WM_PAINT.

VD>Кстати, странное у тебя изображение (Rectangle). :)

В реальном приложении используется BitBlt() для отображения битмапа.
А в этом примере я использовал Rectangle() просто для краткости, чтобы
показать, что проблема не в скорости отрисовки данных.

VD>По поводу SetCursor... Так эту функцию использовать нельзя! SetCursor нужно устанавливать на сообщение WM_SETCURSOR

Как раз в данном случае нельзя поступать так, как ты говоришь. Сообщение WM_SETCURSOR не посылается окну, захватившему (captured) мышиный ввод. Поэтому, для того, чтобы в captured режиме был курсор другой чем в не-captured ;), нужно после SetCapture() вызывать SetCursor(). Во всех других случаях действительно надо реагировать на WM_SETСURSOR.

VD>>Если контрол не оконный, то можно попробовать задавать его на движение мыши.

А вот этого действительно делать нельзя — курсор будет мигать.

VD>>Главное что операция эта не статическая.

...eсли не захвачен ввод от мыши.

I>>Подскажите плз, где копать ?

VD>Знамо где MSDN-е.
Конкретную ссылочку, плиз ;)

>>А тормоза при смене курсора могут быть связыны с тем, что курсор создан как-то не так.

Я тоже так думал, и создавал эти курсоры всеми возможными способами.
Причем самые простые — не анимированые. Все пофигу — тормозит.

Так что все вышеописанное, к сожалению, вопрос не решает.
Проблема все-таки не в этом.

Dmitry Stepanov aka DNS
Re[3]: Проблемы с отрисовкой
От: VladD2 Российская Империя www.nemerle.org
Дата: 09.12.01 22:50
Оценка:
Здравствуйте intrex, Вы писали:

I>Здравствуйте VladD2, Вы писали:


I>>>Создаем ATL Lite control и реализуем методы:...

VD>>1-е замечания. Ты используешь виндовлес-режим для целей где лучше использовать оконный.
I>Ты прав. Оконный режим для этого компонента удобнее, но изначально все компоненты для проекта
I>создавались как windowless, и в данном случае было желание поступить так же.
I>Хотя интересно, какие аргументы ты приведешь в пользу оконных контролов vs. windowless.

VB для убирания фликов вынужден многократно кешировать образ dc в памяти. Если нужна сложная отрисовка (как в товоем случае), то лучше иметь свое окна и делать с ним что угодно.

I>>> FireViewChange();

VD>>Вот это приводит к основным тормозам.
I>Неправда. В рабочей версии используется IOleInPlaceSiteWindowless::ScrollRect() — те же тормоза.

Так а что неправда? Про ScrollRect ты не сказал, а FireViewChange — это полная перерисовка, т.е. 100% тормоза.

VD>>>В твоем же случае нужно использовать ScrollWindow.

I>Пробовал, и напрямую ::ScrollWindowEx() — никак не влияет.
I>Так что причина не в этом. А здесь использован FireViewChange() для краткости, чтобы не загромождать код примера.

Плохая краткость.

VD>>Если будешь использовать оконный режим, то лучше перейти на отрисовку в WM_PAINT.

I>В случае оконного режима метод CComControlBase::OnDrawAdvanced() вызывается непосредственно обработчиком события WM_PAINT. Он выполняет стандартную подготовку контекста рисования, /* BeginPaint() и т.д. */ и никаких критических вызовов там нет. Так что использование OnDrawAdvanced() равносильно использованию обыкновенного
I>обработчика WM_PAINT.

А ну тогда понятно почему у тебя тормоза. Ты же всегда перерисовываешь всю видимую область. Поглади внимательнее как у ATL-щиков реализован OnPaint из которого вызывается OnDrawAdvanced. Там нет одной существенной детали... там не запоминается область которую действитеьно надо перерисовывать. Эта область кладется для отимизации отрисовки.

VD>>Кстати, странное у тебя изображение (Rectangle).

I>В реальном приложении используется BitBlt() для отображения битмапа.
I>А в этом примере я использовал Rectangle() просто для краткости, чтобы
I>показать, что проблема не в скорости отрисовки данных.

А пример, то тормозит? Може пришлешь его?

VD>>По поводу SetCursor... Так эту функцию использовать нельзя! SetCursor нужно устанавливать на сообщение WM_SETCURSOR

I>Как раз в данном случае нельзя поступать так, как ты говоришь. Сообщение WM_SETCURSOR не посылается окну, захватившему (captured) мышиный ввод. Поэтому, для того, чтобы в captured режиме был курсор другой чем в не-captured , нужно после SetCapture() вызывать SetCursor(). Во всех других случаях действительно надо реагировать на WM_SETСURSOR.

Возможно. Но при выходе и повторном заходе в окно курсор должен "испортиться". Или при капчуре он не меняется?

VD>>>Если контрол не оконный, то можно попробовать задавать его на движение мыши.

I>А вот этого действительно делать нельзя — курсор будет мигать.

Если он "апаратный", то не будет.

I>>>Подскажите плз, где копать ?

VD>>Знамо где MSDN-е.
I>Конкретную ссылочку, плиз

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

>>>А тормоза при смене курсора могут быть связыны с тем, что курсор создан как-то не так.

I>Я тоже так думал, и создавал эти курсоры всеми возможными способами.
I>Причем самые простые — не анимированые. Все пофигу — тормозит.

Так добей свой пример (шоб можно было скомпилировать и запустить) и кидай на было... поглядим. М тоже интересно стало.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.