浮动工具条应该都不会陌生。MS Office Word 、Excel中都有,只要你选中内容就会出现透明淡淡的工具条。鼠标移动到上面就会显示。
要实现浮动效果只要把 ParentHandle = 0 系统就会把控件浮出显示,但效果不好,系统任务条上会出现多余的东西,程序焦点会被显示的控件夺走。
解决这个问题,需要系统的API提供了几个样式扩展参数。
- WS_EX_TOOLWINDOW 这个木,像浮动工具条一样一样样的。
- WS_EX_APPWINDOW 控件浮出来后会在系统工具条上显示出来,作为工具条这个肯定是不应该出现的。
- WS_EX_NOACTIVATE 防止主界面的Active被干掉,保证你界面的Focus有效
- WS_EX_TOPMOST 窗口置顶设置
这种方案适用单一控件浮动控制,主要是因为多控件需要对多种事件进行特殊处理才能达到比较理想的效果。
有效:不需要焦点处理的控件(toolbar),单一控件(如Edit,Listbox 等)
不推荐复合处理,建议特殊处理 如:Frame或Panel中放置了很多需要消息控制的控件。
处理步骤
- 去除ParentHandle控制,让其浮出
- 设置控件样式,让它看起来像一个真的浮动对象
- 处理你需要的响应消息
通过上述3步就能实现一个简单的浮出。
测试环境
- Delphi XE2
- WIN7
代码实现
type
TWinAcc = class(TWinControl);
procedure TForm9.Button3Click(Sender: TObject);
var
cDrop: TWinControl;
v:NativeInt;
begin
cDrop := TListBox.Create(Edit4);
cDrop.Visible := False;
cDrop.Parent := Edit4;
// 设置样式,变成浮动窗体
/// WS_EX_APPWINDOW --- 去掉系统工具条显示
/// WS_EX_NOACTIVATE --- 不使用Active,这样主界面就不会闪烁问题
/// WS_EX_TOOLWINDOW --- (这个木,像浮动工具条一样一样样的)
v := GetWindowLong(cDrop.Handle, GWL_EXSTYLE);
v := v and not WS_EX_APPWINDOW or WS_EX_NOACTIVATE or WS_EX_TOOLWINDOW;
SetWindowLong(cDrop.Handle, GWL_EXSTYLE, v);
// 这个木自然是为了把控件浮出界面
Winapi.Windows.SetParent(cDrop.Handle, 0);
// 这个很重要,由于没有了Active,无法正常处理焦点问题
// 因此需要接收处理 SetFocus 的消息
CallWindowProc(TWinAcc(cDrop).DefWndProc, cDrop.Handle, WM_SETFOCUS, 0, 0);
TListBox(cDrop).Items.Assign(ListBox1.Items);
cDrop.Width := 300;
cDrop.Height := 230;
cDrop.Visible := True;
end;
使用这种方式可以实现一些比较复杂ComboBox的下拉样式。