• TLabel和TEdit的初次显示过程


    procedure TForm1.Button2Click(Sender: TObject);

    var
    l: TLabel;
    begin
    l:=TLabel.Create(self);
    l.Name:='label999';
    l.Caption:='test label';
    l.Left:=10;
    l.Top:=10;
    l.Transparent:=True; // 这句会影响自己的客户区在父控件里显示时背景色是否需要重绘
    l.Parent:=self;
    end;

    这里AControl是图形子控件,即上面的l,以下是主要执行步骤(把所有用到的函数主要语句列出来)
    1. 执行 SetParent
    2. 执行 InsertControl
    3. 执行 Insert(AControl) 此处不算插入前和插入后执行的一大堆检查与通知语句
    4. 执行 AControl.Invalidate;
    5. 执行 TControl.InvalidateControl
    6. 执行 InvalidateRect(Parent.Handle, @Rect, False) 刷新父控件的无效区,当Transparent:=True的时候,第三个参数是True则需要重绘背景

    总结:
    图形控件的显示比较简单,就是计算自己的有效区域后,然后把它的父控件(一定是Win控件)某个区域声明为无效区域。如果是图形控件是透明的,那么还要计算其是否与兄弟图形控件完全重合,重合的话就不用重绘了。不过最重要的是,PaintControls函数里才真正重绘Win控件的所有子图形控件。


    问题:其中是否重合的问题还需要仔细研究,为什么只比较一部分兄弟图形控件呢?当某个控件特别大完全遮住了某个控件时,情况又不一样。

    procedure TForm1.Button4Click(Sender: TObject);
    var
    l: TEdit;
    begin
    l:=TEdit.Create(self);
    l.Name:='edit100';
    l.Text:='test';
    l.Left:=100;
    l.Top:=100;
    l.Parent:=self;
    end;

    1. 子控件执行 SetParent(AParent)
    2. 父控件执行 InsertControl(Self); 其中Self是子控件
    3. 父控件执行 Insert(AControl) 此处不算插入前和插入后执行的一大堆检查与通知语句
    4. 父控件执行 UpdateControlState
    5. 父控件寻找最高层Parent,执行UpdateShowing
    6. 最高层Parent创建句柄后,递归执行UpdateShowing先显示所有子Win控件
    7. 发消息 CM_SHOWINGCHANGED 调用API SetWindowPos 显示自己。问题:为什么不需要调用 UpdateWindow
    8. 在显示Win控件的过程中,所有图形子控件也被一起显示了。

    总结:说到底就是调用API SetWindowPos 显示每一个Win子控件。

    问题1:这个只是初次显示,以后的显示,还要查看Invalidate函数,它只是简单发送CM_INVALIDATE消息,最后发现是调用API InvalidateRect声明整个Win控件客户区都无效。
    声明无效区域仅仅是声明,真正如何重绘,还要看每个Win控件自己如何响应WM_PAINT消息(少数控件,比如TListBox和TComboBox覆盖这个消息)。
    一般情况下还是调用TWinControl.WMPaint,然后调用PaintHandler,它调用BeginPaint PaintWindow PaintControls EndPaint 把所有内容在内存里重绘,最后调用API BitBlt一次性全部贴图。
    问题2:如果有重绘消息,会有无数个各自不同的重绘消息发给不同的Win控件(主窗体上的每一个窗口)?

    ============================================================

    另一种写法也可以显示TEdit,但是与TEdit的显示风格不一致:
    procedure TForm1.Button1Click(Sender: TObject);
    var
    l: TEdit;
    begin
    l:=TEdit.Create(self);
    l.Name:='edit100';
    l.Text:='test';
    l.Left:=100;
    l.Top:=100;
    l.ParentWindow:=Self.Handle;
    l.HandleNeeded;
    // SetWindowPos(l.Handle, BitBtn1.Handle, 0, 0, 0, 0, SWP_NOMOVE + SWP_NOSIZE + SWP_NOACTIVATE);
    end;

    测试Parent的Handle,纯正的Windows的Handle,没有经过Delphi的封装:

    procedure TForm1.Button3Click(Sender: TObject);
    begin
    if ParentWindow=0 then ShowMessage('ParentWindow is nil')
    else ShowMessage('ParentWindow is not nil');
    end;

    procedure TForm1.BitBtn1Click(Sender: TObject);
    begin
    if Edit1.ParentWindow=0 then ShowMessage('ParentWindow is nil')
    else ShowMessage('ParentWindow is not nil');
    exit;
    end;

    另外,可以通过VC直接测试SetWindowPos的功能:

    void CdsdsDlg::OnBnClickedOk()
    {
    int cx = GetSystemMetrics(SM_CXSCREEN);
    int cy = GetSystemMetrics(SM_CYSCREEN);
    int dx = 600;
    int dy = 400;
    SetWindowPos(&wndTopMost,cx-dx,cy-dy,dx,dy,SWP_SHOWWINDOW); //设置窗口于右下角
    }

  • 相关阅读:
    MySQL 分库分表方案
    MySQL高性能优化实战总结
    MySQL太慢?试试这些诊断思路和工具
    Get MySQL这5个优化技巧
    一次MySQL两千万数据大表的优化过程,三种解决方案
    MySQL 常用30种SQL查询语句优化方法
    掌握 MySQL 这 19 个骚操作,效率至少提高3倍
    分分钟解决 MySQL 查询速度慢与性能差
    总结 | 慢 SQL 问题经验总结
    MySQL主从延时这么长,要怎么优化?
  • 原文地址:https://www.cnblogs.com/findumars/p/3917061.html
Copyright © 2020-2023  润新知