如何在不从活动窗口中窃取焦点的情况下保持表单始终在顶部? [英] How to keep a Form always on top without stealing focus from the active Window?
问题描述
我的问题:如何让我的表单始终保持在最前面(我可以设置 TopMost = true
),而不会在与我的表单交互时从当前活动的窗口中窃取焦点.>
查看图像以更好地理解我的问题:表单位于顶部,当我关注表单之外的任何其他输入控件时,我可以将选定的表情符号发送给它.
1:当我单击表单中的表情符号按钮时,我希望在 FireFox 的输入框中发生的图像.
2:我的表单的图像:只要我在我的表单中单击一个按钮,焦点就会移回该表单.
- 制作一个标准的Form,设置它的
FormBorderStyle = none
.设为 TopMost(此设置本身是另一个主题,我不打算在这里讨论它). - 覆盖
使用命名空间系统;使用命名空间 System::ComponentModel;使用命名空间 System::Windows::Forms;使用命名空间 System::Drawing;公共引用类 frmKeyBoard : 公共系统::Windows::Forms::Form{民众:frmKeyBoard(void) { InitializeComponent();}//[...] 初始化...受保护:属性 System::Windows::Forms::CreateParams^ CreateParams {虚拟系统::Windows::Forms::CreateParams^ get() 覆盖{auto cp = Form::CreateParams;cp->ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW);返回cp;}}//所有按钮的事件处理程序私人的:System::Void buttonNoSelAll_Click(System::Object^ sender, System::EventArgs^ e) {Control^ctl = safe_cast
(sender);SendKeys::Send(ctl->Tag->ToString());}}; 将这个简单的自定义控件添加到项目中.
此控件仅使用 Control.SetStyle,设置ControlStyles::Selectable = false
,防止子Control在交互时变成ActiveControl,因为它没有获得焦点.使用命名空间系统;使用命名空间 System::Windows::Forms;使用命名空间 System::ComponentModel;命名空间自定义控件{[工具箱项目(真)]公共引用类 ButtonNoSel : 公共系统::Windows::Forms::Button{民众:ButtonNoSel(void) {this->InitializeComponent();this->SetStyle(ControlStyles::Selectable, false);}私人的:无效初始化组件(无效){this->UseVisualStyleBackColor = true;}受保护://删除托管资源,如果有的话~ButtonNoSel() { this->!ButtonNoSel();}//删除非托管资源,如果有的话!ButtonNoSel() { }};}
注意这个Form必须在自己的线程上运行.
如果您需要从另一个表单中显示此表单,请使用 Task.Run() 将其显示为对话框窗口,调用ShowDialog()
.这将启动消息循环.例如,来自另一个表单的
Button.Click
处理程序(此处名为MainForm
).私有:无效显示键盘(){frmKeyBoard^ fk = gcnew frmKeyBoard();fk->ShowDialog();删除 fk;}私人的:System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {Task::Run(gcnew Action(this, &MainForm::ShowKeyboard));}
My question: how I can keep my Form always on top (I can do it setting
TopMost = true
) without stealing the focus from the Window currently active when my Form is interacted with.Take a look at the images to better understand my question: the Form is on top and when I focus on any other Input control outside my Form, I can send the selected Emoji to it.
1 : An Image what I want to happen in an input box in FireFox when I click an Emoji Button in my Form.
2 : An Image of my Form: as soon as I click a Button in my Form, the focus moves back to that Form.
解决方案- Make a standard Form, set its
FormBorderStyle = none
. Make it TopMost (this setting is another topic per se, I'm no going to discuss it here). - Override CreateParams to set the
WS_EX_NOACTIVATE
andWS_EX_TOOLWINDOW
extended styles. This prevents the Form from being activated when mouse events are generated inside its surface (see the docs about these styles). - Add some non-selectable Button Controls to it (the
ButtonNoSel
Control shown below) and set theirTag
property to the Unicode char corresponding to the Emoji image these buttons show. - Add the same Click handler to all the Buttons.
These Buttons, when clicked, simply use SendKeys::Send() (a.k.a.
SendInput()
) to send the selected Unicode char to the foreground Window, casting to string theTag
property value.This is how it works (setting the Emoji to a Web Page shown by FireFox):
using namespace System; using namespace System::ComponentModel; using namespace System::Windows::Forms; using namespace System::Drawing; public ref class frmKeyBoard : public System::Windows::Forms::Form { public: frmKeyBoard(void) { InitializeComponent(); } // [...] Initialization... protected: property System::Windows::Forms::CreateParams^ CreateParams { virtual System::Windows::Forms::CreateParams^ get() override { auto cp = Form::CreateParams; cp->ExStyle |= (WS_EX_NOACTIVATE | WS_EX_TOOLWINDOW); return cp; } } // Event handler for all the Buttons private: System::Void buttonNoSelAll_Click(System::Object^ sender, System::EventArgs^ e) { Control^ ctl = safe_cast<Control^>(sender); SendKeys::Send(ctl->Tag->ToString()); } };
Add this simple Custom Control to the Project.
This Control simply uses Control.SetStyle, settingControlStyles::Selectable = false
to prevent the child Control to become the ActiveControl when interacted with, since it doesn't receive the focus.using namespace System; using namespace System::Windows::Forms; using namespace System::ComponentModel; namespace CustomControls { [ToolboxItem(true)] public ref class ButtonNoSel : public System::Windows::Forms::Button { public: ButtonNoSel(void) { this->InitializeComponent(); this->SetStyle(ControlStyles::Selectable, false); } private: void InitializeComponent(void) { this->UseVisualStyleBackColor = true; } protected: // delete managed resources, if any ~ButtonNoSel() { this->!ButtonNoSel(); } // delete unmanaged resources, if any !ButtonNoSel() { } }; }
Note that this Form must run on its own thread.
If you need to show this Form from another one, use Task.Run() to show it as a Dialog Window, callingShowDialog()
. This will start the Message Loop.For example, from a
Button.Click
handler of another Form (here, namedMainForm
).private: void ShowKeyboard() { frmKeyBoard^ fk = gcnew frmKeyBoard(); fk->ShowDialog(); delete fk; } private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { Task::Run(gcnew Action(this, &MainForm::ShowKeyboard)); }
这篇关于如何在不从活动窗口中窃取焦点的情况下保持表单始终在顶部?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
- Make a standard Form, set its