【问题标题】:Frames and Browse History in DelphiDelphi 中的框架和浏览历史
【发布时间】:2010-12-20 08:04:55
【问题描述】:

我目前正在开发一个需要浏览历史记录的 delphi 应用程序,并且正在尝试弄清楚如何实现它。

应用程序有 2 种模式。浏览和详细信息。两者都设计为框架。

搜索后,会在面板 1 中创建并填充适当数量的浏览框架。

从浏览框架中,我们可以打开细节框架,将面板 1 的内容替换为细节框架的内容。或者,可以生成新的搜索,用新的结果集替换当前的结果集。

从细节框架我们可以编辑细节,或者产生新的搜索。某些搜索只能从详细信息框架中获得。浏览框架或细节框架中的其他人。

每次用户显示详细信息框架或产生新搜索时,我都想记录该操作并能够重复它。不会记录其他操作,例如编辑或“更多详细信息”。 (显然,如果用户后退几步然后沿着不同的搜索路径前进,这将从此时开始新的历史记录)

在我看来,我想记录在列表中进行的过程调用,例如

SearchByName(Search.Text);
SearchByName(ArchName.Text);
DisplayDetails(JobID);
SearchByName(EngineerName.Text);
DisplayDetails(JobID);

然后我可以(以某种方式)在我前进时按顺序调用每个项目......

【问题讨论】:

  • 请说明您是否需要保留浏览历史,或者退出程序时丢失是否可以。实施选项会因此而有很大差异。
  • 应用程序关闭后不需要持久化。我想问的重点是如何存储和调用方法处理程序。

标签: delphi


【解决方案1】:

响应 Dan Kelly 存储函数的请求: 但是我仍然看不到我如何调用存储的函数 -

您指的是存储方法处理程序。下面的代码演示了这一点。但是,正如你所表明的那样,你可以做一个大的 if..then 或 case 语句。

这一切都会奏效。但是做这一切的一个更“雄辩”的方式是存储对象指针。例如,如果一个搜索打开另一个搜索,则将第一个的指针传递给第二个。然后在第二个,如果你想引用它,你有一个指向它的指针(首先检查它不是 nil/free)。这是一种更加面向对象的方法,并且更适用于有人可能会不按顺序关闭其中一个帧的情况。

unit searchit;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSearchObject = class
  FSearchValue: String;
  FOnEventClick: TNotifyEvent;
  constructor Create(mSearchValue: string; mOnEventClick: TNotifyEvent);
  procedure FireItsEvent;  
end;

type
  TForm1 = class(TForm)
    SearchByName: TButton;
    GoBack: TButton;
    DisplayDetails: TButton;
    searchfield: TEdit;
    jobid: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure SearchByNameClick(Sender: TObject);
    procedure GoBackClick(Sender: TObject);
    procedure DisplayDetailsClick(Sender: TObject);
  private
    { Private declarations }
    SearchObjectsList: TStringList;
    procedure DisplayDetailFunction(Sender: TObject);
    procedure SearchByNameFunction(Sender: TObject);        
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

constructor TSearchObject.Create(mSearchValue: string;mOnEventClick: TNotifyEvent);
begin
  FOnEventClick   := mOnEventClick;
  FSearchValue    := mSearchValue;
end;

{$R *.dfm}

procedure TSearchObject.FireItsEvent;
begin
  if Assigned(FOnEventClick) then
    FOnEventClick(self);
end;

procedure TForm1.SearchByNameClick(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  mSearchObject := TSearchObject.Create(SearchField.Text,SearchByNameFunction);
  SearchObjectsList.AddObject(SearchField.Text,mSearchObject);
end;

procedure TForm1.DisplayDetailFunction(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  mSearchObject := TSearchObject(Sender);
  ShowMessage('This is the Display Detail Event.  The value of the JobID is '+mSearchObject.FSearchValue);
end;

procedure TForm1.SearchByNameFunction(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  mSearchObject := TSearchObject(Sender);
  ShowMessage('This is the SearchByName Event.  The value of the Search Field is '+mSearchObject.FSearchValue);
end;


procedure TForm1.DisplayDetailsClick(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  mSearchObject := TSearchObject.Create(jobid.text,DisplayDetailFunction);
  SearchObjectsList.AddObject(jobid.text,mSearchObject);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SearchObjectsList := TStringList.Create;
end;

procedure TForm1.GoBackClick(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  if SearchObjectsList.count=0 then
    showmessage('Cannot go Back!')
  else begin
    mSearchObject := TSearchObject(SearchObjectsList.Objects[SearchObjectsList.count-1]);
    mSearchObject.FireItsEvent;

    SearchObjectsList.Delete(SearchObjectsList.count-1);

  end;
end;

end.

【讨论】:

  • 这正是我的想法。我也考虑过指针路线,但更不知道从哪里开始这条路线(不幸的是,指针仍然是我的编程盲点之一)
【解决方案2】:

跟踪 TStringList 中的所有内容;当他们“返回”时,您从字符串列表中删除。这是一种原型:

type
  TSearchObject = class
  FSearchFunction,FSearchValue: String;
  constructor Create(mSearchFunction,mSearchValue: string);
end;

type
  TForm1 = class(TForm)
    SearchByName: TButton;
    GoBack: TButton;
    DisplayDetails: TButton;
    searchfield: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure SearchByNameClick(Sender: TObject);
    procedure GoBackClick(Sender: TObject);
    procedure DisplayDetailsClick(Sender: TObject);
  private
    { Private declarations }
    SearchObjectsList: TStringList;
    jobid: String;   //not sure how you get this
  public
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

constructor TSearchObject.Create(mSearchFunction,mSearchValue: string);
begin
  FSearchFunction := mSearchFunction;
  FSearchValue    := mSearchValue;
end;

{$R *.dfm}

procedure TForm1.SearchByNameClick(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  mSearchObject := TSearchObject.Create('SearchByName',SearchField.Text);
  SearchObjectsList.AddObject(SearchField.Text,mSearchObject);
end;

procedure TForm1.DisplayDetailsClick(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  mSearchObject := TSearchObject.Create('DisplayDetails',JobID);
  SearchObjectsList.AddObject(JobId,mSearchObject);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  SearchObjectsList := TStringList.Create;

end;

procedure TForm1.GoBackClick(Sender: TObject);
var
  mSearchObject: TSearchObject;
begin
  if SearchObjectsList.count=0 then
    showmessage('Cannot go Back!')
  else begin
    mSearchObject := TSearchObject(SearchObjectsList.Objects[SearchObjectsList.count-1]);
    if mSearchObject.FSearchFunction ='SearchByName' then
      ShowMessage('Value of Search Field:'+mSearchObject.FSearchValue)
    else
      ShowMessage('Value of JobID:'+mSearchObject.FSearchValue);
    SearchObjectsList.Delete(SearchObjectsList.count-1);

  end;
end;

【讨论】:

  • 谢谢 这很好,并解决了我的一个问题(未说明),即我如何存储值以及命令。但是我仍然看不到我如何调用存储的函数 - 在您的示例中,您正在使用它来决定使用哪个 ShowMessage ...我需要调用该过程并传递存储的参数...
  • 实际上我很密集 - 一个答案是使用 if / case 语句在 GoBackClick 例程中做出决定......(你可以做另一个选择吗?)
【解决方案3】:

另一种选择是使用我的wizard framework,它使用 TForms 执行此操作,但也可以轻松调整为使用框架。这个概念是每个摘要表单都知道如何创建其适当的详细信息。在您的情况下,该框架更多的是如何做到这一点的示例,而不是即插即用的解决方案。

【讨论】:

    【解决方案4】:

    补充 MSchenkel 的答案。

    保留程序运行之间的列表,请使用 ini 文件

    这就是想法。你必须适应它。特别是,您必须弄清楚将对象转换为字符串和将字符串转换为对象的方法,这里概括为ObjectToString()StringToStringIDStringToObject()

    OnClose 事件中,将列表写入ini 文件。

    const 
      IniFileName = 'MYPROG.INI';
      MaxPersistedObjects = 10;
    
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
     var 
       ini: TIniFile;  
       i: integer;
       cnt: integer;
     begin
       ini:=TIniFile.Create(iniFileName);
       cnt:=SearchObjectsList.Count;
       if cnt>MaxPersistedObjects then 
         cnt:=MaxPersistedObjects;
       for i:=1 to MaxPersistedObjects do
         if i>cnt then
           ini.WriteString('SearchObjects','SearchObject'+intToStr(i),'');
         else 
           ini.WriteString('SearchObjects','SearchObject'+intToStr(i),
             ObjectToString(SearchObjectsList[i-1],SearchObjectsList.Objects[i-1]) );
       ini.Free;
     end;
    

    并在OnCreate event 上阅读。

    procedure TForm1.FormCreate(Sender: TObject);
     var 
       ini: TIniFile;
       i: integer;
     begin
       SearchObjectsList := TStringList.Create;
       ini:=TIniFile.Create(IniFileName);  
       for i:=1 to MaxPersistedObjects do 
        begin
          s:=ini.ReadString('SearchObjects','SearchObject'+intToStr(i),'');
          if s<>'' then
            SearchObjectsList.AddObject(StringToID(s),StringToObject(s));
        end;
       ini.Free;
     end;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-21
      • 1970-01-01
      • 2017-12-29
      • 2012-11-14
      • 2015-10-10
      • 2018-05-28
      相关资源
      最近更新 更多