Link to home
Start Free TrialLog in
Avatar of ChLa
ChLaFlag for United States of America

asked on

how do I populate a filelistbox by creation date instead of alphabetically ?

How do I populate a FileListBox by creation date instead of alphabetically ? Does creation date include seconds ?
Avatar of jimyX
jimyX

FileListBox will always read the files and sort them alphabetically (by the names of the files).

You can not load in a different order unless you override the ReadFileNames method in TCustomFilelistBox
Avatar of ChLa

ASKER

Is overriding the method a good idea ? Or is there a better way ? Often I have a folder with hundreds or thousands of image files. They have different names and numbers, and extensions. I have successfully written a program that will rename/renumber all the files in a folder, alphabetically, for another purpose. But for mass renaming a big folder of images, I need to make sure the files are listed by creation date and not alphabetically. So I am wondering how to have a filelistbox, or something like it, that has the files in order of creation date.
It would be nice to have a filelistbox with buttons allowing me to change back and forth between alphabetical and by creation date.  Is there a better way to do this ? Perhaps I should copy the filenames to some other type of list box ?
You'd better create your own FileListbox, and fill it with files in the exact order you want.
If you want to go that way, just ask and I'm sure we can help

You could even use a TListView, have columns for file name, create date and even file size

Then you can sort by simply clicking on the column header
SOLUTION
Avatar of Emmanuel PASQUIER
Emmanuel PASQUIER
Flag of France image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of ChLa

ASKER

Hi Everyone,
I am still reviewing this information and trying to decide how to procede.I have been looking at the link from epasquier. It led me to read much more. I have also been trying to find out how to get the shell controls so I could see what they have to offer. How would I override the ReadFileNames method ?
I will be looking at a TListView and seeing if I can figure out how to add columns to it, how to populate it with filenames. If a TListView can already put files in order of date/time, that might be a best thing. I would be happy with a FileListBox that automatically puts files in order of creation date. I wanted anyone who is waiting for me to pick a best answer to know I am still working on this. I wonder if there is an aftermarket fiklelist box with a column for create date/time I could buy ?
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial

There should be a link to the Demo folder in your Start menu

Select Demos\DelphiWin32\VCLWin32\ShellControls

You will find all the controls you need so you don't need to mess around with FileListBox any more
Delphi-Demos.png
Avatar of ChLa

ASKER

There is a link to Delphi 2010, but not to Embarcadero RAD Studio !

I can send you the files compressed (zip)
Only EE will not allow some types of extensions
ChLa,
did you try the FileListBoxEx?
FileListBoxEx.pas
Avatar of ChLa

ASKER

Hi Everyone,

I remembered I still have Delphi 7 on Graphics/Web Site computer for which I am writing this program. It has the ShellListView. I looked at a TShellListView and like it. I am surprised it doesn't already have sorting built in, as well as the ability to select which colums we want to include, and in which order. What I like about it is I don't need a DriveComboBox, or a DirectoryListBox. And of course it displays the other file attributes. This computer is a Sony VAIO with W2K. My laptop has W7 and Delphi 2010. My first question is, can I copy the Shell Controls from Delphi7 to Delphi 2010 ? My laptop is my preferred program writing computer as I have more oportunities to work with it.
I played with a FileListBox and see I could easily reorganize the filenames using a sort routine. But of course the filelistbox doesn't show the date/time. I could extract the creation date/time and put it into some sort of listbox or array, and sort it by date/time. But generally, this would be too time consuming for me to do and I would prefer an easier solution. It would be better for me to be able to sory by creation date instead of last modified. But it is not critical, I can live with last modified. But I think it is important to use not just the date, but the time also. This is because many of the files I will be renaming are digital stills, where I may have taken several in a minute, or rendered computer animation, were more than one file may have been created in a minute.
I didn't have much time to work on this in the last couple of days. Last night as I was discovering the shelllistview, I was thinking I would implement a solution I found on About.com for sorting a ShellListView. Now I think I will try the solution outlined in the ariticle suggested by jimyX For the FileListBox.  I see you attached the .pas file for me. Thank you. How do I use it ? Compile it as a component and then add it as a component ? Do I need to backup an existring file first ? Sorry, I am at work and distracted by many things.

Exactly with the ShellListview
See how easy everything becomes
And the good thing is that it is already tested for you by Embarcadero folks

You already have all the necessary columns, hiding is pretty simple and sorting a TListView, well there are many algorithms out there
The main point is not to reinvent the wheel, you will end up with less errors and a component that is guaranteed to be maintained by Embarcadero with any new releases
>   "How do I use it ? Compile it as a component...?"
Yes, in Delphi 7: from the menu -> Component -> Install Component... locate that pas file and then OK and finally compile and install.
In Delphi 2010: from the menu -> File -> New -> Package - Delphi... -> from the Project manager right click on "contains" and select Add the browse and locate that pas file then right click on the package name and select compile and then install after compiling successfully.

>   "Do I need to backup an existring file first ?"
No need, it can be installed as additional component unless you have component with the same name (i.e. FileListBoxEx) but in all cases, I did test it and it works perfectly. However Delphi will prompt you if there is any conflict.

For ShellListView under Delphi 2010:
From Delphi 2010 menu -> File -> open -> Locate and load the files vclshlctrls.dproj and dclshlctrls.dproj. By default the path for those files in my Delphi 2010 is:
C:\Documents and Settings\All Users\Documents\RAD Studio\7.0\Demos\DelphiWin32\VCLWin32\ShellControls
Then compile both of them and then install dclshlctrls.dproj.

PS: to compile and install components in Delphi 2010 after loading the packages or pas files you go to package name in the Project manager then right click on the name of the package and select "Compile" and again right click and "Install".
Avatar of ChLa

ASKER

That worked, now I have the shell components.
Thank you
Avatar of ChLa

ASKER

Now that I have ShellListView on both my Delphi 7 and Delphi 2010, I am trying to add sorting by following the instruction on About.com. Following these instructions the first thing I did was back up Shellctrls.pas. Then I was supposed to remove the shell controls form the IDE. The only way I know to do this is to uncheck the box for "Shell Control Property and component editors" in Components>Install Packages. I did this and the shell controls dissappeared from the samples pallet. I then followed the instructions for exposing the Folder List as a public property. When I try to compile shellctrls.pas, it also wants to compile dcluser, and I get the message Error dcluser.dpk (37) Package cclshlctrls already contains unit "Shell Ctrls". I see thereference to shellcontrols in the package dclusr. What am I doing woring ? Sorry about any mispellings, I wrote down the file names early this morning and can't read my writing now.
>   "uncheck the box for "Shell Control Property and component editors" in Components>Install Packages"

Actually unchecking is just hiding it from the "Samples" in the Tool Palette, you should remove it, and then reinstall it from the beginning after updating it.
Remove-Shell-Control-Property.JPG
Avatar of ChLa

ASKER

Hi,
That worked and got me a bit further. But now I find I don't really know how to compile the .pas
Do I say "New Package" or "New Component" ? Either way I end up with a file named by the filepath, and after installing it the components are not there. If I simply open and compile it, it wants to make it an MDI !  Please give me explicit instructions on how to turn Shellctrls back into components in the pallet. Thanks
After you removed the component from your Delphi, and updated the pas file "ShellCtrls" then you recompile the whole package as you did at the beginning:

From Delphi 2010 menu -> File -> open -> Locate and load the files vclshlctrls.dproj and dclshlctrls.dproj. By default the path for those files in my Delphi 2010 is:
C:\Documents and Settings\All Users\Documents\RAD Studio\7.0\Demos\DelphiWin32\VCLWin32\ShellControls
Then compile both of them and then install dclshlctrls.dproj.
Avatar of ChLa

ASKER

Thank you very much JimyX. Actually, I started this at ome at night on my Graphics VAIO, which has Delphi 7.Is there any difference in the procedure for D7 as opposed to D2010 ? You know, I started by asking how to sort a filelistbox. Later I got the shellllistview and decided it was better. I feel bad I didn't use what you sent for sorting a filelist box. I found the thing on About.com and since it was the only solution for the shelllistview, decided to try it. I probably should have asked you if you have something for shelllistview, like you sent me for a filelist box. Do you already have something for it, or is it best I try the about.com solution ?
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
>   "Is there any difference in the procedure for D7 as opposed to D2010 ?"
No difference, same steps.

>   "I feel bad I didn't use what you sent for sorting a filelist box"
Easy man, we are here to help. Feel free to select whatever is convenient with you.
And whatever choice you make you will get our support and all the help to accomplish it. I also vote for the ShellListView for it has more options and features than the FileListBox.
Also you might use one of them now, but look at it this way, you have the two components working and ready for future needs.

>   "I probably should have asked you if you have something for shelllistview"
I do have an advanced component which is similar to the ShellListView but with many features and capabilities, may be is going to be a bit complicated for your current requirement.
http://www.mustangpeak.net/

Did you get the ShellListView working as per about.com instructions?
Are you facing any difficulties?
Avatar of ChLa

ASKER

Hi,
I didn't have much time to work last night, but I did get through re-compiling shell controls. Then I played with it for a while and started reviewing the rest of the procedure. I did that last night with D7/W2K. Today I plan to repeat it with D2010/W7, and to try to get the rest of it working. I will look at the link you sent.
It is interesting to be able to see the source code for shell controls. It shows me how powerful Delphi could be, if I were a more accomplished programmer.
When I compile, I get the warning that Shell controls are specific to a platform.Does this mean specific to Windows, or a specific flavor of Windows ? I generally hope and expect programs I write in any version of Delphi to work in any version of Windows from 2K to W7.
That means it is specific to windows. It will work on any version of windows
Just make sure to use the shell controls package that came with D2010, for it was designed to support W7 as well as the previous versions.
Avatar of ChLa

ASKER

Hi,
I copied everything from About.com and am getting just one error. I am getting E2003 Undeclared Identifier "FolderList. TShellIstView does not contain a member named FolderList.
My guess is that i declared FolderList inthe wrong place in ShellCtrls.Pas. But it looks right to me.
Here is the procedure as I copied it:

procedure TMainForm.shellListSortPopupItemClick(Sender: Tobject);
begin
    if shellListSortColumn <> TMenuItem(Sender).Tag then
      shellListSortColumn := TMenuItem(Sender).Tag
    else
      shellListSortAscending := NOT shellListSortAscending;
      ShellListView1.FolderList.Sort(@ShellCompare);
      ShellListView1.Invalidate;
end;

Here is part of ShellCtrls.Pas showing where I put the declaration. Look for the comment "//I added this"

    property OnStartDrag;
  end;

{ TCustomShellListView }

  TCustomShellListView = class(TCustomListView, IShellCommandVerb)
  private
    FOldRoot: TRoot;
    FRoot: TRoot;
    FRootFolder: TShellFolder;
    FAutoContext,
    FAutoRefresh,
    FAutoNavigate,
    FSorted,
    FUpdating: Boolean;
    FObjectTypes: TShellObjectTypes;
    FLargeImages,
    FSmallImages: Integer;
    FOnAddFolder: TAddFolderEvent;
    FFolders: TList;
    FTreeView: TCustomShellTreeView;
    FComboBox: TCustomShelLComboBox;
    FNotifier: TShellChangeNotifier;
    FOnEditing: TLVEditingEvent;
    FSettingRoot: boolean;
    FSavePath: string;
    procedure EnumColumns;
    function GetFolder(Index: Integer): TShellFolder;
    procedure SetAutoRefresh(const Value: Boolean);
    procedure SetSorted(const Value: Boolean);
    procedure SetTreeView(Value: TCustomShellTreeView);
    procedure SetComboBox(Value: TCustomShellComboBox);
    procedure TreeUpdate(NewRoot: PItemIDList);
    procedure SetPathFromID(ID: PItemIDList);
    procedure SynchPaths;
  protected
    procedure ClearItems;
    procedure CreateRoot;
    procedure CreateWnd; override;
    procedure DestroyWnd; override;
    procedure DblClick; override;
    procedure DoContextPopup(MousePos: TPoint; var Handled: Boolean); override;
    procedure EditText;
    procedure Edit(const Item: TLVItem); override;
    procedure KeyDown(var Key: Word; Shift: TShiftState); override;
    procedure Loaded; override;
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    function OwnerDataFetch(Item: TListItem; Request: TItemRequest): Boolean; override;
    function OwnerDataFind(Find: TItemFind; const FindString: string;
      const FindPosition: TPoint; FindData: Pointer; StartIndex: Integer;
      Direction: TSearchDirection; Wrap: Boolean): Integer; override;
    procedure Populate; virtual;
    procedure RootChanged;
    procedure SetObjectTypes(Value: TShellObjectTypes);
    procedure SetRoot(const Value: TRoot);
    procedure SetViewStyle(Value: TViewStyle); override;
    procedure WndProc(var Message: TMessage); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure Back;
    procedure Refresh;
    function SelectedFolder: TShellFolder;
    property FolderList: TList read FFolders;             //I added this !
    property Folders[Index: Integer]: TShellFolder read GetFolder;
    property RootFolder: TShellFolder read FRootFolder;
    property Items;
    property Columns;
    property AutoContextMenus: Boolean read FAutoContext write FAutoContext default True;
    property AutoRefresh: Boolean read FAutoRefresh write SetAutoRefresh default False;

What did I do wrong ?
You have done it right, it's only to remove any ShellCtrls.dcu that was compiled from the old code before the update is made. You will find it under this path:
C:\Program Files\CodeGear\RAD Studio\7.0\lib

So just remove the component first then delete all the ShellCtrls.dcu files then reinstall the package.

Make sure to add the path of the package to the library path after reinstalling.
Avatar of ChLa

ASKER

Where do I add the path of the package to the library path ?
Avatar of ChLa

ASKER

I found two old shellcntrls, one is in C:\ProgramFiles\Embarcadero/RAD Studio\7.0
The second is in C:\USERS\me\AppData\Local\(2D559015-4C05-4AE5-8C8B\7E13E1EAB09D)\corewin32\\8247FA69).
The new one is in C:\USERS\me\My Documents\RAD Studio\7.0\Demos\DelphiWin32\VCLWin32)
Should I delete both of the old ones ?

Delete both of them.
The correct version will be recreated when you compile your project
Deleting the one in "C:\ProgramFiles\Embarcadero/RAD Studio\7.0" will fix it. But you can delete the other one as well, in "C:\USERS\me\AppData\Local\(2D559015-4C05-4AE5-8C8B\7E13E1EAB09D)\corewin32\\8247FA69".

To add any component path to the library path:
From Delphi menu -> Tools -> Options -> At the tree items on the left under Environment Options/Delphi Options/Library - Win32 -> at the Library path Editbox add the path: "C:\USERS\me\My Documents\RAD Studio\7.0\Demos\DelphiWin32\VCLWin32" (without the quotes). Make sure to add ; at the end before adding that path, so it looks like:
xxxxxxxx;C:\USERS\me\My Documents\RAD Studio\7.0\Demos\DelphiWin32\VCLWin32
Avatar of ChLa

ASKER

I did all this and now I am getting just one error.
In the shellListSortPopupItemClick procedure from About.com, there is a line:
ShellListView1.FolderList.Sort(@ShellCompare);

It is causing the error message saying ShellCompare is an undeclared identifier.
What do I do ?
You need to add that function (ShellCompare) in your form
function ShellCompare(Item1, Item2: Pointer): Integer;
const
  R: array[Boolean] of Byte = (0, 1);
begin
  result := 0;

  if (Item1 = nil) or (Item2 = nil) then Exit;

  if shellListSortAscending then
  begin
    result := R[TShellFolder(Item2).IsFolder] - R[TShellFolder(Item1).IsFolder];
    if result = 0 then
      if (TShellFolder(Item1).ParentShellFolder <> nil) then
              result := Smallint( TShellFolder(Item1).ParentShellFolder.CompareIDs(
                    shellListSortColumn, //sort_type,
                    TShellFolder(Item1).RelativeID,
                    TShellFolder(Item2).RelativeID) );
    end
    else
    begin
      result := R[TShellFolder(Item1).IsFolder] - R[TShellFolder(Item2).IsFolder];
        if result = 0 then
          if (TShellFolder(Item2).ParentShellFolder <> nil) then
              result := Smallint( TShellFolder(Item2).ParentShellFolder.CompareIDs(
                    shellListSortColumn,// sort_type,
                    TShellFolder(Item2).RelativeID,
                    TShellFolder(Item1).RelativeID) );
    end;
end; (*ShellCompare*)

Open in new window

What we did up to the compiling stage was only setting the ShellListView to support the Sort operation. But it's not added so you should add the sort function in your main application (as per step 4 in About's article):

You may download the complete project here:
http://delphi.about.com/library/code/shelllistview-sort.zip
Avatar of ChLa

ASKER

I did write in the ShellCompare function. But I didn't declare it. Do I declare it after the declarations for procedures, or in public or private declarations ? Is it "Function  ShellCompare(Sender: TObject);" ?
Avatar of ChLa

ASKER

and...
 I didn't include where it says "(*ShellCompare*)"
that's jjust a remark isn't it ?
>   "But I didn't declare it. Do I declare it after the declarations..."

No need, just make sure to place the function "ShellCompare" the first on top before the other events and procedures:
implementation
{$R *.dfm}
...
function ShellCompare(Item1, Item2: Pointer): Integer;
...
procedure TShellListSortForm.FormCreate(Sender: TObject);
...
procedure TShellListSortForm.shellListSortPopupItemClick(Sender: TObject);
...

Open in new window

>   ""(*ShellCompare*)" that's just a remark isn't it ?"
Yes, you can remove that, it's just a comment.
Avatar of ChLa

ASKER

That did it. It's working now. Thank you.

Just a few more questions.

How could I add the ability to sort by Creation Date ?

What do I need to do to have two of these sorting shelllistviews on my form ? I see some procedures refer to shelllistview1. I suppose those would have to be copied and changed to shelllistview2, or I would have a variable for which shelllistview. Such as ShellListView[ShellListViewNumber]. I guess the procedures that don't specify shelllistview1 would not need to be changed.

I read somewhere about a shell component editor in RAD studio. I don't have rad studio. When I bought Delphi2010, I didn't, and still don't know what RAD studio is, so I only downloaded Delphi2010. Would I need RAD Studio to specify which columns a shelllist view has, and in what order ? Can I use this to add creation date ? On my Delphi7/W2K graphics computer, I read something in the D7 help files about a component editor. But I couldn't find it.

I could upgrade to the full RAD Studio and Delphi 2011. Is it worth it ? Have they fixed bugs, improved or added components ?
Avatar of ChLa

ASKER

If I use a shelllistview On Change event to display the number of objects in view (ShellListView1.GetCount) it counts the objects before the change. what event happens after the change, or, what shelllistview property lists objects, or just files, after the change ?  Where can I find a list of ShellListView properties ?
Avatar of ChLa

ASKER

OK,
I see no one is responding to this any more. I suppose that means I have asked too many questions without rewarding points, or dragged this on beyond everyones patience. So I will close this and award points based on the basic question.

It's just that it's really nice to be able to ask a question as it comes up, without the formaiity of sticking to the original question, rules, zones, and awarding points. It's like E-Bay. It's easy and fun to buy things, and to find things not available elsewhere. But going back and leaving feedback is work.

It's also quite a challenge to be fair to everyone after I've gotten so much useful help. Even if I didn't use a specific answer, I learned from it and may use it later. I wonder if there's information telling me how to do this. All the comments werehelpful. Do I check that box first ? Does it matter if I check a specific solution, or do I only need to worry about awarding the right person(s). What is the difference between accept solution and accept solution and award points ?
Avatar of ChLa

ASKER

I want to thank everyone for their help