在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
没有内容,不代表没有边框。比如设计期一个空的TImage仍是有边框的。 if (csOpaque in image1.ControlStyle) then ShowMessage('不透明') 再比如: procedure TWinControl.PaintControls(DC: HDC; First: TControl); var I, Count, SaveIndex: Integer; FrameBrush: HBRUSH; begin // 这个DC其实是父Win控件的句柄 // 一共有2处调用此函数。分别是TControl.Repaint和TWinControl.PaintHandler,分别用来重绘图形控件和Win控件(后者包括了图形子控件,也正因为这个才需要执行这个函数) if DockSite and UseDockManager and (DockManager <> nil) then DockManager.PaintSite(DC); // 重画所有子控件(图形和句柄控件) // FControls和FWinControls在TControl.SetParent里调用TWinControl.Insert里增加元素 if FControls <> nil then // 专指图形控件,不包含windows控件 begin I := 0; if First <> nil then begin I := FControls.IndexOf(First); if I < 0 then I := 0; end; Count := FControls.Count; while I < Count do begin with TControl(FControls[I]) do if (Visible or (csDesigning in ComponentState) and not (csNoDesignVisible in ControlStyle)) and RectVisible(DC, Rect(Left, Top, Left + Width, Top + Height)) then // API begin if csPaintCopy in Self.ControlState then Include(FControlState, csPaintCopy); SaveIndex := SaveDC(DC); // API,重画前,保存父控件的DC MoveWindowOrg(DC, Left, Top); // 调用2个API IntersectClipRect(DC, 0, 0, Width, Height); // API,新建一个完全的区域 // 原本图形控件不能接受Windows消息的,现在也接受了。注意传递了父控件的DC Perform(WM_PAINT, DC, 0); // important7,图形控件已经把WM_PAINT消息内容已经填好,就等程序员填写Paint函数加上真正要执行的内容。 RestoreDC(DC, SaveIndex); // API,恢复父控件的DC Exclude(FControlState, csPaintCopy); // 画完之后,去除标记 end; Inc(I); end; end; // 除此以外,还要给Windows子控件额外画边框(因为实体已经画好了)(注意不是给自己画边框) if FWinControls <> nil then // 专指windows控件,不包含图形控件 for I := 0 to FWinControls.Count - 1 do with TWinControl(FWinControls[I]) do if FCtl3D and (csFramed in ControlStyle) and (Visible or (csDesigning in ComponentState) and not (csNoDesignVisible in ControlStyle)) then begin // fixme 可以试试屏蔽这里的语句,看看效果 FrameBrush := CreateSolidBrush(ColorToRGB(clBtnShadow)); // API FrameRect(DC, Rect(Left - 1, Top - 1, Left + Width, Top + Height), FrameBrush); // API 画矩形边框 DeleteObject(FrameBrush); // API FrameBrush := CreateSolidBrush(ColorToRGB(clBtnHighlight)); FrameRect(DC, Rect(Left, Top, Left + Width + 1, Top + Height + 1), FrameBrush); // 画两条线 DeleteObject(FrameBrush); // API end; end; 又看到一个函数: procedure TWinControl.WMWindowPosChanged(var Message: TWMWindowPosChanged); var Framed, Moved, Sized: Boolean; begin // 三明治手法,这里使边框失效 // 判断是否有边框,是否移动了,是否改变了尺寸 Framed := FCtl3D and (csFramed in ControlStyle) and (Parent <> nil) and (Message.WindowPos^.flags and SWP_NOREDRAW = 0); Moved := (Message.WindowPos^.flags and SWP_NOMOVE = 0) and IsWindowVisible(FHandle); // API Sized := (Message.WindowPos^.flags and SWP_NOSIZE = 0) and IsWindowVisible(FHandle); // 如果有边框,并且已经移动或者改变了尺寸,那么使边框无效 if Framed and (Moved or Sized) then InvalidateFrame; // 类函数 fixme 这不是重复了吗? // 仅仅调整边框不够,更主要是调整控件自己的位置 if not (csDestroyingHandle in ControlState) then UpdateBounds; // 类函数,使用API调整控件在屏幕上的位置 inherited; // super 三明治手法,调用程序员潜在的消息函数,并重新计算最大化最小化的限制和坞里的尺寸 // fixme 根据消息的内容,再次使边框无效(如果有显示或隐藏标记的话) if Framed and ((Moved or Sized) or (Message.WindowPos^.flags and (SWP_SHOWWINDOW or SWP_HIDEWINDOW) <> 0)) then InvalidateFrame; // 类函数,简单调用API end; procedure TWinControl.InvalidateFrame; var R: TRect; begin R := BoundsRect; // 类属性,调用方法,简单计算 InflateRect(R, 1, 1); // API InvalidateRect(Parent.FHandle, @R, True); // API end;
留个爪,以后再详细研究~ |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论