Необходимо создать ActiveX control с возможностью прокрутки содержимого.
То есть если размер картинки больше клиенской области контрола,
то должна быть возможность зацепить картинку мышкой и прокручивать ee
(примерно как в ACDSee). При этом хочется устанавливать свой курсор во
время прокрутки.
ПРОБЛЕМА: Когда контрол имеет достаточно большой размер, прокрутка картинки сильно притормаживает.
Однако, если не устанавлить свой курсор (в строке Label_1), все нормально, ничего не тормозит.
Более того, не тормозит и тогда, если устанавливать не свой курсор а системный
/* например SetCursor(LoadCursor(NULL, IDC_SIZEALL)); тоже не тормозит. */
Совсем странно...
Здравствуйте intrex, Вы писали:
I>Hi All!
I>Помогите разобраться, pls
I>Необходимо создать ActiveX control с возможностью прокрутки содержимого. I>То есть если размер картинки больше клиенской области контрола, I>то должна быть возможность зацепить картинку мышкой и прокручивать ee I>(примерно как в ACDSee). При этом хочется устанавливать свой курсор во I>время прокрутки.
Я делал подобное (правда на MFC) и у меня ничего не тормозило.
По подробней, прокрутка картинки сильно притормаживает?? что именно,
мигает при отрисовке, медленно перемещается ?
И еще кто-нибудь FireViewChange(); ловит ? может там тормозит.
Здравствуйте 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 компонента. Вот тут мне не понятно где копать.
Самое убойное то, что если использовать стандартные курсоры — работает нормально,
а ставишь свои — хоть вешайся. Вот этого никак не могу понять
Что-нибудь посоветуешь ?
Здравствуйте 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 (вернее, некоторые старые драйвера к картам) перестает акселерировать его отрисовку.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.
Здравствуйте 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-е.
Конкретную ссылочку, плиз ;)
>>А тормоза при смене курсора могут быть связыны с тем, что курсор создан как-то не так.
Я тоже так думал, и создавал эти курсоры всеми возможными способами.
Причем самые простые — не анимированые. Все пофигу — тормозит.
Так что все вышеописанное, к сожалению, вопрос не решает.
Проблема все-таки не в этом.
Здравствуйте 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>Причем самые простые — не анимированые. Все пофигу — тормозит.
Так добей свой пример (шоб можно было скомпилировать и запустить) и кидай на было... поглядим. М тоже интересно стало.
Есть логика намерений и логика обстоятельств, последняя всегда сильнее.