StrToDate do not use my FormatSetting [closed] - delphi

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 9 years ago.
In my big application I try to read another dateformat than my locale settings. But that failed with exception. So I made a simple demo to reproduce.
Could be that I made a simple error. My local settings in Windows XP is Finnish date format that is 'd.m.yyyy'. I want to read Swedish format that is 'yyyy-mm-dd'. Please help!
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
const
cnFormat = 'yyyy-mm-dd'; // Swedish dateformat
cnFIFormat = 'd.m.yyyy'; // Finnish dateformat
type
TForm5 = class(TForm)
procedure FormCreate(Sender: TObject);
private
fSetting: TFormatSettings;
function GetCustomDateFormatSettings(aDateFormat: String = cnFormat): TFormatSettings;
function GetSafeDate(aDate: String): TDate;
end;
var
Form5: TForm5;
implementation
{$R *.dfm}
procedure TForm5.FormCreate(Sender: TObject);
var
vDate: TDate;
begin
fSetting := GetCustomDateFormatSettings;
vDate := GetSafeDate('2010-01-04');
end;
function TForm5.GetCustomDateFormatSettings(aDateFormat: String): TFormatSettings;
begin
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, Result);
Result.ShortDateFormat := aDateFormat;
end;
function TForm5.GetSafeDate(aDate: String): TDate;
begin
try
Result := StrToDate(aDate, fSetting); // <- Exception here
except
on E: EConvertError do
begin
// logic to recover from exception
end;
end;
end;
end.

Ok, got the answer. I forgot the DateSeparator. So to avoid exception in the demo I add one line. Have to make that more dynamic then...
function TForm5.GetCustomDateFormatSettings(aDateFormat: String): TFormatSettings;
begin
GetLocaleFormatSettings(LOCALE_SYSTEM_DEFAULT, Result);
Result.ShortDateFormat := aDateFormat;
Result.DateSeparator := '-';
end;

Related

Strange Format result in Delphi XE2 when using Currency data types

In Delphi XE2, I bumped against a strange formatting difference when formatting Currency. Using Double works as expected.
It looks that when using %F or %N (floating point or numeric) you always get 3 decimal digits, even if you request fewer.
With format '%.1f' a Double value of 3.1415 will become '3.1', but a Currency value of 3.1415 will become '3.142' (assuming en-US locale).
With format '%4.0n' a Double value of 3.1415 will become ' 3', but a Currency value of 3.1415 will become '3.142' (assuming en-US locale).
I wrote the below quick DUnit test case, and will investigate further tomorrow.
This particular project cannot be changed to anything other than Delphi XE2 (big corporates are not flexible in what tools they use), so I'm looking for a solution that solves this in Delphi XE2.
In the mean time: what are your thoughts?
unit TestSysUtilsFormatUnit;
interface
uses
TestFramework, System.SysUtils;
type
TestSysUtilsFormat = class(TTestCase)
strict private
DoublePi: Double;
CurrencyPi: Currency;
FloatFormat: string;
NumericFormat: string;
Expected_Format_F: string;
Expected_Format_N: string;
public
procedure SetUp; override;
procedure TearDown; override;
published
procedure Test_Format_F_Double;
procedure Test_Format_F_Currency;
procedure Test_Format_N_Double;
procedure Test_Format_N_Currency;
end;
implementation
procedure TestSysUtilsFormat.Test_Format_F_Double;
var
ReturnValue: string;
begin
ReturnValue := System.SysUtils.Format(FloatFormat, [DoublePi]);
Self.CheckEqualsString(Expected_Format_F, ReturnValue); // actual '3.1'
end;
procedure TestSysUtilsFormat.Test_Format_F_Currency;
var
ReturnValue: string;
begin
ReturnValue := System.SysUtils.Format(FloatFormat, [CurrencyPi]);
Self.CheckEqualsString(Expected_Format_F, ReturnValue); // actual '3.142'
end;
procedure TestSysUtilsFormat.Test_Format_N_Double;
var
ReturnValue: string;
begin
ReturnValue := System.SysUtils.Format(NumericFormat, [DoublePi]);
Self.CheckEqualsString(Expected_Format_N, ReturnValue); // actual ' 3'
end;
procedure TestSysUtilsFormat.Test_Format_N_Currency;
var
ReturnValue: string;
begin
ReturnValue := System.SysUtils.Format(NumericFormat, [CurrencyPi]);
Self.CheckEqualsString(Expected_Format_N, ReturnValue); // actual '3.142'
end;
procedure TestSysUtilsFormat.SetUp;
begin
DoublePi := 3.1415;
CurrencyPi := 3.1415;
FloatFormat := '%.1f';
Expected_Format_F := '3.1';
NumericFormat := '%4.0n';
Expected_Format_N := ' 3';
end;
procedure TestSysUtilsFormat.TearDown;
begin
end;
initialization
RegisterTest(TestSysUtilsFormat.Suite);
end.
Posting this as an answer on the request of the asker in the comments to the question above.)
I can't reproduce the issue on either XE2 or XE3, with a plain console application. (It was just quicker to set up for me.)
Here's the code I used in it's entirely (on both XE2/XE3):
program Project1;
{$APPTYPE CONSOLE}
{$R *.res}
uses
SysUtils;
const
DoublePi: Double = 3.1415;
CurrencyPi: Currency = 3.1415;
FloatFormat = '%.1f';
NumericFormat = '%4.0n';
begin
WriteLn(Format('Double (.1f) : '#9 + FloatFormat, [DoublePi]));
WriteLn(Format('Currency (.1f) : '#9 + FloatFormat, [CurrencyPi]));
WriteLn(Format('Currency (4.0n): '#9 + NumericFormat, [CurrencyPi]));
ReadLn;
end.
Here's the output from the XE2 run (Delphi® XE2 Version 16.0.4429.46931):
:
This was a bug in early Delphi XE 2 versions in these methods:
function WideFormatBuf(var Buffer; BufLen: Cardinal; const Format;
FmtLen: Cardinal; const Args: array of const;
const AFormatSettings: TFormatSettings): Cardinal;
function FormatBuf(var Buffer; BufLen: Cardinal; const Format;
FmtLen: Cardinal; const Args: array of const;
const AFormatSettings: TFormatSettings): Cardinal;
Fails:
Embarcadero® RAD Studio XE2 Version 16.0.4256.43595 (Update 2)
(The odd thing is: that version indicates "no updates available" with starting the "check for updates")
I did not have time to check intermediate versions.
Works:
Embarcadero® RAD Studio XE2 Version 16.0.4429.46931 (Update 4))
Embarcadero® Delphi® XE2 Version 16.0.4504.48759 (Update 4 hotfix 1)
One of the things that XE2 Update 4 (with or without the hotfix) breaks is the creation of a standard (non-IntraWeb) unit test project.
This menu entry is missing: File -> New -> Other -> Unit Test -> Test Project.
As a reminder to myself, this is the skeleton code to quickly get started with the missing Test Project entry:
program UnitTest1;
{
Delphi DUnit Test Project
-------------------------
This project contains the DUnit test framework and the GUI/Console test runners.
Add "CONSOLE_TESTRUNNER" to the conditional defines entry in the project options
to use the console test runner. Otherwise the GUI test runner will be used by
default.
}
{$IFDEF CONSOLE_TESTRUNNER}
{$APPTYPE CONSOLE}
{$ENDIF}
uses
Forms,
TestFramework,
GUITestRunner,
TextTestRunner;
{$R *.RES}
begin
Application.Initialize;
if IsConsole then
with TextTestRunner.RunRegisteredTests do
Free
else
GUITestRunner.RunRegisteredTests;
end.

How to add support of HTML help files (.chm) on Delphi XE2?

How to add support of HTML help files (.chm) on Delphi XE2? We need to use A-links (A-keywords) on HelpContext property of every control to lookup help pages. Delphi XE2 has native support of HTML help files by unit HTMLHelpViewer. But how to use it?
It's not hard with F1 jump to a context.
Select Edit1 and press F1 . Help opens and Overview.htm is shown.
Prerequisite.
Edit1 Help settings:
sample.chm source settings.
sample.ali
IDH_Overview=Overview.htm
IDH_welcom=FirstTopic.htm
IDH_UsingtheMenus=Overview.htm
sample.h
#define IDH_Creating_Projects_and_Topics 1005
#define IDH_Overview 1003
#define IDH_UsingtheMenus 1009
Unit1.pas
unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, HTMLHelpViewer, Vcl.ExtCtrls;
type
TForm1 = class(TForm)
HHALINKLOOKUP: TButton;
JumpAnchor: TButton;
Edit1: TEdit;
Label1: TLabel;
procedure FormCreate(Sender: TObject);
procedure HHALINKLOOKUPClick(Sender: TObject);
procedure JumpAnchorClick(Sender: TObject);
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
hpPath : string;
link : HH_AKLINK;
procedure TForm1.FormCreate(Sender: TObject);
begin
hpPath := ExtractFilePath(Application.ExeName) +
'HelpFile\sample.chm';
Application.HelpFile := hpPath;
end;
procedure TForm1.HHALINKLOOKUPClick(Sender: TObject);
var
link : HH_AKLINK;
szUrl,szKey,szMsgText,szMsgTitle,szWindow : AnsiString;
begin
szKey := Edit1.Text; // 'UsingtheMenus';
szUrl :='Overview.htm';
szMsgText :='Error: Can''t find "'+Edit1.Text+'"!';
szMsgTitle :='Error: HH_ALINK_LOOKUP';
szWindow :='main';
with link do begin
cbStruct := sizeof(HH_AKLINK) ;
fReserved := False;
pszKeywords := PChar(szKey);
pszUrl := nil;
pszMsgText := PChar(szMsgText);
pszMsgTitle := PChar(szMsgTitle);
pszWindow := PChar(szWindow);
fIndexOnFail:= False;
end;
HtmlHelpW(0, hpPath+'>main', HH_DISPLAY_TOPIC, DWORD_PTR(nil));
HtmlHelpW(0, hpPath, HH_ALINK_LOOKUP, DWORD_PTR(#link));
end;
procedure TForm1.JumpAnchorClick(Sender: TObject);
begin
HtmlHelpW(0, hpPath+'::/Overview.htm#'+Edit1.Text+'>main', HH_DISPLAY_TOPIC, DWORD(nil));
end;
end.
Here is a ready to use sample.chm and the source Download
There is a trick how to easily, to jump, not only to the .htm file but jumps directly to an anchor.
Change sample.ali
IDH_Overview=Overview.htm
IDH_welcom=FirstTopic.htm
IDH_UsingtheMenus=Overview.htm#UsingtheMenus
Insert an anchor at the place, you want to jump to in Overview.htm
[...]
<A NAME="UsingtheMenus" </A>
<P><STRONG>Using the Menus and Toolbars</STRONG>
<P>The menus and toolbars provide a complete set of tools
[...]
Now it is possible with F1, jump directly to the desired point in overview.htm.
I suspect that to use A-links you need to do the following:
Assign an Application.OnHelp handler as described below.
Assign Application.HelpFile during program startup.
Call Application.HelpKeyword if you wish to invoke the help system with an A-link.
Set the HelpKeyword property for any GUI controls that you wish to respond to context sensitive F1 key presses.
The OnHelp handler looks like this:
function TMainForm.ApplicationHelp(Command: Word;
Data: THelpEventData; var CallHelp: Boolean): Boolean;
var
Link: THH_AKLink;
ALink: string;
begin
CallHelp := False;
Result := True;
//argh, WinHelp commands
case Command of
HELP_COMMAND:
begin
ZeroMemory(#Link, SizeOf(Link));
Link.cbStruct := SizeOf(Link);
ALink := PChar(Data); // we are going to re-purpose the keyword as an A-link
Link.pszKeywords := PChar(AnsiString(ALink)); // seems we have to pass a PAnsiChar ..
Link.fIndexOnFail := True;
HtmlHelp(GetDesktopWindow, Application.HelpFile, HH_ALINK_LOOKUP,
DWORD_PTR(#Link));
end;
end;
end;
The HtmlHelpViewer unit contains methods named LookupALink which do the same. But I don't see how they could ever be called.
The above approach is a little bit hacky because it interprets keywords as A-Links. If you want context sensitive help, I can't see what else you can do.
Not sure how Xe2 viewer works (I'm on 2007) but I just use Eric Granges port of the Microsoft HTML help API, which unsurprisingly, is called HTMLhelpAPI.pas.
You can call an Alink using the function
ChmShowTopic(const filename,atopic:string):HWND;

Delphi: How to use ShowWindow properly on external application [duplicate]

This question already has an answer here:
How can I make the second instance of my program pass control back to the first instance?
(1 answer)
Closed 8 years ago.
See also:
How can I tell if another instance of my program is already running?
i use the following code before starting my application, to check if another instance
of it is already started:
var _PreviousHandle : THandle;
begin
_PreviousHandle := FindWindow('TfrmMainForm',nil);
if _PreviousHandle <> 0 then
begin
ShowMessage('Application "" is already running!');
SetForegroundWindow(_PreviousHandle);
ShowWindow(_PreviousHandle, SW_SHOW);
Application.Terminate;
Exit;
end;
...
However, if it has started, i need to show that application. The problem is after it is shown in this way the minimize button no longer works, and when i click the icon in the taskbar, it "unminimizes" and the animation that is shown is as if it was minimized. Am i missing something? is there a proper way to activate and show external application while it's minimized?
Here is a complete project, which keeps running only one instance of the application, and which should bring already running instance window to front.
You can download a testing project or try the code, which follows:
Project1.dpr
program Project1;
uses
Forms,
Windows,
Unit1 in 'Unit1.pas' {Form1};
{$R *.res}
var
Mutex: THandle;
const
AppID = '{0AEEDBAF-2643-4576-83B1-8C9422726E98}';
begin
MessageID := RegisterWindowMessage(AppID);
Mutex := CreateMutex(nil, False, AppID);
if (Mutex <> 0) and (GetLastError = ERROR_ALREADY_EXISTS) then
begin
PostMessage(HWND_BROADCAST, MessageID, 0, 0);
Exit;
end;
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.Run;
end.
Unit1.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StrUtils, StdCtrls;
type
TForm1 = class(TForm)
private
function ForceForegroundWindow(WndHandle: HWND): Boolean;
function ForceRestoreWindow(WndHandle: HWND; Immediate: Boolean): Boolean;
protected
procedure WndProc(var AMessage: TMessage); override;
end;
var
Form1: TForm1;
MessageID: UINT;
implementation
{$R *.dfm}
{ TForm1 }
function TForm1.ForceForegroundWindow(WndHandle: HWND): Boolean;
var
CurrThreadID: DWORD;
ForeThreadID: DWORD;
begin
Result := True;
if (GetForegroundWindow <> WndHandle) then
begin
CurrThreadID := GetWindowThreadProcessId(WndHandle, nil);
ForeThreadID := GetWindowThreadProcessId(GetForegroundWindow, nil);
if (ForeThreadID <> CurrThreadID) then
begin
AttachThreadInput(ForeThreadID, CurrThreadID, True);
Result := SetForegroundWindow(WndHandle);
AttachThreadInput(ForeThreadID, CurrThreadID, False);
if Result then
Result := SetForegroundWindow(WndHandle);
end
else
Result := SetForegroundWindow(WndHandle);
end;
end;
function TForm1.ForceRestoreWindow(WndHandle: HWND;
Immediate: Boolean): Boolean;
var
WindowPlacement: TWindowPlacement;
begin
Result := False;
if Immediate then
begin
WindowPlacement.length := SizeOf(WindowPlacement);
if GetWindowPlacement(WndHandle, #WindowPlacement) then
begin
if (WindowPlacement.flags and WPF_RESTORETOMAXIMIZED) <> 0 then
WindowPlacement.showCmd := SW_MAXIMIZE
else
WindowPlacement.showCmd := SW_RESTORE;
Result := SetWindowPlacement(WndHandle, #WindowPlacement);
end;
end
else
Result := SendMessage(WndHandle, WM_SYSCOMMAND, SC_RESTORE, 0) = 0;
end;
procedure TForm1.WndProc(var AMessage: TMessage);
begin
inherited;
if AMessage.Msg = MessageID then
begin
if IsIconic(Handle) then
ForceRestoreWindow(Handle, True);
ForceForegroundWindow(Application.Handle);
end;
end;
end.
Tested on OS versions:
Windows 8.1 64-bit
Windows 7 SP1 64-bit Home Premium
Windows XP SP 3 32-bit Professional
Known issues and limitations:
The MainFormOnTaskbar is not taken into account at all; it must be set to True at this time
You're asking your Main form to show, but it may occur the application hidden window itself is minimized when you minimize the application to the task bar, in case of MainFormOnTaskBar being false.
Don't call the ShowWindow method from the oustide. IMHO it's better if you pass a message to the application and respond from inside, calling the Application.Restore` method, which performs the proper ShowWindow calls among other things.
This is a very common problem with VCL apps, and has been asked and answered many many times in the Borland/CodeGear/Embarcadero forums over the years. Using ShowWindow() in this manner does not work for VCL windows very well because of the way the MainForm interacts with the TApplication object at runtime, especially in different versions of Delphi. What you should do instead is have the second instance send a custom message to the first instance, and then let the first instance restore itself as needed when it receives the message, such as by setting its MainForm.WindowState property, or calling Application.Restore(), etc, and let the VCL work out the details for you, like #jachguate suggested.
The following works well for me. I'm not 100% certain I have fully understood the question though, so do let me know if I've got it wrong.
var
_PreviousHandle: HWND;
WindowPlacement: TWindowPlacement;
....
WindowPlacement.length := SizeOf(WindowPlacement);
GetWindowPlacement(_PreviousHandle, WindowPlacement);
if WindowPlacement.flags and WPF_RESTORETOMAXIMIZED<>0 then
WindowPlacement.showCmd := SW_MAXIMIZE
else
WindowPlacement.showCmd := SW_RESTORE;
SetWindowPlacement(_PreviousHandle, WindowPlacement);
SetForegroundWindow(_PreviousHandle);
Note that the correct type for _PreviousHandle is HWND and not THandle.

This program spending too much time,even no respond,is there any way to improve it? [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
1, Add a popupmenu named PopupMenu1
2, Add a menuitem named TestMI
3, Add a Button
and code :
procedure TForm1.Button1Click(Sender: TObject);
var
MItems: array of TMenuItem;
SList: TStringList;
FileRec: TSearchrec;
i: integer;
begin
SList := TStringList.Create;
//3000+ files
if FindFirst('C:\Windows\System32\*', faNormal or faDirectory, FileRec) = 0
then
repeat
if (FileRec.Name = '.') or (FileRec.Name = '..') then
Continue;
SList.Add(FileRec.Name);
until FindNext(FileRec) <> 0;
FindClose(FileRec);
if SList.Count > 0 then
begin
SetLength(MItems, SList.Count);
for i := 0 to SList.Count - 1 do
begin
MItems[i] := TMenuItem.Create(TestMI);
MItems[i].Caption := SList[i];
end;
TestMI.Add(MItems);
end;
end;
When I click button , it's OK , but when i popup PopupMenu1 and move on TestMI,Because too many files it no respond.
Is there any way to solve it?
Updata :
I have to use PopupMenu to do this .
I find a program , can do it fast , take 150ms
https://docs.google.com/open?id=0B1sDNMAzGE2oZWpTWlpWNHJGZzQ
it use BarMenu Components
but i can't compile in Delphi 2009.
Error :
lib\BarMenus:
{$IFDEF MSWINDOWS}
{$IFNDEF DFS_COMPILER_5_UP}
{$MESSAGE FATAL 'You need Delphi 5 or higher in order to compile this unit.'}
{$ENDIF}
Windows, SysUtils, Classes, Graphics, Menus, Forms;
{$ENDIF}
update to #Sertac Akyuz
you solution is useful , in first case. and very thank you.
and i change that case
Code :
unit Unit1;
interface
uses
Windows,
Messages,
SysUtils,
Variants,
Classes,
Graphics,
Controls,
Forms,
Dialogs,
StdCtrls,
Menus;
type
TForm1 = class(TForm)
Button1: TButton;
PopupMenu1: TPopupMenu;
TestMI: TMenuItem;
procedure Button1Click(Sender: TObject);
procedure CreMI(MI: TMenuItem);
procedure IMonClick(Sender: TObject);
procedure AddSubEmpItem(MI: TMenuItem);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.IMonClick(Sender: TObject);
begin
CreMI(TMenuItem(Sender));
end;
procedure TForm1.AddSubEmpItem(MI: TMenuItem);
var
EmpIM: TMenuItem;
begin
EmpIM := TMenuItem.Create(MI);
with EmpIM do
begin
Caption := '(Folder empty)';
Enabled := False;
Hint := '';
MI.Add(EmpIM);
end;
end;
procedure TForm1.CreMI(MI: TMenuItem);
var
MItems: array of TMenuItem;
SList: TStringList;
FileRec: TSearchrec;
i: integer;
begin
if (MI.Items[0].Caption = '(Folder empty)') and (MI.Count = 1) then
begin
SList := TStringList.Create;
if FindFirst(MI.Hint + '\*', faNormal or faDirectory, FileRec) = 0
then
repeat
if (FileRec.Name = '.') or (FileRec.Name = '..') then
Continue;
SList.Add(FileRec.Name);
until FindNext(FileRec) <> 0;
FindClose(FileRec);
if SList.Count > 0 then
begin
SetLength(MItems, SList.Count);
for i := 0 to SList.Count - 1 do
begin
MItems[i] := TMenuItem.Create(MI);
MItems[i].Caption := SList[i];
MItems[i].Hint := MI.Hint + SList[i] + PathDelim;
AddSubEmpItem(MItems[i]);
MItems[i].OnClick := IMonClick;
MItems[i].AutoHotkeys := maManual;
end;
MI.Add(MItems);
MI.AutoHotkeys := maManual;
end;
end;
//Button1.Caption := IntToStr(MI.Count);
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
AddSubEmpItem(TestMI);
CreMI(TestMI);
end;
end.
Set TestMI.Hint := C:\
Click the button and when I move on C:\ -> Windows -> System32 it no respond too.
can you give some adviese?
A quick test shows the time is spent in InternalRethinkHotkeys. Hot keys won't help with a menu with > 3000 items. Just disable it:
..
TestMI.Add(MItems);
TestMI.AutoHotkeys := maManual; // <--
end;
end;
Having said that, also consider using some other gui element like a list box etc., scrolling through that much items in a menu is practically impossible.
You said:
When I click button , it's OK
So I assume that the file search is quick, and it's adding the menu options quickly, so a background thread isn't going to solve your problem. Your problem is that you are stuffing thousands of entries into a menu, which is not going to work. You need to re-think. Maybe a listbox would be better. Be sure to use BeginUpdate/EndUpdate to enclose your loop.
First, let's assume that you're really smart enough to know that creating a menu with a million items in it is silly, so let's take this as an opportunity to just discuss technical matters, because as all the commenters say, your idea is not workable, but perhaps in your real program you're going to build a list of word documents in a folder only on your computer, so you picked the Windows folder for sake of illustration only. So let us proceed then:
A beginning Delphi programmer would probably insert Application.ProcessMessages call in there, and now, your application will not show "not responding", however you would be introducing some potential for bad things (including crashes) happening, depending on what goes on in the rest of your application. If this is a throwaway program, I would be tempted to simply add the "Application.ProcessMessages" call (once ever 100 times through the loop or so), and my app would not show "not responding".
However in a real-stable-production code environment you should be separating your UI building code (view builder) from your background worker thread.
And a worker thread is not going to be trivial to implement either, because you are effectively working on building a menu using VCL classes that are not supposed to be accessed from the background threads. If you really want to generate a popup menu with 100,000 items in it, there's no nice fast way to do it.
I suggest you should think about some object oriented design:
worker thread with a limit on how large a list of items it will build.
When worker thread completes the FindFirst loop, and moves on to creating menu items, consider using TThread.Synchronize() or some other safe means to make sure that the the method that will add a menu item, which is invoked from a background thread, can do so safely.
Update Edits to this question have rendered this answer rather out of date. Sadly the question is a moving target.

Select Directory error ... delphi 7 [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
unit unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls,FileCtrl,omnixml,omnixmlutils;
type
TForm1 = class(TForm)
btn1: TButton;
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
procedure olddiris(name:string);
procedure GetPath(name:string);
{ Public declarations }
end;
var
Form1: TForm1;
olddir: string; //global variable.
implementation
{$R *.dfm}
procedure Tform1.olddiris(name:string);
begin
if name = 'trick' then
olddir:= 'c:\program files'+name;
end;
procedure Tform1.GetPath(name:string);
var
options : TSelectDirOpts;
begin
OldDirIs(name); //returns olddir
if SelectDirectory(OldDir,options,0) then
ShowMessage('i got it');
end;
procedure TForm1.btn1Click(Sender: TObject);
begin
getpath('trick');
end;
end.
Options is TSelectDirOpts = set of TSelectDirOpt;
TSelectDirOpt Standard is {TSelectDirOpt = (
sdAllowCreate,
sdPerformCreate,
sdPrompt
)
gFindDirs is a simple variable that keeps the Name nothing else so i erase it.
The setPath(gFindDirs) just forget it ok i replace it with a simple massage..
When I run it i get an error: the "class Estringlist.error: List index out of bounds(0)";
I try this with the component jvselectdirectory of jvcl library but I get the same thing...
in jvselectdirectory if I left it empty it goes me to the default application folder...
Here is all the program... push the button get the name turn into an existing directory i create before and try to open it with the selectdirectory that's it i get the above error...
FULL CODE nothing else create a form and put a button one event onclick().
Oops Sorry i fix it.... The rush to fix it wrong copy paste...
Help...
var
olddir: string; //global variable
procedure olddiris(name:string);
begin
if name = 'trick' then
olddir:= 'c:\program files\'+name;
end;
procedure MyGetPath(name:string);
var
options : TSelectDirOpts;
begin
OldDirIs(name); //returns olddir
if FileCtrl.SelectDirectory(OldDir,options,0) then
ShowMessage('i got it');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
Mygetpath('trick');
end;
This code runs without error... (Note: changed GetPath -> MyGetPath; added "\" to 'c:\program files') If the problem still exists, look elsewhere in you code or post more code/info.
You should replace your code with
procedure GetPath(name:string);
var
options : TSelectDirOpts;
begin
FixedOldDirIs(name); //returns olddir
gFindDirs := name;
if FixedSelectDirectory(OldDir,options,0) then
FixedSetPath(gFindDirs);
end;
That should do the trick (if I understand your question correctly...)

Resources