Форум: "Основная";
Текущий архив: 2006.10.22;
Скачать: [xml.tar.bz2];
Внизповторяющееся событие MouseWheel Найти похожие ветки
← →
_Guest_ (2006-09-08 09:31) [0]На событие MouseWheel повешено масштабирование карты. Выполняется оно не очень быстро. Можно ли каким-либо образом не обрабатывать событие сразу после первого прокручивания колесика на один сегмент, а дождаться, когда пользователь закончит прокрутку и отмасштабировать все за один хлоп? Спасибо.
← →
StriderMan © (2006-09-08 09:41) [1]повесь Application.OnMessage, и в нем анализируй, закончилось ли масштабирование рисунка. если нет - просто проглатывай WouseWheel.
← →
Сергей М. © (2006-09-08 10:15) [2]
> Выполняется оно не очень быстро
Есть резон вынести масштабирование в доп.код.поток.
При этом основной получит возможность оперативно реагировать на события колеса, анализировать частоту их возникновения, расчитывать требуемый масштаб и передавать доп.потоку расчетное значение для очередного пересчета им масштаба.
← →
_Guest_ (2006-09-08 15:57) [3]
> Сергей М. © (08.09.06 10:15) [2]
> Есть резон вынести масштабирование в доп.код.поток.
> При этом основной получит возможность оперативно реагировать
> на события колеса
Да можно даже и не выносить в дополнительный. Вопрос как узнать в основном что колесико остановилось? Единственное, что приходит в голову - таймер, но это как-то не серьезно.
← →
Сергей М. © (2006-09-08 16:12) [4]
> как узнать в основном что колесико остановилось? Единственное,
> что приходит в голову - таймер, но это как-то не серьезно.
>
Оч даже серьезно.
Ибо иного способа нет и быть не может.
← →
Loginov Dmitry © (2006-09-08 16:37) [5]Заведи в основном потоке таймер. Запускай его при возникновении события скролла. Останавливай в обработчике OnTimer. Здесь же вызывай код перерисовки.
← →
_Guest_ (2006-09-08 16:50) [6]
> Loginov Dmitry © (08.09.06 16:37) [5]
>
> Заведи в основном потоке таймер. Запускай его при возникновении
> события скролла. Останавливай в обработчике OnTimer. Здесь
> же вызывай код перерисовки.
Это уже все сделано. Спасибо. Думал еще как-то можно.
← →
GrayFace © (2006-09-09 12:56) [7]Можно. Например,
var WheelMove:integer; WheelMoving:boolean;
OnMouseWheel:inc(WheelMoves, Delta);
if WheelMoving then exit;
WheelMoving:=true;
WheelMoves:= Delta;
try
Application.ProcessMessages;
finally
WheelMoving:=false;
end;
if WheelMoves<>0 then ScaleMap(WheelMoves);
← →
sniknik © (2006-09-09 23:54) [8]> Думал еще как-то можно.
добавить событие EndWheel... чегото лишнее чегото не хватает... но рабочий, на основе TMemo, думаю понятно будет
1000 это секунда (примерно), надо подобрать, здесь зато времени хватает увидеть.unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TTmtpMemo = class(TMemo)
private
FCountPoint: DWORD;
FThread: THandle;
FEndWheel: TNotifyEvent;
procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
public
property OnEndWheel: TNotifyEvent read FEndWheel write FEndWheel;
end;
TMemo = class(TTmtpMemo);
TForm1 = class(TForm)
Memo1: TMemo;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
procedure EndWheel(Sender: TObject);
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function WaitWheel(Par: TTmtpMemo): Integer;
begin
result:= 0;
with Par do begin
while (GetTickCount() - FCountPoint) < 1000 do
Sleep(100);
FThread:= 0;
FEndWheel(Par);
end;
EndThread(0);
end;
procedure TTmtpMemo.WMMouseWheel(var Message: TWMMouseWheel);
begin
if Assigned(FEndWheel) then begin
if FThread = 0 then begin
Form1.Label1.Caption:= "Start";
FCountPoint:= GetTickCount();
FThread:= BeginThread(nil, 0, Addr(WaitWheel), Self, 0, FThread);
end;
FCountPoint:= GetTickCount();
end;
inherited;
end;
procedure TForm1.EndWheel(Sender: TObject);
begin
Label1.Caption:= "End";
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.OnEndWheel:= EndWheel;
end;
end.
← →
_Guest_ (2006-09-11 10:33) [9]
> sniknik © (09.09.06 23:54) [8]
> .. но рабочий,
Вы павы !!!
> думаю понятно будет
А вот тут Вы ошибаетесь, Мастер :)
Я половины слов таких не знаю :) Но как работает !!! - просто песня.
Субъективно производительность на масштабировании на порядок выросла.
Ночами спать не буду, но разберусь, чтоб в следующий раз не отвлекать :) Спасибо!
← →
GrayFace © (2006-09-12 11:42) [10]sniknik © (09.09.06 23:54) [8]
А TTimer чем не угодил? Он бы был гораздо лучше! И при каждом WM_MOUSEWHEEL можно было бы перевзводить таймер.
В твоем случае код не рабочий, т.к. периодически возможны неожиданные ошибки. Из второго потока надо отправлять сообщение и обрабатывать формой (или вызывать Synchronize в случае TThread).
А лучше всего было бы при рисовании периодически вызывать Application.ProcessMessages и перезапускать процесс рисования, если было прокручено колесико. (рисовать надо на TBitmap, а не на форму). Есть возможность вставить в цикл отрисовки Application.ProcessMessages?
← →
GrayFace © (2006-09-12 11:45) [11]Кстати, в этом коде
FCountPoint:= GetTickCount();
лучше вытащить изif FThread = 0
. Тогда не будет промежуточных отрисовок.
← →
sniknik © (2006-09-12 13:28) [12]> А TTimer чем не угодил? Он бы был гораздо лучше!
на вкус на цвет...
я не считаю, что таймер тут лучше. по одной простой причине, это легко оформить в виде законченного компанента, в отличие от с таймером.
и потом, разговора про то, что лучше/хуже не было, был ответ на "как сделать по другому"
> В твоем случае код не рабочий, т.к. периодически возможны неожиданные ошибки.
> Из второго потока надо отправлять сообщение и обрабатывать формой (или вызывать Synchronize в случае TThread).
синхронизация/сообщение это как раз то, про что говорил, что чегото не хватает.
но я и не ставил целью написать "конечный" код, цель была показать принцип, и как можно проще (и даже это показалось сложным > [9]). разберется, будут вопросы, можно перейти и к тому чего не хватает.
кстати, неожиданных ошибок не будет, если не рисовать на этом же компаненте паралельно еще откуда нибудь, (еще поток/таймер), и для гаранти этого делать при начале отрисовки локирование канваса (что кажется обычная практика).
> Кстати, в этом коде FCountPoint:= GetTickCount(); лучше вытащить из if FThread = 0. Тогда не будет промежуточных отрисовок.
оно есть и "вытащенное", а то на что ты обратил внимаение это начальная инициализация (предотвратить первое случайное срабатывание), возможно лишняя/неоптимальная по количеству строк...
можно было бы так (если оптимизировать) вместо
if Assigned(FEndWheel) then begin
if FThread = 0 then begin
Form1.Label1.Caption:= "Start";
FCountPoint:= GetTickCount();
FThread:= BeginThread(nil, 0, Addr(WaitWheel), Self, 0, FThread);
end;
FCountPoint:= GetTickCount();
end;
так
if Assigned(FEndWheel) then begin
FCountPoint:= GetTickCount();
if FThread = 0 then begin
Form1.Label1.Caption:= "Start"; //ну это думаю и так понятно тоже лишнее, просто паказать процесс визуально
FThread:= BeginThread(nil, 0, Addr(WaitWheel), Self, 0, FThread);
end;
end;
← →
GrayFace © (2006-09-12 20:04) [13]sniknik © (12.09.06 13:28) [12]
я не считаю, что таймер тут лучше. по одной простой причине, это легко оформить в виде законченного компанента, в отличие от с таймером.
Почему?
sniknik © (12.09.06 13:28) [12]
кстати, неожиданных ошибок не будет, если не рисовать на этом же компаненте паралельно еще откуда нибудь, (еще поток/таймер), и для гаранти этого делать при начале отрисовки локирование канваса (что кажется обычная практика).
Будет.
В потоке:FThread:= 0;
и начинается рисование.
В это время крутанули колесо, создается новый поток, который начинает новое рисование.
sniknik © (12.09.06 13:28) [12]
оно есть и "вытащенное"
Не заметил :)
P.S. О, оказывается не я один отбиваю:=
пробелом с 1 стороны. Правда, я это делаю не вседа.
← →
sniknik © (2006-09-12 20:44) [14]> Почему?
ну куда ты будеш таймер лепить если нужно все в один компонент уложить (вместо одной простой функции потока), не, можно конечно и в сам компонент но тогда нужно и create перекрывать и destroy, заморочено и неудобно. (сам попробуй сделать проще чем ниже показано, с таймером)
> В это время крутанули колесо, создается новый поток, который начинает новое рисование.
возможно, но я в общемто не отрицаю, что нормально лучше доделать с событием например.
например вот такunit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ExtCtrls;
const
WM_RUNEDNWEEL = WM_USER + 111;
type
TTmtpMemo = class(TMemo)
private
FCountPoint: DWORD;
FThread: THandle;
FEndWheel: TNotifyEvent;
procedure WMMouseWheel(var Message: TWMMouseWheel); message WM_MOUSEWHEEL;
procedure WMRunEndWheel(var Message: TMessage); message WM_RUNEDNWEEL;
public
property OnEndWheel: TNotifyEvent read FEndWheel write FEndWheel;
end;
TMemo = class(TTmtpMemo);
TForm1 = class(TForm)
Memo1: TMemo;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
private
procedure EndWheel(Sender: TObject);
public
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
function WaitWheel(Par: TTmtpMemo): Integer;
begin
result:= 0;
with Par do begin
while (GetTickCount() - FCountPoint) < 1000 do
Sleep(100);
FThread:= 0;
PostMessage(Handle, WM_RUNEDNWEEL, 0, 0);
end;
EndThread(0);
end;
procedure TTmtpMemo.WMMouseWheel(var Message: TWMMouseWheel);
begin
if Assigned(FEndWheel) then begin
FCountPoint:= GetTickCount();
if FThread = 0 then begin
Form1.Label1.Caption:= "Start";
FThread:= BeginThread(nil, 0, Addr(WaitWheel), Self, 0, FThread);
end;
end;
inherited;
end;
procedure TTmtpMemo.WMRunEndWheel(var Message: TMessage);
begin
FEndWheel(self);
end;
procedure TForm1.EndWheel(Sender: TObject);
begin
Label1.Caption:= "End";
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Memo1.OnEndWheel:= EndWheel;
end;
end.
но только хотелось бы чтобы это делал уже не я...
← →
sniknik © (2006-09-12 20:47) [15]кстати, тогда уж и в WMRunEndWheel проверку на Assigned(FEndWheel) надо добавить, а то мало ли кто куда какие события шлет...
Страницы: 1 вся ветка
Форум: "Основная";
Текущий архив: 2006.10.22;
Скачать: [xml.tar.bz2];
Память: 0.5 MB
Время: 0.042 c