I never used Indy and am struggling to learn the basic. Took me some time to figure out how to populate the listbox. Now that I have done that how can I download the selected file in the listbox ?
I tried :
procedure TFTP.Button2Click(Sender: TObject);
var
i:integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do begin
if ListBox1.Selected[i] then begin
IdFTP1.Get(listbox1.Selected[i]);
end;
end;
end;
But I am getting :
[dcc32 Error] FTP_Form.pas(75): E2250 There is no overloaded version
of 'Get' that can be called with these arguments
Or do I need to use a savedialog too? Please help me with this. :)
ListBox1.Selected[i] is a Boolean. Note that in the previous line you wrote:
if ListBox1.Selected[i] then begin
Now, look at the TIdFTP.Get() method. It has two overloads:
procedure Get(const ASourceFile: string; ADest: TStream;
AResume: Boolean = false); overload;
procedure Get(const ASourceFile, ADestFile: string; const ACanOverwrite: boolean = false;
AResume: Boolean = false); overload;
You need to provide:
the source filename of the remote file you want to download.
a destination filename or stream to receive the content of the remote file.
I don't know where you intend to obtain these. Presumably the filename comes from the ListBox, which would therefore be ListBox1.Items[i].
What do you want to do with the content you download? Keep it in memory? Save it to a file? Something else? What destination you supply depends on your answers to those questions.
My advice to you is to put the ListBox to one side for the moment, and write a simpler program, one without any UI, that simply downloads a single file from the FTP server. Use a local filename or a TFileStream to save the downloaded content to your local disk. Check that the contents are what you expect. Once you can download one file, you can download any number of files, to other kinds of destinations.
Once you have mastered that, move on to the user interface. Spend some time learning how the ListBox control works, how you populate it, how you read back strings from it, how you test for selection, and so on.
Only when you have a good understanding of all parts involved, then you should you try to fit them together.
One way ....
procedure TFTP.Button2Click(Sender: TObject);
Var
Name{, Line}: String;
begin
Name := IdFTP1.DirectoryListing.Items[ListBox1.ItemIndex].FileName;
SaveDialog1.FileName := Name;
if SaveDialog1.Execute then begin
IdFTP1.Get(Name, SaveDialog1.FileName, true);
end;
end;
Assuming the ListBox contains the remote filenames to download (such as from the TIdFTP.DirectoryListing property after a call to TIdFTP.List()):
procedure TFTP.Button2Click(Sender: TObject);
var
i:integer;
begin
for i := 0 to ListBox1.Items.Count - 1 do
begin
if ListBox1.Selected[i] then begin
IdFTP1.Get(ListBox1.Items[i], 'C:\Some Local Path\' + ListBox1.Items[i]);
end;
end;
end;
Related
I would like to retrieve the file size of a file copied into the clipboard.
I read the documentation of TClipboard but I did not find a solution.
I see that TClipboard.GetAsHandle could be of some help but I was not able to complete the task.
Just from inspecting the clipboard I could see at least 2 useful formats:
FileName (Ansi) and FileNameW (Unicode) which hold the file name copied to the clipboard.
So basically you could register one of then (or both) with RegisterClipboardFormat and then retrieve the information you need. e.g.
uses Clipbrd;
var
CF_FILE: UINT;
procedure TForm1.FormCreate(Sender: TObject);
begin
CF_FILE := RegisterClipboardFormat('FileName');
end;
function ClipboardGetAsFile: string;
var
Data: THandle;
begin
Clipboard.Open;
Data := GetClipboardData(CF_FILE);
try
if Data <> 0 then
Result := PChar(GlobalLock(Data)) else
Result := '';
finally
if Data <> 0 then GlobalUnlock(Data);
Clipboard.Close;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
if Clipboard.HasFormat(CF_FILE) then
ShowMessage(ClipboardGetAsFile);
end;
Once you have the file name, just get it's size or other properties you want.
Note: The above was tested in Delphi 7. for Unicode versions of Delphi use the FileNameW format.
An alternative and more practical way (also useful for multiple files copied) is to register and handle the CF_HDROP format.
Here is an example in Delphi: How to paste files from Windows Explorer into your application
so I have a little problem, my program finds and writes specific files (for example Mp3, wmv and etc) to a CheckBoxList, then I want to select some or all of the files to transfer those files to directory of my choosing. The problem is I dont know how can I move ONLY the selected files?
Heres a bit of code:
procedure TfrMain.Button2Click(Sender: TObject);
var
dirName : String;
begin
dirName := Edit3.Text;
CreateDir(dirName);
if DirectoryExists(dirName) then MoveFile(PChar(Path), PChar(DirName));
end;
procedure TfrMain.CheckBox2Click(Sender: TObject);
begin
if CheckBox2.Checked = true then CheckListBox1.SelectAll;
end;
Thanks in advance.
You need to iterate over the list, and then test whether or not each item is checked.
for i := 0 to CheckListBox1.Count-1 do
if CheckListBox1.Checked[i] then
// do something with the item
I'm using a TFileOpenDialog on a data entry form in Delphi XE. The user selects a PDF document in the dialog and the UNC path and filename gets stored in a database field. I want to limit the scope of where the user browses to the DefaultDirectory property and files/subdirectories below that. My hope is to prevent the user from selecting files that are on local drives or mapped drives not accessible to other users who will need the values stored in the database.
I think the way to do this is the TFileOpenDialog.OnFolderChanging event. But I’m not sure how to test if the selected file or folder is a child of DefaultDirectory. Given a filename or directory name, how can I tell if it is a dependent of DefaultDirectory?
you can compare the ShellItem property of the TFileOpenDialog dialog against the DefaultFolder property using the StartsText function and the set the CanChange value according to the result.
check this sample.
uses
StrUtils,
ActiveX,
ShlObj;
{$R *.dfm}
procedure TForm50.Button1Click(Sender: TObject);
begin
FileOpenDialog1.DefaultFolder:='C:\Program Files';
FileOpenDialog1.Execute;
end;
function GetItemName(Item: IShellItem; var ItemName: TFileName): HResult;
var
pszItemName: LPCWSTR;
begin
Result := Item.GetDisplayName(SIGDN_FILESYSPATH, pszItemName);
if Failed(Result) then
Result := Item.GetDisplayName(SIGDN_NORMALDISPLAY, pszItemName);
if Succeeded(Result) then
try
ItemName := pszItemName;
finally
CoTaskMemFree(pszItemName);
end;
end;
procedure TForm50.FileOpenDialog1FolderChanging(Sender: TObject;var CanChange: Boolean);
var
CurrentDir : TFileName;
Result : HRESULT;
begin
Result := GetItemName(TFileOpenDialog(Sender).ShellItem,CurrentDir);
CanChange := Succeeded(Result) and StartsText(TFileOpenDialog(Sender).DefaultFolder,CurrentDir);
if not CanChange then
ShowMessage('Sorry do you not have access to this folder');
end;
Just thinking along with what you're trying to do here...
You could always let the user choose a folder, and then show an error if an invalid path was chosen. After that, return the user to the root of the valid folder tree.
Advantages:
You get to do your own validation. You could have multiple starting folders, or you can have more complex patterns in what you accept and what you don't.
You can inform your users about what you want them to do, instead of forbidding what's not allowed. In modern UI patterns, it's adviced not to disable buttons, but to let the user click it, and then inform the user why a certain operation cannot be performed. Otherwise it can be confusing for users why they cannot do certain things.
I encounter problem on FastReports, it will not print correctly on pages which contain Korean character. It hapens only on Printer HP K5300 jet, T test it using rave and having no problem. I think it a bug for fast reports. I already convert all my reports from rave to FastReports and dont have plan to moved back.
I am planning to get the generated pages as images without saving it to hard drive and then generate a new preports. this time, the generated images will be used and print. I know this solution is not good. this is worable for now While waiting for their responds.
anybody has any idea how to get the images form generated pages?
If you just want to avoid saving a lot of files, you can create a new export class to print the file just after it is created and delete it instantly.
You can create a whole new export class which print the bitmap from memory (for example, using the TPrinter class and drawing the bitmap directly in the printer canvas)... you will learn how checking the source file of the TfrxBMPExport class.
Take this untested code as an example which will guide you how to create a new class to save/print/delete:
type
TBMPPrintExport = class(TfrxBMPExport)
private
FCurrentPage: Integer;
FFileSuffix: string;
protected
function Start: Boolean; override;
procedure StartPage(Page: TfrxReportPage; Index: Integer); override;
procedure Save; override;
end;
{ TBMPPrintExport }
procedure TBMPPrintExport.Save;
var
SavedFileName: string;
begin
inherited;
if SeparateFiles then
FFileSuffix := '.' + IntToStr(FCurrentPage)
else
FFileSuffix := '';
SavedFileName := ChangeFileExt(FileName, FFileSuffix + '.bmp');
//call your actual printing routine here. Be sure your the control returns here when the bitmap file is not needed anymore.
PrintBitmapFile(SavedFileName);
try
DeleteFile(SavedFileName);
except
//handle exceptions here if you want to continue if the file is not deleted
//or let the exception fly to stop the printing process.
//you may want to add the file to a queue for later deletion
end;
end;
function TBMPPrintExport.Start: Boolean;
begin
inherited;
FCurrentPage := 0;
end;
procedure TBMPPrintExport.StartPage(Page: TfrxReportPage; Index: Integer);
begin
inherited;
Inc(FCurrentPage);
end;
In production code you will want to override another methods to initialize and finalize the printer job, cleaning up, etc.
Code is based on FastReport v4.0 implementation of TfrxCustomImageExport, specially for page numbering and file naming. It may require adjustments for other FastReport versions.
You can use the TfrxBMPExport (frxExportImage unit) component to save the report as BMP.
For example, this code will export the report:
procedure ExportToBMP(AReport: TfrxReport; AFileName: String = '');
var
BMPExport: TfrxBMPExport;
begin
BMPExport := TfrxBMPExport.Create(nil);
try
BMPExport.ShowProgress := True;
if AFileName <> '' then
begin
BMPExport.ShowDialog := False;
BMPExport.FileName := AFileName;
BMPExport.SeparateFiles := True;
end;
AReport.PrepareReport(True);
AReport.Export(BMPExport);
finally
BMPExport.Free;
end;
end;
The Export component, in this case, uses a different file name for each page. If you pass 'c:\path\report.bmp' as the filename, the export component will generate c:\path\report.1.bmp, c:\path\report.2.bmp and such.
As usual, you can drop and manually configure the component on any form/data module if you prefer that way.
I want to list name of all forms exist in my project in a ListBox Dynamically, then by clicking on each of them, list all buttons exist on that form in another ListBox.
But I don't know if it can be implemented and how it can.
In case you are on Delphi 2010 you can use RTTI to list all registered ( = somehow used in the application) form classes:
uses
TypInfo, RTTI;
procedure ListAllFormClasses(Target: TStrings);
var
aClass: TClass;
context: TRttiContext;
types: TArray<TRttiType>;
aType: TRttiType;
begin
context := TRttiContext.Create;
types := context.GetTypes;
for aType in types do begin
if aType.TypeKind = tkClass then begin
aClass := aType.AsInstance.MetaclassType;
if (aClass <> TForm) and aClass.InheritsFrom(TForm) then begin
Target.Add(aClass.ClassName);
end;
end;
end;
end;
You must somehow take care that the class is not completely removed by the linker (therefor the registered hint above). Otherwise you cannot get hands on that class with the method described.
The forms are usually listed using Screen.Forms property, ex:
procedure TForm1.Button1Click(Sender: TObject);
var
I: Integer;
begin
Memo1.Lines.Clear;
for I:= 0 to Screen.CustomFormCount - 1 do
Memo1.Lines.Add(Screen.Forms[I].Caption);
end;
sabri.arslan's answer is the way to go to find all instantiated forms at run-time.
In the comments Hamid asked for a way to find unassigned forms as well. Assuming that by unassigned he means uninstantiated forms, there would be only one way to do so and that is to iterate over the registry of classes used by the vcl streaming system to instantiate components by name when a dfm is streamed in.
However, IIRC, forms are not automatically added to the registry. In fact, if you want to instantiate forms based on a string of their name, you need(ed) to add them to the class registry yourself. OP could of course do that for each of the forms in his project himself. But, that leaves the problem that the class registry used by the streaming system is implemented using var's in the implementation section of the classes unit. And therefore can't be iterated over (easily) from the outside.
So the solution would be to use the initialization section of all form units in the project and register each form in a "roll-your-own" registry with their name and class and have the registry provide the methods to iterate over the registered forms. These method can be used to populate the listbox mentioned by the OP.
To get at the TButtons on a form would then require instantiating the form (it could remain hidden) and iterating over the components using code similar to sabri.arslan's answer to find the TButton instances.
Instantiating the form would require getting the class of the form from the registry based on the form's name selected in the listbox.
Example of a simple roll-your-own form registry:
unit Unit1;
interface
uses
Classes
, Forms
, SysUtils
;
procedure RegisterForm(aName: string; aClass: TFormClass);
procedure ListForms(aNames: TStrings);
function InstantiateForm(aName: string): TCustomForm;
implementation
var
FormRegistry: TStringList;
procedure RegisterForm(aName: string; aClass: TFormClass);
begin
FormRegistry.AddObject(aName, Pointer(aClass));
end;
procedure ListForms(aNames: TStrings);
var
i: Integer;
begin
for i := 0 to FormRegistry.Count - 1 do begin
aNames.Add(FormRegistry[i]);
end;
end;
function InstantiateForm(aName: string): TCustomForm;
var
idx: Integer;
frmClass: TFormClass;
begin
Result := nil;
idx := FormRegistry.IndexOf(aName);
if idx > -1 then begin
frmClass := TFormClass(FormRegistry.Objects[idx]);
Result := frmClass.Create(nil);
end;
end;
initialization
FormRegistry := TStringList.Create;
FormRegistry.Duplicates := dupError;
FormRegistry.Sorted := True;
finalization
FreeAndNil(FormRegistry);
end.
you can use "for" loop.
procedure ListForms(lbForms:TListBox);
var
i,j:integer;
begin
for i:=0 to application.ComponentCount-1 do
if application.components[i] is tform then
begin
lbForms.add(tform(application.components[i]).Name);
end;
end;
procedure ListBox1Click(Sender:TObject);
var
ix,j,i:integer;
begin
ix:=ListBox1.ItemIndex;
if ix>=0 then
begin
for i:=0 to application.componentcount-1 do
if application.components[i] is tform then
begin
if tform(application.components[i]).name=listbox1.items.strings[ix] then
begin
for j:=0 to tform(application.components[i]).controlcount - 1 do
if tform(application.components[i]).controls[i] is tbutton then
begin
listbox2.add(tbutton(tform(application.components[i]).controls[i]).caption);
end;
break;
end;
end;
end;
end;
There is no way (easy) to find the included forms.
But if you loop through the RCdata of the resources (See (1) (2) (3)), you can find the names of the forms. But that dosn't help you creating them.
In order to make forms "findable" the have to "register" them yourself, using RegisterCLass og finding them again using FindClass. See an example here: http://www.obsof.com/delphi_tips/delphi_tips.html#Button
Do you need this to be built at run time, or would compile time information work for you?
In recent versions (Delphi 2006 and higher?), you can set a compiler option to generate XML documentation for your project. A separate XML file is generated for each unit. You could parse this XML to find and forms and look at the members for any buttons.