線上訂房服務-台灣趴趴狗聯合訂房中心
發文 回覆 瀏覽次數:2714
推到 Plurk!
推到 Facebook!

有參數設定不讓Form上物件的Focus自動接收方向鍵或是Tab的控制嗎?

答題得分者是:smallfox
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#1 引用回覆 回覆 發表時間:2011-06-18 21:59:52 IP:122.127.xxx.xxx 未訂閱
 請教大大們~

我想要能自己處理所有的鍵盤動作

假設Form上擺了幾顆Button, 一個Grid
而方向鍵只想拿來捲動Grid
所以試著將Form.Keypreview設為True
然後在FormKeyDown裡頭攔截鍵盤碼
當判斷為方向鍵時就變動Grid的列號

但是按下方向鍵, 會先移動了按鈕的Focus後, 才會捲動Grid
請問有參數可以設定不讓Delphi自動處理Focus?
還是有什麼方式可以更早攔截到鍵盤碼?

關鍵字:Keypreview, FormKeyDown, Focus, DoOnMessage

編輯記錄
douglas 重新編輯於 2011-06-18 08:04:24, 註解 無‧
douglas 重新編輯於 2011-06-18 08:19:30, 註解 無‧
douglas 重新編輯於 2011-06-19 19:12:42, 註解 無‧
douglas 重新編輯於 2011-06-21 00:20:36, 註解 整理問題描述,希望有需要的人能看懂‧
smallfox
高階會員


發表:2
回覆:113
積分:128
註冊:2003-02-19

發送簡訊給我
#2 引用回覆 回覆 發表時間:2011-06-19 01:46:25 IP:203.67.xxx.xxx 訂閱
在 FormKeyDown 事件中判斷 KEY 為方向鍵時:
若 Grid not Focused, 就 set Grid to Focus
試看看吧 !!
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#3 引用回覆 回覆 發表時間:2011-06-20 09:04:17 IP:125.230.xxx.xxx 未訂閱
在Grid.SetFocus之前,按鈕的Focus已經自動先被方向鍵影響(跳到下一顆按鈕)
然後才會輪到Grid捲動(這個是我在FormKeyUp裡頭判斷為方向鍵時就去改變Grid的列號)
===================引 用 smallfox 文 章===================
在 FormKeyDown 事件中判斷 KEY 為方向鍵時:
若?Grid not Focused, 就 set Grid to Focus
試看看吧 !!
編輯記錄
douglas 重新編輯於 2011-06-20 09:13:05, 註解 無‧
smallfox
高階會員


發表:2
回覆:113
積分:128
註冊:2003-02-19

發送簡訊給我
#4 引用回覆 回覆 發表時間:2011-06-20 22:40:24 IP:211.74.xxx.xxx 訂閱
請問你的 Form 是否是繼承過來的 ?
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#5 引用回覆 回覆 發表時間:2011-06-20 23:10:24 IP:220.141.xxx.xxx 未訂閱
不是繼承的(我還沒那個功力).

我用Delphi2009,全部的物件都是標準的,直接拉出來用
我目前測試的寫法是在Form上擺上幾顆按鈕
Form.Keypreview := True;
然後Form的三個鍵盤事件都設了中斷點
當我按下方向鍵後,可以用肉眼能分辨的速度看見先後順序為:
1 先移動了按鈕的Focus
2 進入FormKeyUp事件裡頭(其他兩個攔不到方向鍵)

(目前正在閱讀Key Hook相關的文章,希望是我要的答案)
===================引 用 smallfox 文 章===================
請問你的 Form 是否是繼承過來的 ?
smallfox
高階會員


發表:2
回覆:113
積分:128
註冊:2003-02-19

發送簡訊給我
#6 引用回覆 回覆 發表時間:2011-06-20 23:35:54 IP:211.74.xxx.xxx 訂閱
我弄懂你的意思了

當 Button 取得 focus 時, 你是無法攔截方向鍵, 似乎它的底層已先處理掉了

能做的是, 盡量不要讓 Button 取得 focus.

如: 設定屬性 TabStop=False, 在 OnClick 事件中處理完程序後, 就把 focus 移走...等

這樣你依舊可以在 FormKeyDown 事件中, 撰寫控制按鍵的程式碼.
smallfox
高階會員


發表:2
回覆:113
積分:128
註冊:2003-02-19

發送簡訊給我
#7 引用回覆 回覆 發表時間:2011-06-20 23:37:20 IP:211.74.xxx.xxx 訂閱
forbidden = O n C l i c k
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#8 引用回覆 回覆 發表時間:2011-06-20 23:46:14 IP:220.141.xxx.xxx 未訂閱
原諒我找到的答案的激動,真的感動到快哭了!!!
我知道從Focus下手算是”表面上看起來正常”的做法
不過我要弄董完全控制鍵盤可能還要花上一段時間 @@"

測試了TabStop可以處理掉Tab鍵
我另外有找到 TForm.ActiveControl,把這個屬性值動態設為nil就可以控制Focus了
===================引 用 smallfox 文 章===================
我弄懂你的意思了
當 Button 取得 focus 時, 你是無法攔截方向鍵, 似乎它的底層已先處理掉了
能做的是, 盡量不要讓 Button 取得 focus.
如: 設定屬性 TabStop=False, 在 OnClick 事件中處理完程序後, 就把 focus 移走...等
這樣你依舊可以在 FormKeyDown 事件中, 撰寫控制按鍵的程式碼.
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#9 引用回覆 回覆 發表時間:2011-06-20 23:48:47 IP:220.141.xxx.xxx 未訂閱
當 Button 取得 focus 時, 你是無法攔截方向鍵, 似乎它的底層已先處理掉了

另外想問關於上述這點,是否有哪個屬性可以設定取消Delphi自動自發的動作阿?

smallfox
高階會員


發表:2
回覆:113
積分:128
註冊:2003-02-19

發送簡訊給我
#10 引用回覆 回覆 發表時間:2011-06-20 23:58:21 IP:211.74.xxx.xxx 訂閱
因為它是元件, 除非你是繼承來改寫, 否則對於原生的元件, 沒有改動的餘地.
(除非你改了 Delphi 所附的 Source .pas 再編譯, 但這對於未來版本升級, 會是風險)

或者, 有興趣可以試看看 Windows API 的方式吧.
jow
尊榮會員


發表:66
回覆:751
積分:1253
註冊:2002-03-13

發送簡訊給我
#11 引用回覆 回覆 發表時間:2011-06-21 12:37:12 IP:112.104.xxx.xxx 未訂閱

[code delphi]
unit fMain;

interface
uses
Windows, Messages, Classes, Controls, Forms, StdCtrls, Dialogs;

type
TForm1 = class(TForm)
Button1: TButton;
procedure FormCreate(Sender: TObject);
private
procedure DoOnMessage(var Msg: TMsg; var Handled: Boolean);
end;

var
Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
Application.OnMessage := DoOnMessage;
end;

procedure TForm1.DoOnMessage(var Msg: TMsg; var Handled: Boolean);
begin
Handled := False;
case Msg.message of
WM_KEYDOWN:
begin
Handled := True;
case Msg.wParam of
VK_TAB: ShowMessage('VK_TAB');
VK_UP: ShowMessage('VK_UP');
VK_DOWN: ShowMessage('VK_DOWN');
VK_LEFT: ShowMessage('VK_LEFT');
VK_RIGHT: ShowMessage('VK_RIGHT');
else Handled := False;
end;
end;
end;

if not Handled then
begin
TranslateMessage(Msg);
DispatchMessage(Msg);
Handled := True;
end;

end;

end.

[/code]

douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#12 引用回覆 回覆 發表時間:2011-06-21 14:24:05 IP:125.230.xxx.xxx 未訂閱
感謝jow大大的分享,這次感受到了Message的威力
確定能在自動處理Focus之前就能攔取到鍵盤碼
而且反應速度比在FormKeyDown裡頭做還要快上一些

編輯記錄
douglas 重新編輯於 2011-06-21 09:14:56, 註解 無‧
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#13 引用回覆 回覆 發表時間:2011-06-21 17:09:00 IP:220.128.xxx.xxx 未訂閱
如果按上下方向鍵,只做移動資料列的動作,又何必理會現在的焦點在哪裡?就簡單地,把 Form.KeyPriview 設為 true,Form 的 KeyDown 判斷是否按了上、下方向鍵,直接呼叫 DataSet 的 Prior 或 Next 就好了。
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#14 引用回覆 回覆 發表時間:2011-06-21 22:47:08 IP:220.141.xxx.xxx 未訂閱
這可能跟我個人的排版還有程式架構有關
我一個專案是由多個Form組合的,例如:
Form1負責輸入,上面擺了多個按鈕
Form2負責顯示,擺了一個Grid
當這專案執行的時候Form1、Form2會同時Show出來
我希望不論何時按下方向鍵都只能捲動Grid
以我目前所知道的技巧就是把全部的Form的Keypreview屬性設為True
不論哪個Form攔截到鍵盤碼都會對應到一張對照表,執行對應的動作
假設使用者隨意操作後,讓現在的Focus在Form1上(有多個按鈕)的某個按鈕
這時候當按下方向鍵想要捲動Grid的時候,就會發生先移動了Form1上某個按鈕的Focus
然後才會判斷鍵盤碼為方向鍵而去捲動Form2的Grid
就是在這樣的情況之下,我才需要各位大大的熱心分享
===================引 用 cancer 文 章===================
如果按上下方向鍵,只做移動資料列的動作,又何必理會現在的焦點在哪裡?就簡單地,把 Form.KeyPriview 設為 true,Form 的 KeyDown 判斷是否按了上、下方向鍵,直接呼叫 DataSet 的 Prior 或 Next 就好了。
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#15 引用回覆 回覆 發表時間:2011-06-22 08:55:24 IP:220.128.xxx.xxx 未訂閱
Hello,通常這種情形,KeyDown 移動資料之後,要順便來個 Key := 0; 把按鍵取消,就等於沒有按任何按鈕。
===================引 用 douglas 文 章===================
假設使用者隨意操作後,讓現在的Focus在Form1上(有多個按鈕)的某個按鈕
這時候當按下方向鍵想要捲動Grid的時候,就會發生先移動了Form1上某個按鈕的Focus
然後才會判斷鍵盤碼為方向鍵而去捲動Form2的Grid
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#16 引用回覆 回覆 發表時間:2011-06-22 22:15:17 IP:220.141.xxx.xxx 未訂閱
在我苦力的測試過程中有個狀況
如果任意操作之後Focus停留在某個Button上
在這個條件之下FormKeyDown是攔不到方向鍵的,只剩下FormKeyUp有作用
在這種狀況下按了方向鍵就會先自動從按紐1跳到按鈕2然後才進入FormKeyUp
在這情況下,我才試著控制物件的Focus
因為如果Form上的任何物件都不要獲得Focus,那麼方向鍵就不會有作用(除非自己控制)

後來jow大大分享的技術,可以直接取得鍵盤的Message,就從根本上解決這個問題
完全不用透過Form的鍵盤事件來處理.
===================引 用 cancer 文 章===================
Hello,通常這種情形,KeyDown 移動資料之後,要順便來個 Key := 0; 把按鍵取消,就等於沒有按任何按鈕。
===================引 用 douglas 文 章===================
假設使用者隨意操作後,讓現在的Focus在Form1上(有多個按鈕)的某個按鈕
這時候當按下方向鍵想要捲動Grid的時候,就會發生先移動了Form1上某個按鈕的Focus
然後才會判斷鍵盤碼為方向鍵而去捲動Form2的Grid
編輯記錄
douglas 重新編輯於 2011-06-22 08:32:27, 註解 無‧
cancer
高階會員


發表:58
回覆:319
積分:190
註冊:2004-07-31

發送簡訊給我
#17 引用回覆 回覆 發表時間:2011-06-23 09:00:25 IP:220.128.xxx.xxx 未訂閱
Hello, 有時候我故意不用 TButton 和 TBitbin,改用 TSpeedButton,它沒有焦點,有焦點的按鈕有一個大問題,焦點跳到這個按鈕之後,鍵盤按了 Enter 就會執行,完全在使用者意料之外。
douglas
初階會員


發表:24
回覆:42
積分:38
註冊:2008-03-05

發送簡訊給我
#18 引用回覆 回覆 發表時間:2011-06-23 15:29:47 IP:125.230.xxx.xxx 未訂閱
感謝大大分享 ^_^  
在下一直都是TButton打天下,沒有深入研究過SpeedButton

我就是因為Delphi"體貼"的舉動才發生悲劇的 @@"
不過因為這個機緣學到了不少新技術倒是非常開心
===================引 用 cancer 文 章===================
Hello, 有時候我故意不用 TButton 和 TBitbin,改用 TSpeedButton,它沒有焦點,有焦點的按鈕有一個大問題,焦點跳到這個按鈕之後,鍵盤按了 Enter 就會執行,完全在使用者意料之外。
系統時間:2024-04-24 3:29:06
聯絡我們 | Delphi K.Top討論版
本站聲明
1. 本論壇為無營利行為之開放平台,所有文章都是由網友自行張貼,如牽涉到法律糾紛一切與本站無關。
2. 假如網友發表之內容涉及侵權,而損及您的利益,請立即通知版主刪除。
3. 請勿批評中華民國元首及政府或批評各政黨,是藍是綠本站無權干涉,但這裡不是政治性論壇!