- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我有一个 VCL 表单应用程序,我在其中拦截在 OnKeyPress 和 OnKeyDown 处理程序中按下的键。这适用于常规字符和键,例如 VK_ESC。
但是,当试图捕捉箭头键(VK_UP 和 VK_DOWN)时,它不起作用,因为它们似乎只是在改变主窗体上控件的焦点,而不是触发主窗体的 OnKeyDown 处理程序。
如何捕捉/处理这些按键?
更新:根据以下答案尝试以下操作,但仍然没有成功。
void __fastcall TMain::WndProc(TMessage& Message)
{
switch (Message.Msg)
{
case WM_GETDLGCODE:
Log(lInfo) << "Got WM_GETDLGCODE";
break;
case CM_WANTSPECIALKEY:
Log(lInfo) << "Got WM_WANTSPECIALKEY";
break;
在我的应用程序中使用向上/向下箭头都不会触发上述情况。
我做了以下观察。如果创建一个空的 vcl 表单,上述情况被触发,首先触发 CM_WANSPECIALKEY,然后是 WM_GETDLGCODE。
但是,只要将 TButton 放置在表单上,就不会再触发 case。
我正在使用 C++ Builder XE3。
最佳答案
Windows 保留箭头键用于导航目的。如果一个窗口想要处理箭头键消息,它必须响应 WM_GETDLGCODE
消息并在其返回值中包含 DLGC_WANTARROWS
(或 DLGC_WANTALLKEYS
)标志。
大多数 VCL UI 组件(包括 TForm
)为 WM_GETDLGCODE
返回 0。只有少数标准 VCL 组件响应 DLGC_WANTARROWS
(或 DLGC_WANTALLKEYS
):
TColorGrid
,TToolBar
,TCustomGrid
,TMediaPlayer
,TCustomRibbon
,TRibbonSpinButton
、TSpinButton
、TTabbedNotebook
、TCustomCombo
和 TTabSet
在您的 TForm
类中,覆盖其虚拟 WndProc()
方法,或声明一个 message
处理程序,以处理 WM_GETDLGCODE
,然后你可以返回任何你需要的标志。
void __fastcall TMyForm::WndProc(TMessage &Message)
{
TForm::WndProc(Message);
if (Message.Msg == WM_GETDLGCODE)
Message.Result |= DLGC_WANTARROWS;
}
更新:如果 WM_GETDLGCODE
不起作用,请尝试响应 CM_WANTSPECIALKEY
消息:
void __fastcall TMyForm::WndProc(TMessage &Message)
{
TForm::WndProc(Message);
if (Message.Msg == CM_WANTSPECIALKEY)
{
switch (reinterpret_cast<TCMWantSpecialKey&>(Message).CharCode)
{
case VK_LEFT:
case VK_RIGHT:
case VK_UP:
case VK_DOWN:
Message.Result = 1;
break;
}
}
}
更新:您正尝试在表单本身中处理关键事件,这仅在以下情况下有效:
Form 窗口本身有输入焦点。
子 VCL 窗口接收键消息,并且窗体的 KeyPreview
属性为真。
当窗口子控件(如按钮)具有输入焦点时,键消息将转到该窗口,而不是窗体窗口。为了使 KeyPreview
属性适用于箭头键,获得焦点的子项必须响应 WM_GETDLGCODE
消息,要求操作系统发送箭头键消息。只有这样, child 才能将消息转发给表单进行处理。
默认情况下按钮不要求箭头键消息,因此您必须子类化按钮以手动处理 WM_GETDLGCODE
消息,例如:
class TMain : public TForm
{
__published:
TButton *Button1;
void __fastcall FormKeyDown(TObject *Sender, Word &Key, TShiftState Shift);
void __fastcall FormKeyPress(TObject *Sender, Char &Key);
private:
TWndMethod PrevBtnWndProc;
void __fastcall BtnWndProc(TMessage &Message);
public:
__fastcall TMain(TComponent *Owner);
};
__fastcall TMain::TMain(TComponent *Owner)
: TForm(Owner)
{
PrevBtnWndProc = Button1->WindowProc;
Button1->WindowProc = &BtnWndProc;
}
void __fastcall TMain::BtnWndProc(TMessage &Message
{
PrevBtnWndProc(Message);
if (Message.Msg == WM_GETDLGCODE)
Message.Result |= DLGC_WANTARROWS;
}
void __fastcall TMain::FormKeyDown(TObject *Sender, Word &Key, TShiftState Shift)
{
// works now!
}
void __fastcall TForm7::FormKeyPress(TObject *Sender, Char &Key)
{
// works now!
}
如果您只有几个控件可以子类化,那很好,但是如果您有很多控件,另一种解决方案是让您的 Form 类处理 CM_DIALOGKEY
消息:
void __fastcall TMyForm::WndProc(TMessage &Message)
{
TForm::WndProc(Message);
if (Message.Msg == CM_DIALOGKEY)
{
switch (reinterpret_cast<TCMDialogKey&>(Message).CharCode)
{
case VK_LEFT:
case VK_RIGHT:
case VK_UP:
case VK_DOWN:
// process key as needed...
// set Message.Result to suppress the message further...
Message.Result = 1;
break;
}
}
}
你应该阅读EDN上的以下文章,它很好地解释了VCL如何处理关键消息,以及VCL如何实现可用于拦截关键消息的各种 Hook :
关于c++ - 如何在带有 TButtons 的 VCL 表单应用程序中使用键盘箭头进行输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45845465/
我有一个 Delphi GUI 应用程序(带有 RAD studio 2010),我希望用户能够重新安排他的工作区。我知道如何使 TButton 可以在同一个表单中拖动,但不知道如何让用户能够将按钮从
我正在尝试模拟 TButton 的下拉菜单,如下所示: procedure DropMenuDown(Control: TControl; PopupMenu: TPopupMenu); var
这个问题不太可能对任何 future 的访客有帮助;它只与一个较小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,通常不适用于全世界的互联网受众。如需帮助使此问题更广泛适用,visit the
这里我重现了我遇到过几次的情况。我有两种形式。表格 1 和表格 2。 Form1 有一个编辑字段并连接了 OnKeyup 事件。 Form2 只有一个按钮和 OnClick 相连。当在 Form1 中
以下代码是 Delphi 自行编写的,会引发错误 undeclared identifier TButton unit Unit1; interface uses Winapi.Windows,
我正在将一个大型项目转换为 Firemonkey,并且我们有一些自定义按钮,这些按钮未显示在表单上。我已将问题隔离到一个非常简单的项目: 使用下面的代码,在移动设备和桌面设备上(使用 Delphi X
我目前正在做“圈和叉”作为作业。我生成了一个 10x10 的 TButton 对象数组,但我不知道它们是如何调用的以及如何控制它们: Form1: TForm1; pole: array[1 ..
我正在用 C++ Builder 社区版制作一个简单的刽子手游戏,我的游戏由代表字母的按钮组成,如果字母没有出现在单词中,你就会失去生命,等等。 ..但是,如果我为 abcedary 中的每个字母制作
在我的主窗体上,我有一个 TPanel,其中包含充当工具栏的按钮。我想克隆/复制此工具栏和按钮及其功能到第二种形式。 使用 newmenu.merge(mainmenu) 克隆菜单很简单。这是复制 T
FireMonkey (Delphi XE3) 应用程序中发生以下情况。看下面的代码(这只是一个虚拟示例,用于说明问题): procedure TForm1.Button4Click(Sender:
我正在尝试创建一个虚拟键盘,其中每个按钮都有一个数字和几个字母。例如,数字 2 旁边还会有文本 ABC(字体较小),数字 3 旁边会有 3 DEF 就在它旁边。 我可以成功地一一编辑这些按钮的自定义样
我想在点击按钮时显示一个弹出菜单,但是这个过程在Delphi XE中出现错误。 procedure ShowPopupMenuEx(var mb1:TMouseButton;var X:integer
我正在使用 Delphi XE 并尝试更新旧的 Delphi 代码库。该软件最初是用 Delphi 7 开发的,并使用了 Jonathan Hosking 在 2001 年编写的 TPNGButton
我最近开始将我的 RAD Studio 2007 项目升级到 RAD Studio 2009。我注意到的一件事是看似简单的代码突然无法编译。 示例代码: class CButtonPopupMenu
在我的 Delphi VCL 表单应用程序中,我必须更改 TButton 的背景颜色。有没有办法在不使用第三方组件的情况下应用此更改? 谢谢。 最佳答案 您无法更改 TButton 的颜色组件,而不是
我注意到在我的 iPhone 和 iPad 上运行我的 iOS 应用程序时,OnKeyUp 事件处理确实发生在 TButton 控件上(但我相信它在 Windows模拟器)。但是,OnKeyDown
我有一个 TAction,可用于菜单项和 TButton。我希望菜单项显示标签,并且 TButton 仅显示图标。但是,当分配一个 Action 时,Vcl 会自动设置 TButton 的 Capti
我正在尝试创建一个 THintWindow 并在其上放置一个 TButton 或 TFrame 。这是我的代码: TForm1 = class(TForm) Button1: TButton;
当我尝试使用以下代码行禁用样式化 VCL 上的按钮时 TButton(Sender).enabled:= False; 我得到了这个结果(按钮在运行时禁用) 而不是这个! (按钮在设计时禁用) 将两个
我有一个 VCL 表单应用程序,我在其中拦截在 OnKeyPress 和 OnKeyDown 处理程序中按下的键。这适用于常规字符和键,例如 VK_ESC。 但是,当试图捕捉箭头键(VK_UP 和 V
我是一名优秀的程序员,十分优秀!