Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2007.04.22;
Скачать: CL | DM;

Вниз

есть ли разница между onKeyUp и onKeyPress?   Найти похожие ветки 

 
Creative   (2006-11-27 17:06) [0]

Пытаюсь описать собственный класс окна. Все работает, но удивляет одна вещь. У меня обрабабывается событие onKeyPress, пишу аналогичную обработку событие onKeyUp. Результат - тот же самый. Все событие, которе должны происходить, происходят, пока клавише нажата. Разве они не должны происходить только при ее отпускании? Почему так происходит?


type TWndCore = class
    private
     ......//все нужные поля

    OnKeyPress     : procedure;
    OnKeyUp        : procedure;
    constructor CreateWnd(Width, Height : integer; FullScreen, VSync : boolean; ColorDepth, Freq : integer);
    destructor Destroy(); override;
    function  MessageOperations(hInstance : HINST; hPrevInstance : HINST; lpCmdLine : PChar; nCmdShow : Integer) : Integer; stdcall;

===============

function TWndCore.MessageOperations(hInstance, hPrevInstance: HINST;
 lpCmdLine: PChar; nCmdShow: Integer): Integer;
var Msg : TMsg;
begin
.........

if @OnKeyPress <> nil then OnKeyPress;
if @OnKeyUp <> nil then OnKeyUp;
end;


Основной код



procedure KeyUp;
begin
if Keys[VK_UP] then DoSmth1;
end;

procedure KeyPress;
begin
if Keys[VK_UP] then DoSmth2;
end;

begin
Wnd := TWndCore.CreateWnd(640, 480, false, true, 32, 60);
Wnd.OnKeyPress := KeyPress;
Wnd.OnKeyUp := KeyUp;

Wnd.MessageOperations(hinstance, hprevinst, cmdline, cmdshow)
end.


 
Игорь Шевченко ©   (2006-11-27 17:15) [1]


> есть ли разница между onKeyUp и onKeyPress?


Есть.


> Пытаюсь описать собственный класс окна
> ...


> Почему так происходит?


Потому что кривой класс окна ?


 
Creative   (2006-11-27 17:25) [2]


> > Почему так происходит?
> Потому что кривой класс окна ?


а здесь можно как-то прикрепить файл? можно было бы предъявить исходник.


 
Игорь Шевченко ©   (2006-11-27 17:27) [3]

Creative   (27.11.06 17:25) [2]

Нет, файл здесь нельзя прикрепить, можно только код в сообщение вставить.
Но судя по всему, у тебя какая-то своя обработка, которой в приведенном коде не видно. Событие OnKeyUp срабатывает в ответ на сообщение WM_KEYUP, а OnKeyPress на сообщение WM_CHAR. Как видишь, разница есть.


 
Creative   (2006-11-27 17:35) [4]

Проблема в том, что конкетно обработку событий я стянула из чужого кода и в том-то и дело что в нем НЕ БЫЛО никакой своей обработки. Я привела в первом посте все, что касалось событий. Поэтому я и думала, что описанные приемы - это что-то принятое и понятное системе и достаточно только написать то, что мне нужно, аналогичным образом - и все будет работать.


 
Игорь Шевченко ©   (2006-11-27 17:37) [5]

Creative   (27.11.06 17:35) [4]


> Проблема в том, что конкетно обработку событий я стянула
> из чужого кода


Два варинта - либо криво стянула, либо чужой код крив. Я не увидел в приведенном фрагменте ничего, что бы относилось к обработке этих событий, а с телепатией у меня в понедельник плохо. Что знал - рассказал, будет больше кода, будет больше рассказов


 
Creative   (2006-11-27 17:40) [6]

Да я-то с удовольствием, но он велик слишком. Не лучше будет по почте?


 
Игорь Шевченко ©   (2006-11-27 17:47) [7]

Creative   (27.11.06 17:40) [6]

Во-первых, можно кусками. До 7168 байт в сообщение можно вставить. Не относящиеся к проблеме части кода можно убрать. Во-вторых, выкладывая код в форум ты привлекаешь всех посетителей. В третьих, посылая что-то по почте, ты просишь техподдержку, вынуждая конкретного адресата заниматься твоей пролемой.


 
Creative   (2006-11-27 17:49) [8]

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


unit Core;

interface

uses Windows, Messages, OpenGL;

const ApplicationName = "RenderPort";

var keys : Array[0..255] of Boolean;

type TWndCore = class
    private
    FHandle  : HWND;
    FHDC     : HDC;
    FGLRC    : HGLRC;
    FWidth   : integer;
    FHeight  : integer;
    FRenderPort       : TWndClass;
    FoldScreenWidth   : integer;
    FoldScreenHeight  : integer;
    FScrMode          : TDeviceMode;
    FMainAction : Pointer;
    FFullScreen       : boolean;
    FBPP             : integer;
    FFreq            : integer;
    FVertSync        : boolean;
    WGL_EXT_swap_control : boolean;
    FActive : boolean;
    protected
    procedure GraphicInit;
    procedure GraphicFree;
    procedure RefreshRenderPort;
    function  ChangeDisplayMode(Width, Height, BPP, Freq : integer) : boolean;
    public
    OnBeforeRender : procedure;
    OnRender       : procedure;
    OnAfterRender  : procedure;
    OnKeyPress     : procedure;
    constructor CreateWnd(Width, Height : integer; FullScreen, VSync : boolean; ColorDepth, Freq : integer);
    destructor Destroy(); override;
    procedure PreparePort(FullScreen : boolean; ColorDepth : integer);
    procedure SwapBuffers;
    procedure ResizePort(Width, Height : integer);
    function  MessageOperations(hInstance : HINST; hPrevInstance : HINST; lpCmdLine : PChar; nCmdShow : Integer) : Integer; stdcall;
end;



 
Creative   (2006-11-27 17:50) [9]


var ScrWidth,
   ScrHeight,
   ScrBPP,
   ScrFreq : integer;
   glext : string;
   wglGetSwapIntervalEXT : function : GLint; stdcall;
   wglSwapIntervalEXT : function(interval : GLint) : Boolean; stdcall;

implementation

{ TWndCore }

constructor TWndCore.CreateWnd(Width, Height: integer; FullScreen, VSync: boolean; ColorDepth, Freq: integer);
var dwstyle : DWORD;
   dwexstyle : DWORD;
   h_Inst : HINST;

function MainAction(hWnd: HWND; Msg: UINT;  wParam: WPARAM;  lParam: LPARAM): LRESULT; stdcall;
begin
Result := 0;
 case (Msg) of
   WM_CREATE:
     begin
       //
     end;
   WM_CLOSE:
     begin
       PostQuitMessage(0);
       Result := 0
     end;
   WM_KEYDOWN:
     begin
       keys[wParam] := True;
       Result := 0;
     end;
   WM_KEYUP:
     begin
       keys[wParam] := False;
       Result := 0;
     end;
   WM_SIZE:
     begin
       ResizePort(LOWORD(LPARAM), HIWORD(LPARAM));
       Result := 0;
     end;
   WM_LBUTTONDOWN:
     begin
       //
     end;
   WM_LBUTTONUP:
     begin
       //
     end;
   WM_MOUSEMOVE:
     begin
       //
     end;
   WM_TIMER :
     begin
       Result := 0;
       end;
   else
     Result := DefWindowProc(hWnd, Msg, wParam, lParam);
 end;
end;


 
Creative   (2006-11-27 17:53) [10]

Пропущены стандартные условия создания окна (if FullScreenб ChangeDisplayMode и всякое такое) и подготовка контекста устройства (окно пишется для последующей работы с OpenGL)


function TWndCore.MessageOperations(hInstance, hPrevInstance: HINST;
 lpCmdLine: PChar; nCmdShow: Integer): Integer;
var Msg : TMsg;
begin
FActive := true;
while FActive do begin
 if (PeekMessage(msg, 0, 0, 0, PM_REMOVE)) then begin
 if (msg.message = WM_QUIT) or (msg.message = WM_CLOSE) then
 FActive := false
   else begin
   TranslateMessage(msg);
   DispatchMessage(msg);
   end;
 end;

RefreshRenderPort;
if @OnRender <> nil then OnRender;
if @OnKeyPress <> nil then OnKeyPress;

SwapBuffers;
end;

Destroy();
Result := Msg.wParam;
end;



 
Игорь Шевченко ©   (2006-11-27 17:53) [11]

И зачем тебе требуется OnKeyPress при такой обработке ? Насколько я вижу, этот код позволяет узнать нажата ли в данный момент кнопка, а не вызвать пользовательский обработчик по нажатию/отпусканию кнопки.

В чем задача-то ?


 
Creative   (2006-11-27 17:55) [12]

Соственно основной код. Код исходный, без моих искажений.

program Start;

uses Windows, Core, OpenGL;

var Wnd : TWndCore;
   C: TCube;

{$R *.res}

procedure DrawCube;
begin
C.Render;
end;

procedure KeyPress;
begin
if Keys[VK_LEFT] then C.RotateY(-3);
if Keys[VK_RIGHT] then C.RotateY(3);
if Keys[VK_DOWN] then C.Move(-0.1);
end;

begin
Wnd := TWndCore.CreateWnd(640, 480, false, true, 32, 60);
C:= TCube.Create;
Wnd.OnRender := DrawCube;
Wnd.OnKeyPress := KeyPress;
Wnd.MessageOperations(hinstance, hprevinst, cmdline, cmdshow)
end.



 
Creative   (2006-11-27 17:58) [13]


> Игорь Шевченко ©   (27.11.06 17:53) [11]
> В чем задача-то ?


Задачка в том, что мне нужно, чтобы по нажатию клавиши последовательно перерисовывались картинки. Но если я использую это событие onKeyPress - они перерисовываются слишком быстро, не успеваешь клавишу оторвать, уже несколько мелькнуло. Мне посоветовали повесить обработчик на onKeyUp.
А конкретно этот код понравился мне (в отличие от стандартного Winmin`а) тем, что в отновном проекте не болтается бешеное количество служебных процедур.


 
Игорь Шевченко ©   (2006-11-28 10:22) [14]

Creative   (27.11.06 17:58) [13]


> Задачка в том, что мне нужно, чтобы по нажатию клавиши последовательно
> перерисовывались картинки. Но если я использую это событие
> onKeyPress - они перерисовываются слишком быстро, не успеваешь
> клавишу оторвать, уже несколько мелькнуло. Мне посоветовали
> повесить обработчик на onKeyUp.


Для этой задачки этот код вроде не подходит. Этот код подходит для того, чтобы в программе путем опроса определять, нажата ли в текущий момент определенная клавиша. Но никакой реакции на момент нажатия (или отпускания) клавиши этот код не подразумевает.
Может быть, попробовать стандартный способ ?


 
Creative   (2006-11-28 11:08) [15]


> Этот код подходит для того, чтобы в программе путем опроса
> определять, нажата ли в текущий момент определенная клавиша.
>  Но никакой реакции на момент нажатия (или отпускания) клавиши
> этот код не подразумевает.
> Может быть, попробовать стандартный способ ?


Да, но в действие то происходит момент нажатия клавиши. Как же так?

Стандартный способ - вы имеете в виду нечто, аналогичное тому как обрабатываются событие в VCL? Потому что я сейчас как раз думаю рассмотреть как это сделано там, и переписать для себя. Если это не очень глупо.


 
Игорь Шевченко ©   (2006-11-28 11:57) [16]

Creative   (28.11.06 11:08) [15]


> Да, но в действие то происходит момент нажатия клавиши.
> Как же так?


Из приведенного кода я не вижу, что действие (хоть какое-то) происходит в момент нажатия клавиши. По приведенному коду (в посте[0]) мне непонятно, в какой момент производится вызов твоих обработчиков OnKeyUp и OnKeyPress.

Может, тебе подойдет такой способ:

function MainAction(hWnd: HWND; Msg: UINT;  wParam: WPARAM;  lParam: LPARAM): LRESULT; stdcall;
var
 WndCoreInstance: TWndCore;

begin
 Result := 0;
WndCoreInstance := TWndCore(GetWindowLong(hWnd, GWL_USER));
 case (Msg) of
  WM_NCCREATE:
    begin
      WndCoreInstance := TWndCore(
        PCreateStruct(LParam)^.lpCreateParams);
      SetWindowLong(hWnd, GWL_USER, Integer(WndCoreInstance));
    end;
 
  WM_CREATE:
    begin
      //
    end;
  WM_CLOSE:
    begin
      PostQuitMessage(0);
      Result := 0
    end;
  WM_KEYDOWN:
    begin
      keys[wParam] := True;
      Result := 0;
      if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.OnKeyDown) then
        WndCoreInstance.OnKeyDown(WndCoreInstance);
   
    end;
  WM_KEYUP:
    begin
      keys[wParam] := False;
      Result := 0;
      if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.OnKeyUp) then
        WndCoreInstance.OnKeyUp(WndCoreInstance);
   
    end;
...........
end;


И в том месте, где в WndCore создается окно, в CreateWindow или в CreateWindowEx последним параметром вставить Self


 
Creative   (2006-11-28 12:08) [17]


> Из приведенного кода я не вижу, что действие (хоть какое-
> то) происходит в момент нажатия клавиши. По приведенному
> коду (в посте[0]) мне непонятно, в какой момент производится
> вызов твоих обработчиков OnKeyUp и OnKeyPress.
>
> Может, тебе подойдет такой способ:


Если честно, из кода мне тоже это непонятно, поэтому я здесь. Я просто вижу, что оно происходит, но не могу объяснить почему.

А ваш способ обязательно сейчас попробую.


 
Creative   (2006-11-28 12:16) [18]


> WM_NCCREATE:


а что это такое?


 
Creative   (2006-11-28 12:22) [19]

Есть два затруднения:

1. GWL_USER - undeclared identifier
2. WndCoreInstance.OnKeyDown(WndCoreInstance) - too many actual parameters


 
Игорь Шевченко ©   (2006-11-28 12:27) [20]

Creative   (28.11.06 12:08) [17]


> > WM_NCCREATE:
>
>
> а что это такое?


Это сообщение Windows


> 1. GWL_USER - undeclared identifier


Виноват, GWL_USERDATA


 
Игорь Шевченко ©   (2006-11-28 12:28) [21]


> 2. WndCoreInstance.OnKeyDown(WndCoreInstance) - too many
> actual parameters


Тогда просто WndCoreInstance.OnKeyDown; и WndCoreInstance.OnKeyUp;


 
Creative   (2006-11-28 12:34) [22]

а с избыточностью параметров как быть?


 
Creative   (2006-11-28 12:36) [23]

Откомпилиться-то он откомпилился, но при запуске выдает ошибку:
Failed to get a FB render port context.


 
Creative   (2006-11-28 12:39) [24]

...и выдает он ее в соответствии вот с этим кодом:

if FHandle = 0 then begin
MessageBox(FHandle, "Failed to get a FB render port context.", "Fatal error", MB_OK  or MB_ICONERROR);
Destroy();
exit;


Насколько я поняла, это потому что

FHandle := CreateWindowEx(dwexstyle, ApplicationName, ApplicationName, dwstyle, 0, 0, Width, Height, 0, 0, h_Inst, self);

либо вообще не происходит, либо происходит как-то криво


 
Creative   (2006-11-28 12:41) [25]

И начинается эта кривизна, как только в коде появляется обработка сообщения WM_NCCREATE


 
Игорь Шевченко ©   (2006-11-28 12:53) [26]

В обработку сообщения WM_NCCREATE добавь перед end строку:
Result := DefWindowProc(hWnd, Msg, wParam, lParam);


 
Creative   (2006-11-28 13:05) [27]

Отчет.
Все запускается, но работает следующим образом:

1. KeyDown работает точно, при этом очень хорошо заметно, насколько он отличается от KeyPress.
2. KeyUp - не работает вовсе. Она начинает работать, если в MessageOperations написать строку if @OnKeyUp <> nil then OnKeyUp; (аналогично if @OnKeyPress <> nil then OnKeyPress, которая стояла там раньше), но при этом она и работает как KeyPress. по-моему это неправильно.
Как заставить работать KeyUp?


 
Игорь Шевченко ©   (2006-11-28 13:17) [28]

Creative   (28.11.06 13:05) [27]

В MessageOperations наверное вообще ничего не надо писать ? Какой смысл вызывать процедуру, реагирующую на нажатие кнопок, при обработке каждого сообщения ?

А зачем ее (процедуру OnKeyUp) вообще вызывать ?


 
Creative   (2006-11-28 13:29) [29]


> А зачем ее (процедуру OnKeyUp) вообще вызывать ?


Если я правильно понимаю, то все равно придется вернуться к тому, что собственно в WM_KEYUP писать обработку нажатий всех клавиш, которые мне нужны. Или нет? Извините, пожалуйста, но я не совсем ясно вас понимаю.


 
Игорь Шевченко ©   (2006-11-28 13:43) [30]

Creative   (28.11.06 13:29) [29]

Если тебе надо по нажатию на кнопку делать какие-то действия, то и делай. Зачем делать что-то по ее (кнопки) отпусканию ?


 
Creative   (2006-11-28 13:49) [31]

Вы знаете, я посмотрела и решила, что действительно - KeyDown вполне достаточно. Спасибо вам большое.
У меня только один вопрос еще: не могли бы вы объяснить, что сейчас происходит в обработке сообщения WM_NCCREATE?


 
Игорь Шевченко ©   (2006-11-28 13:55) [32]

Creative   (28.11.06 13:49) [31]

В обработчике сообщения NCCREATE происходит установка соответствия между окном и экземпляром класса TWndCore, для того, чтобы потом, зная HWND окна, можно было легко и просто узнать экземпляр класса WndCore, создавший это окно.


 
Creative   (2006-11-28 14:01) [33]

Скажите, а я могу аналогичным образом
(if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.OnKeyDown) then
       WndCoreInstance.OnKeyDown;)
обрабатывать и другие сообщения?


 
Creative   (2006-11-28 14:04) [34]

Извиняюсь, выяснила, что кажется могу :-)


 
Игорь Шевченко ©   (2006-11-28 14:08) [35]

Creative   (28.11.06 14:01) [33]


> Скажите, а я могу аналогичным образом
> (if Assigned(WndCoreInstance) and Assigned(WndCoreInstance.
> OnKeyDown) then
>        WndCoreInstance.OnKeyDown;)
> обрабатывать и другие сообщения?


Безусловно



Страницы: 1 вся ветка

Текущий архив: 2007.04.22;
Скачать: CL | DM;

Наверх




Память: 0.57 MB
Время: 0.112 c
1-1172653682
Alexander_K
2007-02-28 12:08
2007.04.22
Borland Developer Studio 2006 и MapX


15-1175081770
Юрий
2007-03-28 15:36
2007.04.22
Вложенные запросы SQL


1-1172500673
Степан
2007-02-26 17:37
2007.04.22
Тень от формы


15-1174690671
eXPell
2007-03-24 01:57
2007.04.22
Ну, разве что для интереса)))


10-1131624226
Ruslanyd
2005-11-10 15:03
2007.04.22
Подключение к открытому файлу *.xls