Delphi使用表顺序同步面板顺序

时间:2015-02-12 04:36:09

标签: delphi delphi-xe

我在运行时生成面板。我在表单上有一个面板,然后我在里面有一个scrollBox alClient。在scrollBox里面我动态添加了面板。它们都属于Scrollbox,我生成后将它们对齐到底部。所以他们一个接一个地出现。

我使用的代码如下:

Procedure TMain.AdaugaElement(numar:integer; tip:string);
var
  pan:TPanel;
  semn:TShape;
  pos:TPoint;
  lab:TLabel;
  myimg:TImage;
  bmpsep, dest:TBitmap;
begin

  pan:=TPanel.Create(self);
  pan.Parent:=ScrollBox1;
  pan.Align:=alBottom;
  pan.Height:=50;
  pan.Name:='Layeru'+IntToStr(numar);
  pan.Caption:='Elementul '+IntToStr(numar);
  pan.Font.Color:=$00004F4F;
  pan.Font.Quality:=fqAntialiased;
  pan.Color:=$0080FFFF;
  pan.OnMouseDown:=layerRowMouseDown;
  pan.ParentColor:=false;
  pan.ParentBackground:=false;
  pan.Color:=clWhite;

  Pos:= pan.ClientOrigin;

  vt.AppendRecord([vt.RecordCount+1,Pan.name,numar,numar,0 ,0, 20,20,800,600,pan.Caption,tip]);

  lab:=TLabel.Create(self);
  lab.Parent:=pan;
  lab.Left:=54;
  lab.Top:=16;
  lab.Font.Size:=10;
  lab.Font.Color:=clBlack;
  lab.Font.Style:=[];
  lab.Font.Quality:=fqAntialiased;
  lab.Caption:=IntToStr(numar);
  Randomize;
  lab.Name:='Layernumber'+IntToStr(numar);

  semn:=TShape.Create(self);
  semn.Parent:=pan;
  semn.Left:=3;
  semn.Top:=3;
  semn.Height:=44;
  semn.Width:=44;
  semn.Pen.Color:=$00009D9D;
  semn.Brush.Color:=clWhite;

  myimg:=TImage.Create(self);
  myimg.Width:=42;
  myimg.Height:=42;
  myimg.Left:=4;
  myimg.Top:=4;
  myImg.Visible:=true;
  myimg.Proportional:=true;
  myimg.Stretch:=true;
  myImg.Parent:=pan;

  SelectLayerPan(numar);
end;
  • SelectLayerPan程序会模拟表格中的选定行,因此当我添加新面板时,它会显示为“已选择”' (它'取消选择'所有面板然后选择'新面板)

  • vtVirtualTable,我在其中输入有关生成的面板的信息

所以我添加这样的面板:

AdaugaElement(1,'type1');
AdaugaElement(2,'type1');
AdaugaElement(3,'type1');
AdaugaElement(4,'type1');

接下来,我想使用鼠标在各自之间移动面板。所以最初我添加了:

- panel5
- panel4
- panel3
- panel2
- panel1 

(按此顺序)

然后使用鼠标拖动panel1并将其放在panel4和panel5之间。因此它们将显示为:

- panel5
- **panel1**
- panel4
- panel3
- panel2

(按此顺序)

此拖放操作在layerRowMouseDown中完成。

但是,因为在virtualTable中我有关于面板的信息(按原始顺序),所以

record1: panel1  pos:1
record2: panel2  pos:2
record3: panel3  pos:3
record4: panel4  pos:4
record5: panel5  pos:5

我必须识别移动的面板记录并更新它以便它将反映其新位置,因此VirtualTable必须如下所示:

record1: panel1  pos:4
record2: panel2  pos:1
record3: panel3  pos:2
record4: panel4  pos:3
record5: panel5  pos:5

我该怎么做?

我的意思是,当我放下面板时,如何检测面板的最终位置?或者,我如何获得容器中的面板顺序(ScrollBox1)?

到目前为止,我尝试使用FindVCLWindow(pos)使用面板的起始位置和倍数来识别面板(及其在scrollBox中的顺序),但是当有更多面板时,它们不再可见直接(没有滚动),它显然停止正常工作。

所以这不是解决方案

2 个答案:

答案 0 :(得分:0)

Top中面板的TScrollBox属性似乎是面板顺序的唯一可靠指标。要查找面板的顺序,您可以将面板临时分配到列表,然后在Top属性上对该列表进行排序。现在,您将在列表中按照它们在滚动框中显示的顺序排列它们。

以下只是使用临时列表进行排序的示例。您需要对其进行修改以适合您的目的。

procedure TForm6.UpdateRecords;
var
  Comparer: IComparer<TMyPanel>;
  i: integer;
  s: string;
begin
  Comparer := TDelegatedComparer<TMyPanel>.Create(
    function (const A, B: TMyPanel):integer
    begin
      Result := A.Top - B.Top;
    end);
  TempPanelList := TMyPanelList.Create(Comparer);
  try
    for i := 0 to ScrollBox1.ControlCount-1 do
      TempPanelList.Add(TMyPanel(ScrollBox1.Controls[i]));
    TempPanelList.Sort;
    for i := 0 to TempPanelList.Count-1 do
    begin
      // replace this with your own code, something like in next snippet
      s := s + ', ' + inttostr(TempPanelList.items[i].Tag);
      Label1.Caption := s;
      //
    end;
  finally
    TempPanelList.Free;
  end;
end;

然后,要在列表中的面板和vt中的相应记录之间获取引用,您可以在创建面板时使用tag属性。您似乎将参数numar传递给AdaugaElement过程,因此假设这可以作为vt的索引,您可以将此numar分配给pan.Tag

最后要更新pos中的vt字段,您可以在循环中指定面板的新位置,在此循环中将TempPanelList中TPanel的索引指定为{{1}中的pos记录。 注意!我不知道使用vt

的正确语法
VirtualTable

但是你的设置在许多帐户上看起来都非常脆弱,而上述内容并没有帮助。您正在分配TMain实例(表单?)作为所有这些TPanel,TShapes,TLabels和TImages的所有者。当用户添加和删除图层时,它会变得非常混乱。我想创建一个复合类TLayerItem来保存与一个层和LayerManager类相关的所有内容来管理TLayerItems。

答案 1 :(得分:-2)

这似乎是一种效率低下的解决方案。还有,为什么重新发明轮子?

您所描述的内容与工具栏的工作方式非常相似,只是它是垂直布局而不是水平布局。我会查看一些工具栏的来源,看看你是否可以使用已经设计好的东西来做你想做的事情。如果不出意外,您将获得一些好主意如何实施您尝试做的事情。

或者,我会考虑在滚动框内使用TFlowPanel,您可以将面板放在流动面板上,而不是直接放在滚动框上。

编辑:我向有人低估了这一点道歉,但我们不允许指出异地内容,而且我不打算在这里发布几个工具栏组件的所有代码。