TListView在使用VCL样式时出现滚动错误-Delphi XE8

TListView在使用VCL样式时出现滚动错误-Delphi XE8,delphi,listview,right-to-left,vcl-styles,bidi,Delphi,Listview,Right To Left,Vcl Styles,Bidi,我尝试通过以下功能将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,

我尝试通过以下功能将
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样式时,我有两个问题,如下所示:

1:
垂直滚动条
未单击就不会出现

2:当我更改ListView列的大小并单击水平滚动条时,将显示以下错误消息:

异常源:
Vcl.ComCtrls.TListViewStyleHook.WMMouseMove

过程TListViewStyleHook.WMMouseMove(var消息:TWMMouse);
变量
SF:TScrollInfo;
SPos:整数;
R:TRect;
开始
如果VertSliderState=TSThumbTnVertPressed,则
开始
SF.fMask:=SIF_ALL;
SF.cbSize:=SizeOf(SF);
GetScrollInfo(句柄、SB_VERT、SF);
ScrollPos:=ScrollPos+(SF.nMax-SF.nMin)*((Mouse.CursorPos.Y-PrevScrollPos)/VertTrackRect.Height);
PrevScrollPos:=Mouse.CursorPos.Y;
如果控件为TCustomListView,则
开始
PostMessage(Handle,WM_VSCROLL,Integer(SmallPoint(SB_THUMBTRACK,Round(ScrollPos))),0);
如果TCustomListView(Control).ViewStyle=vsReport,则
开始
如果(Abs(滚动位置-列表位置)>=1)或
((ScrollPos=SF.nMin)和(ListPos ScrollPos))或
((ScrollPos=SF.nMax)和(ListPos-ScrollPos))然后
开始
如果TCustomListView(Control).GroupView,则
开始
SPO:=圆形(滚动位置-列表位置);
如果SF.nPos+SPos<0,则SPos:=-SF.nPos;
结束
其他的
开始
ListView_GetItemRect(句柄、0、R、LVIR_边界);
SPos:=圆形((滚动位置-列表位置)*垂直高度);
结束;
ListView_滚动(句柄、0、SPos);
ListPos:=ScrollPos;
结束;
结束
其他的
开始
如果Abs(滚动位置-列表位置)>=1,则
开始
ListView_滚动(手柄,0,圆形((ScrollPos-ListPos));
ListPos:=ScrollPos;
结束;
结束;
结束
其他的
PostMessage(Handle,WM_VSCROLL,Integer(SmallPoint(SB_拇指位置,Round(ScrollPos))),0);
画卷;
已处理:=真;
出口
结束;
如果按HorzSliderState=TSThumbTnHorz,则
开始
SF.fMask:=SIF_ALL;
SF.cbSize:=SizeOf(SF);
GeTScrollInfo(手柄,SB_HORZ,SF);
ScrollPos:=ScrollPos+(SF.nMax-SF.nMin)*((Mouse.CursorPos.X-PrevScrollPos)/HorzTrackRect.Width);
如果滚动位置SF.nMax,则
ScrollPos:=SF.nMax;
PrevScrollPos:=Mouse.CursorPos.X;
如果控件为TCustomListView,则
开始
如果TCustomListView(Control).ViewStyle=vsReport,则
开始
如果Abs(滚动位置-列表位置)>=1,则
开始
ListView_滚动(手柄,圆形((ScrollPos-ListPos)),0);
ListPos:=ScrollPos;
结束;
结束
其他的
开始
如果Abs(滚动位置-列表位置)>=0.5,则
开始
ListView_滚动(手柄,圆形((ScrollPos-ListPos)),0);
ListPos:=ScrollPos;
结束;
结束;
结束
其他的
PostMessage(Handle,WM_HSCROLL,Integer(SmallPoint(SB_拇指位置,Round(ScrollPos))),0);
画卷;
已处理:=真;
出口
结束;
如果(HorzSliderState TsThumbTnhorzPressed)和(HorzSliderState=TsThumbTnhorzhot),则
开始
HorzSliderState:=TsThumbTnHorznormal;
画卷;
结束;
如果(VertSliderState TsThumbTnvertPressed)和(VertSliderState=TsThumbTnverTot),则
开始
VertSliderState:=TSThumbTnVertNormal;
画卷;
结束;
如果(HorzUpState tsArrowBtnLeftPressed)和(HorzUpState=tsArrowBtnLeftHot),则
开始
水平状态:=tsarrowbtnleeftnormal;
画卷;
结束;
如果(HorzDownState tsArrowBtnRightPressed)和(HorzDownState=tsArrowBtnRightHot),则
开始
HorzDownState:=tsArrowBtnRightNormal;
画卷;
结束;
如果(VertUpState tsArrowBtnUpPressed)和(VertUpState=tsArrowBtnUpHot),则
开始
垂直向上状态:=tsArrowBtnUpNormal;
画卷;
结束;
如果(VertdowState TsarrowbtDownpressed)和(VertdowState=TsarrowbtDownhot),则
开始
垂直下降状态:=TsarrowbtDownNormal;
画卷;
结束;
CallDefaultProc(TMessage(Message));
如果是LeftButtonDown,那么
画卷;
已处理:=真;
结束;
这个问题应该如何解决


谢谢。

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

不要这样做。相反,将控件的
BiDiMode
属性设置为
bdrightoleft
。除非我遗漏了一些东西,这将使您获得所需的行为,并且我现在已经测试了它,否则以这种方式滚动主题不会有任何问题

你的捆绑方式有两个大问题:

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

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


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

    不要这样做。相反,将控件的
    BiDiMode
    属性设置为
    bdrightoleft
    。除非我遗漏了什么,否则这会让你做出你需要的行为
    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;