gpt4 book ai didi

delphi - Ownerdraw TListBox 子控件不通过滚动移动

转载 作者:行者123 更新时间:2023-12-02 23:16:32 26 4
gpt4 key购买 nike

procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
Rect: TRect; State: TOwnerDrawState);
begin
inherited;
TListBox(Control).Canvas.FillRect(Rect);
TListBox(Control).Canvas.TextOut(Rect.Left+5, Rect.Top+8, TListBox(Control).Items[Index]);
if odSelected in State then
begin
Button.Left:=Rect.Right-80;
Button.Top:=Rect.Top+4;
Button.Visible:=true;
Button.Invalidate;
end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
ListBox1.DoubleBuffered:=true;
ListBox1.ItemHeight:=30;
ListBox1.Style:=lbOwnerDrawFixed;
Button:=TButton.Create(ListBox1);
Button.Parent:=ListBox1;
Button.DoubleBuffered:=true;
Button.Visible:=false;
Button.Width:=50;
Button.Height:=20;
Button.Caption:='BTN';
end;

screenshot 1

screenshot 2

仅当使用 ScrollBar 或向我的 ListBox 发送 WM_VSCROLL 消息时才存在重绘问题。当我使用键盘箭头或鼠标单击更改选择时,通常会绘制所有内容。当所选项目通过滚动可见并且不离开可见区域时,也不存在问题。

我认为 Button.Top 属性在 DrawItem 调用之前仍然具有旧值,并在稍后更改(例如更改为 -30px)。

最佳答案

问题在于您正在使用 OnDrawItem 事件来更改 UI(在本例中为定位按钮)。不要这样做,该事件仅供抽奖。

我建议您:

  1. 子类化 ListBox 以处理 WM_VSCROLL 消息,并让消息处理程序根据需要重新定位按钮。

    var
    PrevListBoxWndProc: TWndMethod;

    procedure TForm1.FormCreate(Sender: TObject);
    begin
    PrevListBoxWndProc := ListBox1.WindowProc;
    ListBox1.WindowProc := ListBoxWndProc;
    end;

    procedure TForm1.FormDestroy(Sender: TObject);
    begin
    ListBox1.WindowProc := PrevListBoxWndProc;
    end;

    procedure TForm1.PositionButton(Index: Integer);
    var
    R: TRect;
    begin
    if Index <= -1 then
    Button.Visible := False
    else
    begin
    R := ListBox1.ItemRect(Index);
    Button.Left := R.Right - 80;
    Button.Top := R.Top + 4;
    Button.Visible := True;
    end;
    end;

    var
    LastIndex: Integer = -1;

    procedure TForm1.ListBox1Click(Sender: TObject);
    var
    Index: Integer;
    begin
    Index := ListBox1.ItemIndex;
    if Index <> LastIndex then
    begin
    LastIndex := Index;
    PositionButton(Index);
    end;
    end;

    procedure TForm1.ListBoxWndProc(var Message: TMessage);
    begin
    PrevListBoxWndProc(Message);
    if Message.Msg = WM_VSCROLL then
    PositionButton(ListBox1.ItemIndex);
    end;
  2. 完全删除TButton。使用 OnDrawItem 将按钮的图像(您可以使用 DrawFrameControl()DrawThemeBackground() 来实现)直接绘制到 ListBox 上,然后使用 OnMouseDown/UpOnClick 事件来检查鼠标是否位于“按钮”上方,如果是,则根据需要进行相应操作。

    var
    MouseX: Integer = -1;
    MouseY: Integer = -1;

    procedure TForm1.ListBox1DrawItem(Control: TWinControl; Index: Integer;
    Rect: TRect; State: TOwnerDrawState);
    var
    R: TRect;
    P: TPoint;
    BtnState: UINT;
    begin
    TListBox(Control).Canvas.FillRect(Rect);
    TListBox(Control).Canvas.TextOut(Rect.Left+5, Rect.Top+8, TListBox(Control).Items[Index]);
    if not (odSelected in State) then Exit;
    R := Rect(Rect.Right-80, Rect.Top+4, Rect.Right-30, Rect.Top+24);
    P := Point(MouseX, MouseY);
    BtnState := DFCS_BUTTONPUSH;
    if PtInRect(R, P) then BtnState := BtnState or DFCS_PUSHED;
    DrawFrameControl(TListBox(Control).Canvas.Handle, R, DFC_BUTTON, BtnState);
    InflateRect(R, -4, -4);
    DrawText(TListBox(Control).Canvas.Handle, 'BTN', 3, R, DT_CENTER or DT_VCENTER or DT_SINGLELINE);
    end;

    procedure TForm1.ListBox1MouseDown(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
    begin
    if Button <> mbLeft then Exit;
    MouseX := X;
    MouseY := Y;
    ListBox1.Invalidate;
    end;

    procedure TForm1.ListBox1MouseUp(Sender: TObject; Button: TMouseButton;
    Shift: TShiftState; X, Y: Integer);
    begin
    if Button <> mbLeft then Exit;
    MouseX := -1;
    MouseY := -1;
    ListBox1.Invalidate;
    end;

    procedure TForm1.ListBox1Click(Sender: TObject);
    var
    P: TPoint;
    R: TRect;
    Index: Integer;
    begin
    P := Point(MouseX, MouseY);
    Index := ListBox1.ItemAtPos(P, True);
    if (Index = -1) or (Index <> ListBox1.ItemIndex) then Exit;
    R := ListBox1.ItemRect(Index);
    R := Rect(R.Right-80, R.Top+4, R.Right-30, R.Top+24);
    if not PtInRect(R, P) then Exit;
    // click is on selected item's "button", do something...
    end;

关于delphi - Ownerdraw TListBox 子控件不通过滚动移动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29155916/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com