TEdit.Text won't update with user entered text - delphi

I wrote a program where a TEdit (Edit1) and TButton (Button1) are used. When Button1 is pressed, the content of Edit1.Text is compared to a string constant. If both are identical, some other buttons will be set active. Edit1 and Button1 were directly placed onto Form1.
This all worked.
Then I rearranged Form1 (appearance of the window). I added some Panels and GridPanels. Button1 and Edit1 moved from Form1 to Form1->Panel5->GridPanel2.
Since then, things do not work anymore.
When I read Form1.Edit1.Text, only the original text shows up. When the program runs and I type something into Edit1, the typed text is visible. But the reading/content
of Form1.Edit1.Text does not change.
Is there any setting that stops that the data entered into the edit field is put into Edit.Text?
Whatever I type, Edit1.Text remains the original content that is in the code (Object Inspector).
I already did it a couple of times that I moved items onto panels and never had such a behavior.
Here is the code, that was not changed after moving Button1 and Edit1 onto panels.
procedure TForm1.Button1Click(Sender: TObject);
begin
//showmessage for debugging to see what the content is
showmessage(Form1.Edit1.Text);
if Form1.Edit1.Text = '1234' then
begin
// enable a button and an edit
Form1.Button_Open.Enabled := True;
Form1.Edit_Id.Enabled := True;
end
else
begin
showmessage('Wrong input');
// room for more code
end;
end;
I tried to find settings that stop data entered into the text field from updating Edit1.Text, but I did not find anything.
I deleted Edit1 and Button1 and entered new ones with the same names at the places they were before (GridPanel), but that still did not work.
I deleted Edit1 and Button1 and entered new ones with different names at the places they were before (GridPanel), but still did not work.
I deleted Edit1 and Button1 and entered new ones directly on Form1, but they also showed the same behavior.
Nothing that I type into the text field finds its way into Edit1.Text. It remains the original text that has been typed into the code.

I found the reason, by looking into the main program/project file:
Form1 was actually called twice. By deleting the second call, the program started to work as it should.
program Project1;
uses
Vcl.Forms,
Vcl.Themes,
Vcl.Styles,
EMR.pas {Form1};
{$R *.res}
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm1, Form1); //called twice!!
Application.Run;
end.

Related

Displaying a disabled modal form

I'm trying to disable a TForm's descendant and showing it as a modal form.
procedure TForm1.Button1Click(Sender: TObject);
var
Frm : TMyForm;
begin
Frm := TMyForm.Create(nil);
try
Frm.Enabled := False;
Frm.ShowModal();
finally
Frm.Free;
end;
end;
At runtime, it raises the following error message:
Cannot make a visible window modal.
The OP wants to display a disabled form modally when the form should be displayed for read-only purposes.
Disabling the form is the wrong thing to do.
How do you display the information? If you are using TEdit, TMemo, or TRichEdit controls, you should simply set them to read only. Otherwise, if you have some combinations of various controls like radio buttons, you should disable each and every such control, not the form itself. I mean, surely you still want the Cancel button to be enabled?
In addition, disabling the form instead of the actual controls will make the controls look enabled, which is very confusing! That's an important point.
So what you need to do is to display the form normally (not disabled!) and then set its controls to their appropriate states when the dialog is shown.
Just to emphasise my point about disabling the form vs its controls, consider this dialog box:
If I do
procedure TCustomViewFrm.FormShow(Sender: TObject);
begin
Enabled := False;
end;
then it looks like this when shown:
As you can see, every control looks very enabled indeed, but no control responds to mouse or keyboard input. This is very confusing and a horribly bad UX.
In fact, you cannot even close the dialog box using its title-bar Close button or Alt+F4. You cannot close it using its system menu, either. In fact, you cannot close it at all, because to close a window, it must respond to user input, and a disabled window doesn't do that. (You cannot move the window, either.)
Instead, if we disable all controls (except the Cancel button),
procedure DisableControl(AControl: TWinControl);
begin
for var i := 0 to AControl.ControlCount - 1 do
begin
if
(AControl.Controls[i] is TCustomButton)
and
(TCustomButton(AControl.Controls[i]).ModalResult = mrCancel)
then
Continue;
if AControl.Controls[i] is TWinControl then
DisableControl(TWinControl(AControl.Controls[i]));
AControl.Controls[i].Enabled := False;
end;
end;
procedure TCustomViewFrm.FormShow(Sender: TObject);
begin
DisableControl(Self);
end;
you get this nice UI:
Not only is it very clear that all controls are disabled, the user can also close the dialog box without killing your application using the Task Manager.

Delphi - How to copy the text from one tedit to another, while the user is typing in the first one?

There are two tedit
One is enabled for the user, and the other disabled.
The moment user types anything in the tedit, the same thing gets typed in the disabled tedit, while the user is typing.
I don't want to use any buttons for this.
How to implement this in Delphi?
You can use the OnChange event of your first TEdit and set text of the second edit to the text of the first. This should look like
procedure TForm1.Edit1Change(Sender: TObject);
begin
Edit2.Text := Edit1.Text;
end;

Delphi XE5 Firemonkey TTabItem and TEdit repaint coordination

I created a TTabControl with two TTabItems. On each TTabItem there is one (or more) TImageViewers and several TEdits. When I click on the TImageViewer, a modal screen pops up, I set some values, and I want to report those values to the user through the TEdits. So on returning from the Modal screen,
I execute
editn.text := whateveritis;
I then say
editn.repaint;
Nothing happens. I say TTabItem.repaint. Nothing happens. I click the other TTabIem and then come back to the first TabItem and, voila, the Edit control contains the right information. So my editn.text := whateveritis must be working (that's the only write to the TEdit), but I can't get the blinkin' control to show the result without going off-tab. How do I get it to redisplay as soon as I change the content? Do I need to write an OnChange routine that is one line, self.repaint? Seems ugly, and I'd hope there's a more global approach. Suggestions?
In light of initial comments, let me give more details. Setup: In main screen, drop in tabcontrol, and in tabcontrol drop in 2 tabitems. In tabitem1, drop in a timageviewer and 4 tedits (plus other stuff, probably irrelevant). Image gets dropped into the imageviewer (and displays correctly). The onclick event activates the following (ellipsis cuts out irrelevant code):
procedure TSCKMain.ImageViewer1Click(Sender: TObject);
var
lochold, scrollhold : tpoint;
backfromwavform : tmodalresult;
begin
lochold.X := mouseloccallback.x;
lochold.Y := mouseloccallback.y;
scrollhold.X := round(imageviewer1.ViewportPosition.X);
scrollhold.Y := round(imageviewer1.ViewportPosition.Y);
…
repeat backfromwavform := Wavform.Showmodal until backfromwavform<>mrnone;
case backfromwavform of
mrOK : begin {blue end}
Specsingle.BlueEnd.X := lochold.X;
Specsingle.BlueEnd.y := lochold.y;
edit13.Text := inttostr(Specsingle.BlueEnd.X);
Edit14.Text := inttostr(Specsingle.BlueEnd.y);
PublicWindowFlag := 'RePlot';
end;
mrContinue : begin {red end}
Specsingle.RedEnd.X := lochold.X;
Specsingle.RedEnd.y := lochold.y;
edit15.Text := inttostr(Specsingle.RedEnd.X);
Edit16.Text := inttostr(Specsingle.RedEnd.y);
PublicWindowFlag := 'RePlot';
end;
…
end;
if PublicWindowFlag<>'Cancel' then
if PublicWindowFlag='RePlot' then
begin
specsingle.RegenImage;
end
else
showmessage('Single image semaphore error. Debug.');
Imageviewer1.scrollto(scrollhold.X-Imageviewer1.viewportposition.X, scrollhold.y-Imageviewer1.ViewportPosition.Y);
end;
The modal screen sends back either mrContinue or mrOK correctly, and the appropriate case executes. However, edit13, edit14, edit15, and edit16 do not change their content. However, if I click over to Tabitem2 and back to Tabitem1, they DO repaint and DO contain the correct characters, which they could only have gotten from the above code. Conclusion: somehow, the edits aren’t repainting independently, but it’s not clear why.
Got it. The canvas for the imageviewer, the canvas for the bitmap in the imageviewer, and the canvas for the parent form are all in play. One must be sure that the canvas is the right one. As soon as scenes got untangled between imageviewer.bitmap and everything else, the edits worked as one would expect.

Delphi- combobox on toolbar

I am trying to put a combobox on a toolbar in Delphi 2010. The App is a MDI text editor. If I place a combobox on the toolbar and run the app, when I click the combobox, it opens up a new child window and doesn't drop down for a selection. I have tried putting the toolbar and combobox in both a controlbar and a coolbar, both with the same results. In fairness, I have not recreated the toolbar, just moved it to the other controls.
Has anyone seen this before and how do I get around it?
I just tried it again with the same results. Here is the code for the combobox1.
procedure TMainForm.ComboBox1Change(Sender: TObject);
begin
exec_sql(combobox1.Text);
end;
There is no on click for the toolbar and no button currently opens a new child.
The exec_sql looks like this:
procedure TMainForm.exec_sql(MachName:string);
var
sql_str: string;
parm_str: string;
begin
mach.Free;
parm_str := MachName;
sql_str := 'Select * from machines where MACHINE_NAME = :parm_str';
with adoquery1 do
begin
close;
sql.Text := sql_str;
with Parameters.ParamByName('parm_str') do
begin
DataType := ftString;
Value := parm_str;
end;
open;
mach := TMachineData.get_record_data(ADOQuery1);
end;
ShowMessage('Current Machine Is ' + mach.MACHINE_NAME);
end;
I am unable to reproduce your problem. Here are the steps I took to try and do so:
File->New->Other->Delphi Projects->MDI Application
Created a new folder when prompted for the project
Delphi shows a new MDI parent, with a toolbar, some toolbuttons, menu, etc.
Dropped a new TComboBox on the toolbar
Added 'Item 1', 'Item 2', and 'Item 3' to the combobox via the Object Inspector
Ran the application, and clicked the dropdown button on the combobox.
Picked any item from the combobox; it behaved as expected.
Picked a different item from the combobox. It behaved as expected.
Therefore, the problem is not with placing a TComboBox on a TToolBar, and has to be elsewhere in your code, in a location not included in your question.
You'll need to use the debugger, set some breakpoints in various locations, and take a look at the call stack window to see how you got where you're at in the code. You can then set a new breakpoint in one of those earlier calls, repeat the process, and keep doing so until you trace back to the point that's causing your problem.
I just tested debugging in this fashion. I created a FormCreate event in the default CHILDWIN unit, added Dialogs to the implementation uses clause, and added a call to MessageDlg('New child created', mtInformation, [mbOK], 0); in that FormCreate event. I set a breakpoint there, and ran the app, and then clicked on the New toolbar button. When the breakpoint was triggered, the call stack window looked like this (I've highlighted the place that caused the new child window to be created - the line below it is relevant as well):
The problem was the combobox was firing the Form1.OnActivate event which created a new mdi child. OnActivate was set to ActionFirstChildExecute. I was creating a new blank child when the app opened. This had the described undesired effect. I removed the OnActivate and moved the ActionFirstChildExecute to OnShow. The app and combobox then worked as expected. There was nothing in the ActionFirstChildExecute to cause the behavior as shown in the code below. The problem was clicking the combobox fired the Form1.OnActivate event calling the code below.
procedure TMainForm.ActionFirstChildExecute(Sender: TObject);
var
ChildForm: TMDIChild;
begin
Inc (Counter);
ChildForm := TMDIChild.Create (Self);
ChildForm.Caption := ('NONAME' + IntToStr(MDIChildCount));
ChildForm.Show;
(ActiveMDIChild as TMDIChild).FormCreate(Application);
if ParamStr(1) <>'' then open_mru_item(ParamStr(1));
end;

Switch Application.Mainform at runtime and invoke MainformOnTaskBar cause flickering on Windows Taskbar

I am using Delphi 2010 to build a Win32 GUI application running on Windows XP/Vista and Windows 7.
Basically, the Application.MainForm is a read only property and can't be changed at runtime once the first form is created via Application.CreateForm:
begin
Application.Initialize;
Application.MainFormOnTaskbar := True;
Application.CreateForm(TForm1, Form1);
Application.CreateForm(TForm2, Form2);
Application.Run;
end.
The above example will make Form1 as application's mainform. It will show on Windows 7 taskbar's thumbnail preview.
Setting Application.MainFormOnTaskBar to true at runtime allow us to enjoy Windows aero theme features.
I need to switch the application's mainform at runtime. For example, set Form2 as main form. I use following code to make it work:
procedure SetAsMainForm(aForm:TForm);
var
P:Pointer;
begin
Application.MainFormOnTaskBar := False;
try
P := #Application.Mainform;
Pointer(P^) := aForm;
aForm.Show;
finally
Application.MainFormOnTaskBar := True;
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
SetAsMainForm(Form2);
end;
Execute Button1.Click will make Form2 as mainform and update the Windows' taskbar thumbnail preview. However, the Taskbar may flicker on the switching.
My questions are:
Is there any way to away such flickering?
Is it safe to set Application.MainformOnTaskBar := False and set it to True again in runtime?
The main form isn't something you're allowed to change in Delphi. You managed to find a way that appears to work half-way, but it's a hack. Stop doing that.
An application has only one main form, and it's the first form that finishes being created via CreateForm. If you need two radically different behaviors for the main form, then you can try a couple of techniques:
Define your two main forms as frames. Put all your functionality there. Then define a single form that will act as the parent of one of the two frames. Instead of switching the main form, simply destroy the frame and replace it with a new one.
Similar to the frame solution, but use forms instead. Create the forms, and set the Parent property to be the "real" main form. This will probably have a lower initial cost because you already have the two forms, but in my experience, re-parenting forms is more fragile than frames, which were designed for being child controls, so prefer the frame technique.
The flicker on the taskbar comes from one form disappearing and another appearing. With either technique above, there's always just one form, never two, so there's nothing to flicker.
Another option to consider is to set MainFormOnTaskbar=False, then create a hidden MainForm for the lifetime of the process, and have Form1 and Form2 be secondary forms that you create and free dynamically when needed, and give them their own taskbar buttons by overriding the TForms.CreateParams() method, eg:
procedure TForm1.CreateParams(var Params: TCreateParams);
begin
inherited;
Params.ExStyle := Params.ExStyle or WS_EX_APPWINDOW;
Params.WndParent := GetDesktopWindow;
end;

Resources