0

我试图通过以下函数将TListView控件的方向设置为:RTL

procedure RTL_LV(lv:TListView);
const
  LVM_FIRST = $1000;
  LVM_GETHEADER = LVM_FIRST + 31;
var
  header: THandle;
begin
  header:= SendMessage (lv.Handle, LVM_GETHEADER, 0, 0);
  SetWindowLong (header, GWL_EXSTYLE,
                 GetWindowLong (header, GWL_EXSTYLE)  or
                 WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);

  SetWindowLong (lv.Handle, GWL_EXSTYLE,
                 GetWindowLong (lv.Handle, GWL_EXSTYLE)  or
                 WS_EX_LAYOUTRTL or WS_EX_NOINHERITLAYOUT);
  lv.invalidate;
end;

但是当项目使用时我有两个问题如下VCL Styles

1:Vertical scrollbar不点击不出现。

在此处输入图像描述

2:当我更改 ListView 列的大小并horizontal scrollbar单击时,会显示以下错误消息:

在此处输入图像描述

异常来源:Vcl.ComCtrls.TListViewStyleHook.WMMouseMove

在此处输入图像描述

procedure TListViewStyleHook.WMMouseMove(var Message: TWMMouse);
var
  SF: TScrollInfo;
  SPos: Integer;
  R: TRect;
begin
  if VertSliderState = tsThumbBtnVertPressed then
  begin
    SF.fMask := SIF_ALL;
    SF.cbSize := SizeOf(SF);
    GetScrollInfo(Handle, SB_VERT, SF);
    ScrollPos := ScrollPos + (SF.nMax - SF.nMin) * ((Mouse.CursorPos.Y - PrevScrollPos) / VertTrackRect.Height);

    PrevScrollPos := Mouse.CursorPos.Y;

    if Control is TCustomListView then
    begin
      PostMessage(Handle, WM_VSCROLL, Integer(SmallPoint(SB_THUMBTRACK, Round(ScrollPos))), 0);
      if TCustomListView(Control).ViewStyle = vsReport then
      begin
        if (Abs(ScrollPos - ListPos) >= 1) or
        ((ScrollPos = SF.nMin) and (ListPos <> ScrollPos)) or
        ((ScrollPos = SF.nMax) and (ListPos <> ScrollPos)) then
        begin
          if TCustomListView(Control).GroupView then
          begin
            SPos := Round(ScrollPos - ListPos);
            if SF.nPos + SPos < 0 then SPos := -SF.nPos;
          end
          else
            begin
              ListView_GetItemRect(Handle, 0, R, LVIR_BOUNDS);
              SPos := Round((ScrollPos - ListPos) * R.Height);
            end;
          ListView_Scroll(Handle, 0, SPos);
          ListPos := ScrollPos;
        end;
      end
      else
      begin
        if Abs(ScrollPos - ListPos) >= 1 then
        begin
          ListView_Scroll(Handle, 0, Round((ScrollPos - ListPos)));
          ListPos := ScrollPos;
        end;
      end;
    end
    else
      PostMessage(Handle, WM_VSCROLL, Integer(SmallPoint(SB_THUMBPOSITION, Round(ScrollPos))), 0);
    PaintScroll;
    Handled := True;
    Exit;
  end;

  if HorzSliderState = tsThumbBtnHorzPressed then
  begin
    SF.fMask := SIF_ALL;
    SF.cbSize := SizeOf(SF);
    GeTScrollInfo(Handle, SB_HORZ, SF);
    ScrollPos := ScrollPos + (SF.nMax - SF.nMin) * ((Mouse.CursorPos.X - PrevScrollPos) / HorzTrackRect.Width);
    if ScrollPos < SF.nMin then
      ScrollPos := SF.nMin;
    if ScrollPos > SF.nMax then
      ScrollPos := SF.nMax;

    PrevScrollPos := Mouse.CursorPos.X;

    if Control is TCustomListView then
    begin
      if TCustomListView(Control).ViewStyle = vsReport then
      begin
        if Abs(ScrollPos - ListPos) >= 1 then
        begin
          ListView_Scroll(Handle, Round((ScrollPos - ListPos)), 0);
          ListPos := ScrollPos;
        end;
      end
      else
      begin
        if Abs(ScrollPos - ListPos) >= 0.5 then
        begin
          ListView_Scroll(Handle, Round((ScrollPos - ListPos)), 0);
          ListPos := ScrollPos;
        end;
      end;
    end
    else
      PostMessage(Handle, WM_HSCROLL, Integer(SmallPoint(SB_THUMBPOSITION, Round(ScrollPos))), 0);
    PaintScroll;
    Handled := True;
    Exit;
  end;

  if (HorzSliderState <> tsThumbBtnHorzPressed) and (HorzSliderState = tsThumbBtnHorzHot) then
  begin
    HorzSliderState := tsThumbBtnHorzNormal;
    PaintScroll;
  end;

  if (VertSliderState <> tsThumbBtnVertPressed) and (VertSliderState = tsThumbBtnVertHot) then
  begin
    VertSliderState := tsThumbBtnVertNormal;
    PaintScroll;
  end;

  if (HorzUpState <> tsArrowBtnLeftPressed) and (HorzUpState = tsArrowBtnLeftHot) then
  begin
    HorzUpState := tsArrowBtnLeftNormal;
    PaintScroll;
  end;

  if (HorzDownState <> tsArrowBtnRightPressed) and (HorzDownState =tsArrowBtnRightHot) then
  begin
    HorzDownState := tsArrowBtnRightNormal;
    PaintScroll;
  end;

  if (VertUpState <> tsArrowBtnUpPressed) and (VertUpState = tsArrowBtnUpHot) then
  begin
    VertUpState := tsArrowBtnUpNormal;
    PaintScroll;
  end;

  if (VertDownState <> tsArrowBtnDownPressed) and (VertDownState = tsArrowBtnDownHot) then
  begin
    VertDownState := tsArrowBtnDownNormal;
    PaintScroll;
  end;

  CallDefaultProc(TMessage(Message));
  if LeftButtonDown then
    PaintScroll;
  Handled := True;
end;

这些问题应该如何解决?

谢谢。

4

1 回答 1

5

您的方法存在多个问题。快速的答案是:

不要这样做。相反,将控件的BiDiMode属性设置为bdRightToLeft. 除非我遗漏了某些东西,否则这将为您提供所需的行为并且我现在对其进行了测试,以这种方式滚动主题没有问题。

您绑定执行此操作的方式存在两个大问题:

  1. 您不能保证控件会保留您强制进入的设置。VCL 第一次需要为控件重新创建窗口时,您的设置将被删除。

  2. 您假设 VCL 不需要以某种方式考虑此设置。显然是这样,因为在尝试削弱 VCL 并将样式直接发送到窗口时,您会遇到不良行为。如果你真的想直接控制窗口样式,你需要创建你自己的控件类的后代,并在适当的地方处理所有相关的事情——你不能随便选择任何你想将控件更改为 RTL 的旧时间Windows API 调用(而不是控件的属性)并期望控件将继续正常工作。

于 2015-10-20T18:07:01.023 回答