Модераторы: Poseidon, Snowy, bems, MetalFan
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> PageControl, прокрутка закладок 
V
    Опции темы
Seroga
Дата 29.10.2014, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 12.10.2008

Репутация: нет
Всего: нет



Здравствуйте!
Собрался я сделать прокрутку мышью закладок у PageControl'а когда они выходят за границы выдимости, как это сделано в например в браузерах. То есть неважно где сейчас фокус, если наводишь мышь на область закладок и крутишь колесо мышки закладки прокручиваются. Другой пример Outlook из офиса, неважно где фокус, куда наводишь мышь в той области и делается прокрутка. Сделал для пробы отлова сообщения так:

Код

TMyPageControl = class(TPageControl)
  private
    procedure WMMouseWheel(var Message: TWMLButtonDblClk); message WM_MOUSEWHEEL;
  end;


Все работает в случае если фокус у компонента который лежит на PageControl'е. То есть тут работает цепочка по которой передается сообщение "выше" на парента и аж до формы. Но когда фокус у контрола который лежит рядом, например на панели, WM_MOUSEWHEEL на PageControl не приходит. Вариант заюзать TApplication.OnMessage нежелателен. Можно ли как-то еще отловить сообщение WM_MOUSEWHEEL если контрол на который оно пришло не имеет в цепочке Parent'ов PageControl?
PM MAIL   Вверх
drkot
Дата 30.10.2014, 13:16 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Вам нужно перехватывать WM_MOUSEWHEEL на уровне формы.
если есть несколько областей реагирующих на колесико, то их можно поместить в разные контейнеры и производить перехват на уровне контейнеров (TPanel)


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
Seroga
Дата 31.10.2014, 17:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 12.10.2008

Репутация: нет
Всего: нет



Не, на уровне формы не подоходит, я же компонент делаю, на каждой форме такое лепить не фонтан.  Насоветовали глянуть в сторону хуков мышки. Начал лазить по исходникам делфи, нашел у компонента Ribbon как раз то что ищу, у него закладки скролятся и сделано через хук. Предварительный вариант такой:

Код

TMyPageControl = class(TPageControl)
  protected
    function DoMouseWheelDown(AShift: TShiftState; AMousePos: TPoint): Boolean; override;
    function DoMouseWheelUp(AShift: TShiftState; AMousePos: TPoint): Boolean; override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

. . .

implementation

{$R *.dfm}

var
  FHookHandle: THandle;

{ TMyPageControl }

function PageControlMouseWheelHook(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
var
  LCtrl: TWinControl;
  LStruct: PMouseHookStructEx;
  LKeyState: TKeyboardState;
begin
  if Code < 0 then begin
    Result := CallNextHookEx(FHookHandle, Code, wParam, lParam);
    Exit;
  end;
  if wParam = WM_MOUSEWHEEL then begin
    LStruct := PMouseHookStructEx(lParam);
    LCtrl := FindControl(WindowFromPoint(LStruct.MouseHookStruct.pt));
    if LCtrl is TMyPageControl then begin
      GetKeyboardState(LKeyState);
      TMyPageControl(LCtrl).DoMouseWheel(Vcl.Forms.KeyboardStateToShiftState(LKeyState),
        ShortInt(LStruct.mouseData shr 16), Point(0, 0));
      Result := 1;
    end else
      Result := CallNextHookEx(FHookHandle, Code, wParam, lParam);
  end else
    Result := CallNextHookEx(FHookHandle, Code, wParam, lParam);
end;

constructor TMyPageControl.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  if not (csDesigning in ComponentState) then begin
    if FHookHandle <> 0 then
      UnhookWindowsHookEx(FHookHandle);
    FHookHandle := SetWindowsHookEx(WH_MOUSE, PageControlMouseWheelHook,
      0, GetCurrentThreadId);
  end;
end;

destructor TMyPageControl.Destroy;
begin
  if FHookHandle <> 0 then
    UnhookWindowsHookEx(FHookHandle);
  inherited Destroy;
end;

function TMyPageControl.DoMouseWheelDown(AShift: TShiftState;
  AMousePos: TPoint): Boolean;
begin
  SelectNextPage(True);
  Result := True;
end;

function TMyPageControl.DoMouseWheelUp(AShift: TShiftState;
  AMousePos: TPoint): Boolean;
begin
  SelectNextPage(False);
  Result := True;
end;

PM MAIL   Вверх
drkot
Дата 1.11.2014, 22:20 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Цитата(Seroga @  31.10.2014,  18:58 Найти цитируемый пост)
Насоветовали глянуть в сторону хуков мышки.

чтоб хорошего насоветовали... а вот всякой пакости как всегда вагон....

Вы отдаете себе отчет в том, что будет если на форме (или приложении) окажутся два и более таких компонента? Как оно будет работать?

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

А так нормальное решение Вам предложено... хотите страдать - страдайте...





--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
bems
Дата 3.11.2014, 06:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



Цитата(drkot @  1.11.2014,  22:20 Найти цитируемый пост)
Вы отдаете себе отчет в том, что будет если на форме (или приложении) окажутся два и более таких компонента? Как оно будет работать?
нормально будет, если ставить общий хук для всех инстансов компонента. например завести счетчик компонентов и ставить хук когда создаётся первый объект и удалять когда удаляется последний. на случай если объект создаётся не в главном треде сделать этот счетчик threadvar (впрочем компоненты все равно толком не работают в не-VCL тредах)



--------------------
Обижено школьников: 8
PM MAIL   Вверх
Seroga
Дата 3.11.2014, 19:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 3
Регистрация: 12.10.2008

Репутация: нет
Всего: нет



Цитата(drkot @ 1.11.2014,  22:20)
Цитата(Seroga @  31.10.2014,  18:58 Найти цитируемый пост)
Насоветовали глянуть в сторону хуков мышки.

чтоб хорошего насоветовали... а вот всякой пакости как всегда вагон....

Вы отдаете себе отчет в том, что будет если на форме (или приложении) окажутся два и более таких компонента? Как оно будет работать?

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

А так нормальное решение Вам предложено... хотите страдать - страдайте...

Ну и в чем тут удобство? А если мне на форме нужны будут эти обработчики, то как быть? 
Как быть с сотней других форм где есть уже PageControl? Их всех перелопатить?

Добавлено через 26 секунд
Цитата(bems @ 3.11.2014,  06:27)
Цитата(drkot @  1.11.2014,  22:20 Найти цитируемый пост)
Вы отдаете себе отчет в том, что будет если на форме (или приложении) окажутся два и более таких компонента? Как оно будет работать?
нормально будет, если ставить общий хук для всех инстансов компонента. например завести счетчик компонентов и ставить хук когда создаётся первый объект и удалять когда удаляется последний. на случай если объект создаётся не в главном треде сделать этот счетчик threadvar (впрочем компоненты все равно толком не работают в не-VCL тредах)

Ну оно вроде так и сделано. Нужно только код из Destroy перенести в finalization.
PM MAIL   Вверх
bems
Дата 4.11.2014, 23:58 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



Цитата(Seroga @  3.11.2014,  19:00 Найти цитируемый пост)
Нужно только код из Destroy перенести в finalization
это можно, а вот из Create просто перенести в initialization нельзя, потому что тогда при использовании компонента в длл это будет обращение к user32 api из DllMain, а это черевато



--------------------
Обижено школьников: 8
PM MAIL   Вверх
drkot
Дата 5.11.2014, 23:51 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ищущий
***


Профиль
Группа: Завсегдатай
Сообщений: 1042
Регистрация: 5.5.2006

Репутация: 5
Всего: 8



Цитата(bems @  3.11.2014,  07:27 Найти цитируемый пост)
общий хук для всех инстансов компонента

только это не соответствует идеологии VCL... а делать то можно... 

Цитата(Seroga @  3.11.2014,  20:00 Найти цитируемый пост)
Ну и в чем тут удобство?

у Вас все PageControl получат уведомление о прокрутке и все прокрутятся. 
Принятие решения о том кому "адресовано" действие равносильно прописыванию общей реакции для формы.
О чем и говорилось выше....

Другими словами хук будет простым решение только для условия одного "живого" PageControl. В остальных случаях решение теряет тривиальность и потребует широкого напильника для каждого конкретного случая.
При этом получение события формой (контейнером) и принятие решения кого крутить остается одинаково тривиальным при любом масштабе задачи.

Цитата(bems @  5.11.2014,  00:58 Найти цитируемый пост)
обращение к user32 api из DllMain

извольте... какой DllMain? Хук то локальный должен быть!


--------------------
Ошибка не становится истиной по причине широкого распространения,
как и Истина не становится Ошибкой из-за того, что никто её не видит.
PM   Вверх
bems
Дата 6.11.2014, 04:18 (ссылка) |    (голосов:1) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 3400
Регистрация: 5.1.2006

Репутация: 31
Всего: 88



Цитата(drkot @  5.11.2014,  23:51 Найти цитируемый пост)
извольте... какой DllMain? Хук то локальный должен быть! 

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


--------------------
Обижено школьников: 8
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "Delphi: Общие вопросы"
SnowyMetalFan
bemsPoseidon
Rrader

Запрещается!

1. Публиковать ссылки на вскрытые компоненты

2. Обсуждать взлом компонентов и делиться вскрытыми компонентами

  • Литературу по Дельфи обсуждаем здесь
  • Действия модераторов можно обсудить здесь
  • С просьбами о написании курсовой, реферата и т.п. обращаться сюда
  • Вопросы по реализации алгоритмов рассматриваются здесь
  • 90% ответов на свои вопросы можно найти в DRKB (Delphi Russian Knowledge Base) - крупнейшем в рунете сборнике материалов по Дельфи


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Snowy, MetalFan, bems, Poseidon, Rrader.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Delphi: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0492 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.