I want to get multiple different 开发者_开发百科types values (time, pressure, name, ...) from user. and I want to customize my inputbox. But it take only one value.
Are there any way to solve this situation, or any component to use?
François is right. You've reached the limit of the tool you've been given. InputBox
simply isn't designed for complex input, and it's not designed to be extended to handle multiple values, either.
The page you linked to in your comment has an example, but it's presented rather poorly, so I don't blame you for misunderstanding it. It took me a few reads to get, too. At its core is the MyAsk
function at the bottom. (Ignore the TAppendThread
class declaration at the top. It's useless.) MyAsk
accepts a list of records with with prompts and values, and for each record, it calls InputBox
to request a value from the user. It might be easier to understand without the record. It could be rewritten like this:
procedure MultiInputBox(const Prompts: array of string; var Values: array of string]);
var
i: Integer;
begin
Assert(Length(Prompts) = Length(Values));
for i := 0 to High(Prompts) do begin
Values[i] := InputBox(Application.Title, Prompts[i], Values[i]);
end;
end;
Call it like this:
TempTime := TimeToStr(DefaultTime);
TempPressure := IntToStr(DefaultPressure);
TempName := DefaultName;
MultiInputBox(['Time', 'Pressure', 'Name'], [TempTime, TempPressure, TempName]);
TimeToUse := StrToTime(TempTime);
PressureToUse := StrToInt(TempPressure);
NameToUse := TempName;
That's a terrible interface for the user, though. There's no way to go back, there's no way to cancel, there's no indication of how long the interrogation is going to last, and there's no way to enforce formats for certain data types. You'll really be much better off if you design a custom form that gets exactly the information you need. You're using a tool that makes designing a form about the easiest thing in the world. Don't resist that.
If you need to get the time, the pressure, and the name, then make a form with three input controls. Use a TDateTimePicker
for the time, consider a TSpinEdit
for the numeric input, and use a TEdit
for the name. Put TLabel
controls next to each input so the user knows what each one is for. Put OK and Cancel buttons on the form. Set various other form properties, such as the border style and the caption. There's almost no code to write in that form. You're free to add code to validate the input values, though, to make sure they make sense.
To use it, simply create it, populate its initial values, show it modally, and read the new values out when it closes.
var
form: TDatePressureNameDialog;
begin
form := TDatePressureNameDialog.Create(nil);
try
form.TimePicker.Value := DefaultTime;
form.PressureEdit.Value := DefaultPressure;
form.NameEdit.Text := DefaultName;
if form.ShowModal = mrOK then begin
TimeToUse := Frac(form.TimePicker.Value);
PressureToUse := form.PressureEdit.Value;
NameToUse := form.NameEdit.Text;
end;
finally
form.Free;
end;
end;
Notice also how I check the result of the ShowModal
method. That lets you know whether the user pressed OK or Cancel to close the form. You can't do that with InputBox
, which always returns a string. (InputQuery
can tell you that information, which is the primary difference between those two functions, but that alone doesn't really make either function worth using in your situation.)
Don't worry about this new form class weighing down your project. The two things that have the biggest impact on project size are the SysUtils and Forms units. You've already included those, so the worst of it is already past. Adding a form to a project that already has at least one form doesn't affect the project size much at all, especially not the form I described above, which only has eight controls.
What exactly do you mean by "inputbox" - a TEdit? There are many different kinds of components for input, which can do many different things. For a name, TEdit is very good - but for time, you may want a calendar control, and for pressure you may want to use a control that looks great for numbers.
Yes, design a Form!
Dialogs.InputBox is designed to get 1 string from the user, quick and simple.
If you want more, you have to design an Entry Form.
If you want a basic dialog, you can look at the code in Dialogs.InputQuery, and use it as a starting point to code your own procedure.
If you want the real deal, you have to dig in and code a real Form.
Rob's Kennedy is right.. An input box is NOT a good option... What exactly are you trying to save ? Exe Space, ressources or source code? Or you just want to save the environment with your "green" code?
If you take a look at the InputQuery function you'll see that what it does is create a TForm and it create somes TButtons/TLabels/TEdit, position and show modal the form.
Exactly what you would do with a new form that you would add to your project.. beside you can validate, customize the controls and position them and even add hints...
Go with the new form...
You don't have to set every form to auto-create, after you create your form go into project options, select the forms option and move all forms you don't want auto-created to the right.
The pattern I most generally use for these non-auto-created forms is something like the following:
Function GetValuesFromDialog : boolean;
var
dlg : tValuesDialog;
begin
result := false;
dlg := tValuesDialog.Create(nil);
try
// set initial values in dialog
dlg.SetValues( rData );
// show the dialog
result := dlg.ShowModal = mrOk;
// pull values from dialog
if result then
dlg.GetValues( rData );
finally
dlg.free;
end;
end;
the GetValues/SetValues methods populate the dialog from a record or class which holds the values that are used in the routine. I never try to manipulate controls on a form from outside the form but instead write routines to do it in the form itself.
I agree that the MultiInputBox in Rob's answer is not the greatest UX, but even so, the code you provided would not work with Delphi, because var Values: array of string
is not where your intension was going to. once you call it later with [TempTime, TempPressure, TempName]
as the second argument, that would not compile, since that is an array of const.
So you'd have to go with something like this:
Procedure MultiInputBox(const Prompts: array of string; const Values: array of pstring; ATitle: string);
var
i: integer;
begin
Assert(Length(Prompts) = Length(Values));
if(trim(ATitle)='')then ATitle := Application.Title;
for i:=0 to High(Prompts)
do if Assigned(Values[i])
then Values[i]^ := InputBox(ATitle, Prompts[i], Values[i]^);
end;
and the usage would change to:
TempTime := TimeToStr(DefaultTime);
TempPressure := IntToStr(DefaultPressure);
TempName := DefaultName;
MultiInputBox(['Time', 'Pressure', 'Name'], [@TempTime, @TempPressure, @TempName]);
TimeToUse := StrToTime(TempTime);
PressureToUse := StrToInt(TempPressure);
NameToUse := TempName;
精彩评论