I am new to Delphi. I would like to know, is there any way to add any Caption or Text inserted/created by the user in a Form to a StringGrid automatically?
For example, using for a simple translator VCL, the Form detects a Button added and the Caption of this new Button automatically appears in the StringGrid to go for the translating process.
unit frmTranslation_u;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Vcl.ExtCtrls,
Vcl.Grids;
type
TfrmTranslation = class(TForm)
pnlPersonalInformation: TPanel;
lblFirstName: TLabel;
lblSureName: TLabel;
edtFirstName: TEdit;
edtSurName: TEdit;
pnlAction: TPanel;
btnEnglish: TButton;
btnAfrikaans: TButton;
btnDisplay: TButton;
bmbReset: TBitBtn;
bmbClose: TBitBtn;
memResult: TMemo;
sgdData: TStringGrid;
procedure btnAfrikaansClick(Sender: TObject);
procedure btnEnglishClick(Sender: TObject);
procedure btnDisplayClick(Sender: TObject);
procedure bmbResetClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure sgdDataClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
frmTranslation: TfrmTranslation;
implementation
{$R *.dfm}
procedure TfrmTranslation.bmbResetClick(Sender: TObject);
begin
// Clear the edit
edtFirstName.Clear;
edtSurName.Clear;
// Clear The memo
memResult.Clear;
// Shift the focus to the first name edit
edtFirstName.SetFocus;
end;
procedure TfrmTranslation.btnAfrikaansClick(Sender: TObject);
begin
lblFirstName.Caption := 'Noemnaam';
lblSureName.Caption := 'Van';
frmTranslation.Caption := 'Vertaling';
lblFirstName.Left := 32;
lblSureName.Left := 80;
btnAfrikaans.Enabled := False ;
btnEnglish.Enabled := true;
end;
procedure TfrmTranslation.btnDisplayClick(Sender: TObject);
begin
// show the full name in the memo
memResult.Lines.Add('You Added '+edtFirstName.Text +' '+ edtSurName.Text);
end;
procedure TfrmTranslation.btnEnglishClick(Sender: TObject);
begin
lblFirstName.Caption := 'First Name';
lblSureName.Caption := 'Surname';
frmTranslation.Caption := 'translation';
lblFirstName.Left := 40 ;
lblSureName.Left := 50 ;
btnEnglish.Enabled := false ;
btnAfrikaans.Enabled := true ;
end;
procedure TfrmTranslation.FormCreate(Sender: TObject);
var
i, iCol, iRow : integer ;
begin
sgdData.Cells[0,0] := 'NAME';
sgdData.Cells[1,0] := 'TYPE';
sgdData.Cells[2,0] := 'Id_LAN';
sgdData.Cells[3,0] := 'VALUE';
end;
procedure TfrmTranslation.sgdDataClick(Sender: TObject);
begin
end;
end.
Related
i created dynamic tabsheet in page control , and then each page needs to host a frame with several component like Tedit and etc . these Tedit in my frame host data from an ini file .
if i do my tabsheet static it works ! but i need to do my tabsheet dynamic ... i tried to create a frame but when i put in my loop i get error
how can i do it ?
thanks !
unit DlgXRechnung;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.ExtCtrls, Xml.xmldom,
Xml.XMLIntf, Vcl.Buttons, Xml.XMLDoc, IniFiles, Vcl.ComCtrls;
type
TDlg_XRechnung = class(TForm)
Panel1: TPanel;
Panel2: TPanel;
Panel3: TPanel;
Panel4: TPanel;
X_Rechnung: TXMLDocument;
Memo_XML: TMemo;
Btn_Laden: TBitBtn;
OpenDialog_Datei: TOpenDialog;
Panel5: TPanel;
Label1: TLabel;
Edit_LeitwegeID: TLabeledEdit;
Edit_Bestellnummer: TLabeledEdit;
Edit_Projektreferenz: TLabeledEdit;
Edit_Vertragsnummer: TLabeledEdit;
Edit_Rechnungsnummer: TLabeledEdit;
Edit_Rechnungsdatum: TDateTimePicker;
Label2: TLabel;
Label3: TLabel;
Edit_Leistungsdatum: TDateTimePicker;
Edit_Bemerkung: TMemo;
Label4: TLabel;
Btn_XML_erstellen: TBitBtn;
Btn_Close: TBitBtn;
Panel6: TPanel;
Label5: TLabel;
Edit_Rechnungsersteller_Name: TLabeledEdit;
Edit_Rechnungsersteller_Adresse: TLabeledEdit;
Edit_Rechnungsersteller_PLZ: TLabeledEdit;
Edit_Rechnungsersteller_UST_ID: TLabeledEdit;
Edit_Rechnungsersteller_Ort: TLabeledEdit;
Edit_Rechnungsersteller_Land: TLabeledEdit;
Edit_Rechnungsersteller_Firmenbuch: TLabeledEdit;
Edit_Rechnungsersteller_Steuerart: TLabeledEdit;
GroupBox1: TGroupBox;
Edit_Waehrung_Rechnung: TLabeledEdit;
Edit_Waehrung_UST: TLabeledEdit;
Panel7: TPanel;
Label6: TLabel;
Edit_Rechnungsempfänger_Name: TLabeledEdit;
Edit_Rechnungsempfänger_Adresse: TLabeledEdit;
Edit_Rechnungsempfänger_PLZ: TLabeledEdit;
LabeledEdit4: TLabeledEdit;
Edit_Rechnungsempfänger_Ort: TLabeledEdit;
Edit_Rechnungsempfänger_Land: TLabeledEdit;
LabeledEdit7: TLabeledEdit;
LabeledEdit8: TLabeledEdit;
PC_Positionen: TPageControl;
procedure Btn_LadenClick(Sender: TObject);
procedure FormShow(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure Btn_XML_erstellenClick(Sender: TObject);
procedure Btn_CloseClick(Sender: TObject);
procedure PC_PositionenChange(Sender: TObject);
private
INIDateiname : string;
INIDatei : TIniFile;
PDFDatei : string;
XRechnungDatei : string;
Version : integer;
DebugMode : integer;
AnzahlPositinen : integer;
procedure INIDatei_einlesen;
procedure XML_erstellen;
{ Private-Deklarationen }
public
{ Public-Deklarationen }
end;
var
Dlg_XRechnung: TDlg_XRechnung;
implementation
{$R *.dfm}
// -----------------------------------------------------------------------------
procedure TDlg_XRechnung.Btn_CloseClick(Sender: TObject);
begin
Close;
end;
// -----------------------------------------------------------------------------
procedure TDlg_XRechnung.Btn_LadenClick(Sender: TObject);
begin
if OpenDialog_Datei.Execute then
begin
INIDateiname := OpenDialog_Datei.FileName;
end;
if Trim(INIDateiname) <> '' then INIDatei_einlesen;
end;
// -----------------------------------------------------------------------------
procedure TDlg_XRechnung.Btn_XML_erstellenClick(Sender: TObject);
begin
XML_erstellen;
end;
// -----------------------------------------------------------------------------
procedure TDlg_XRechnung.FormCreate(Sender: TObject);
begin
INIDateiname := '';
end;
// -----------------------------------------------------------------------------
procedure TDlg_XRechnung.FormShow(Sender: TObject);
begin
if Trim(ParamStr(1)) <> '' then
begin
INIDateiname := ParamStr(1);
INIDatei_einlesen;
end;
end;
// -----------------------------------------------------------------------------
procedure TDlg_XRechnung.INIDatei_einlesen;
var NeueSeite : TTabSheet;
i,l: Integer;
begin
try
INIDatei := TIniFile.Create(INIDateiname);
Version := INIDatei.ReadInteger('INI','Version', 1);
DebugMode := INIDatei.ReadInteger('INI','DebugMode', 0);
PDFDatei := INIDatei.ReadString('PDF','PDFName', '');
XRechnungDatei := INIDatei.ReadString('PDF','XInvoice', '');
Edit_LeitwegeID.Text := INIDatei.ReadString('InvData','BT-10', '');
Edit_Bestellnummer.Text := INIDatei.ReadString('InvData','BT-13', '');
Edit_Projektreferenz.Text := INIDatei.ReadString('InvData','BT-11', '');
Edit_Vertragsnummer.Text := INIDatei.ReadString('InvData','BT-12', '');
Edit_Rechnungsnummer.Text := INIDatei.ReadString('InvData','BT-1', '');
Edit_Rechnungsdatum.Date := INIDatei.ReadDate('InvData','BT-2', now);
Edit_Leistungsdatum.Date := INIDatei.ReadDate('InvData','BT-9', now);
Edit_Bemerkung.Text := INIDatei.ReadString('InvData','BT-22', '');
Edit_Rechnungsersteller_Name.Text := INIDatei.ReadString('InvErst','BT-27', '');
Edit_Rechnungsersteller_UST_ID.Text := INIDatei.ReadString('InvErst','BT-31', '');
Edit_Rechnungsersteller_Adresse.Text := INIDatei.ReadString('InvErst','BT-35', '') + INIDatei.ReadString('InvErst','BT-36', '');
Edit_Rechnungsersteller_PLZ.Text := INIDatei.ReadString('InvErst','BT-38', '');
Edit_Rechnungsersteller_Ort.Text := INIDatei.ReadString('InvErst','BT-37', '');
Edit_Rechnungsersteller_Land.Text := INIDatei.ReadString('InvErst','BT-40', '');
Edit_Rechnungsempfänger_Name.Text := INIDatei.ReadString('InvEmp','BT-44','');
Edit_Rechnungsempfänger_Adresse.Text := INIDatei.ReadString('InvEmp','BT-50', '') + INIDatei.ReadString('InvEmp','BT-51', '');
Edit_Rechnungsempfänger_PLZ.Text := INIDatei.ReadString('InvEmp','BT-53', '');
Edit_Rechnungsempfänger_Ort.Text := INIDatei.ReadString('InvEmp','BT-52', '');
Edit_Rechnungsempfänger_Land.Text := INIDatei.ReadString('InvEmp','BT-55', '');
AnzahlPositinen := INIDatei.ReadInteger('POS','AnzPos', 1);
for i := 1 to AnzahlPositinen do
begin
NeueSeite := TTabSheet.Create(PC_Positionen);
NeueSeite.PageControl := PC_Positionen;
NeueSeite.Caption := 'Position ' + IntToStr(i);
end;
finally
INIDatei.Free;
end;
end;
First design a TFrame using the IDE (Much like you design a TForm). Add all the items such as TEdit that your need. Add the unit of the frame to the uses clause of the form's unit. When creating the frame, you need to specify an owner. You can use the same as the TabSheet you created. You should either clear the name property or set a suitable unique name for each.
Then inside the loop you use to create the TabSheet, create a new instance of the frame, assign his parent property to the TabSheet just created, then read all items values from the INI file.
By the way, read again my answer (https://stackoverflow.com/a/66943453/189103) to your previous question. It already contained all the information required.
I would like to create array of all listboxes and access them. I tried to do it using pointers, however my program crashes during runtime with error access violation at address...
type ControlsCount = 4;
type PLB = ^TListBox;
var listBoxes: array of PLB;
procedure TExport.FormCreate(Sender: TObject);
var i: word; n: integer;
begin
with FormExport do
begin
ListRowHeight := List_sex.height;
List_sex.items.add('---');
List_sex.items.add('Man');
List_sex.items.add('Woman');
List_sex.onmousemove:=ListMouseMove;
setLength(listBoxes, ControlsCount);
n := -1;
for i := 0 to ControlsCount - 1 do
if Components[i] is TWinControl then
if TWinControl(Components[i]).CanFocus then
begin
inc(n);
// mistake here: should be listBoxes[n] not listBoxes[i]
listBoxes[i] := PLB(Components[i]);
end;
realControlsCount := n;
end;
end;
procedure TExport.resetListBoxes;
var i: word;
begin
for i := 0 to realControlsCount-1 do
begin
TListBox(listBoxes[i]^).height := ListRowHeight;
end;
end;
So here I try to set the pointer of the control to listBoxes[i].
listBoxes[i] := PLB(Components[i]);
and here I try to access it:
TListBox(listBoxes[i]^).height := ListRowHeight;
this is the line where it generates error.
What am I doing wrong?
Just remove all pointer stuff and check whether control is really TListBox. Also you misused ControlsCount while accessed another list Components[i]
var listBoxes: array of TListBox;
...
for i := 0 to ControlsCount - 1 do
if Controls[i] is TListBox then //note strict constraint
listBoxes[n] := Controls[i] as TListBox;
...
listBoxes[i].height := ListRowHeight;
Aslso consider using TList<TListBox> instead of array
Regarding the answere MBo gave this is how I would use it with a TList
unit Unit1;
interface
uses
System.SysUtils, System.Types, System.UITypes, System.Classes, System.Variants,
FMX.Types, FMX.Controls, FMX.Forms, FMX.Graphics, FMX.Dialogs, Generics.Collections,
FMX.Layouts, FMX.ListBox, FMX.Controls.Presentation, FMX.StdCtrls;
type
TForm1 = class(TForm)
lst1: TListBox;
lst2: TListBox;
lst3: TListBox;
btn1: TButton;
pnl1: TPanel;
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
procedure btn1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
listboxes: TList<TListBox>; // Define list that will contain listboxes
implementation
{$R *.fmx}
procedure TForm1.btn1Click(Sender: TObject);
var
lstbx: TListBox;
begin
for lstbx in listboxes do
ShowMessage(lstbx.Height.ToString); Loop through all listboxes and show their height
end;
procedure TForm1.FormCreate(Sender: TObject);
var
control: TControl;
begin
listboxes := TList<TListBox>.Create; // Create the TList
for control in pnl1.Controls do
begin
if control is TListBox then
listboxes.Add(control as TListBox); // Loop through all listboxes on a panel and add then to the list if they are a listbox
end;
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
listboxes.Free; // Free the list
end;
end.
I have one Delphi 10.0 Seattle project to FTP some files to a server.
I will do the following:
On Button1 OnClick event, I will calculate something and will make one text file. Edit1 will hold the file name.
On Button2 OnClick event, the last 4 characters of the file name will be deleted. The file will be renamed with the new name. Edit2 will hold the new name and it will be uploaded to one server.
During the file uploading, no button click will work and the Form cannot be closed. I have used one Boolean variable FileToBeTranferred. It is false at Form creation.
I have written the following code:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Math;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
var
FileToBeTranferred: boolean;
procedure TForm1.Button1Click(Sender: TObject);
begin
if FileToBeTranferred = false then
begin
//Do some calculation
//Edit1.Text := Output File Name
FileToBeTranferred := true;
end
else
begin
Button1.Click(nil);
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if FileToBeTranferred = true then
begin
Edit2.Text := delete(Edit1.Text, (length(Edit1.Text)-4), 4);
//Upload to Server
Button2.Click(self);
end
else
begin
//Upload finished
FileToBeTranferred := false;
Button2.Click(nil);
end;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
if FileToBeTranferred = true then CanClose := false
else CanClose := true;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FileToBeTranferred := false;
end;
end.
I am unable to do anything. I am getting too many errors. The errors are as follows:
[dcc32 Error] Unit1.pas(44): E2197 Constant object cannot be passed as var parameter in Edit2.Text := delete(Edit1.Text, (length(Edit1.Text)-4), 4); - for deleting last 4 characters for file rename.
[dcc32 Error] Unit1.pas(47): E2034 Too many actual parameters in Button2.Click(nil); - as FTP is in progress so no more modification to the file is allowed. Button1.Click will not perform anything.
[dcc32 Error] Unit1.pas(47): E2034 Too many actual parameters in Button2.Click(self);- as FTP progress completed so the file is ready to be appended. Button2.Click will not perform its usual work.
What is the solution to this?
The code you have shown is just all kinds of wrong. Not just the syntax errors, but also logic errors. Even if the code compiled, your Button1 click handler will get stuck in an endless recursive loop if FileToBeTranferred is true, and your Button2 click handler will get stuck in an endless recursive loop regardless of FileToBeTranferred.
Try something more like this instead:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Math;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
FileToBeTranferred: boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
if not FileToBeTranferred then
begin
//Do some calculation
//Edit1.Text := Output File Name
FileToBeTranferred := True;
end;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
if FileToBeTranferred then
begin
Edit2.Text := Copy(Edit1.Text, 1, Edit1.GetTextLen-4);
//Upload to Server, wait for completion
FileToBeTranferred := False;
end;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := not FileToBeTranferred;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FileToBeTranferred := False;
end;
end.
That being said, you might consider a different approach. For instance, one that doesn't require the FileToBeTranferred Boolean at all:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Math;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
Button1.Enabled := False;
//Do some calculation
//Edit1.Text := Output File Name
Button2.Enabled := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Button2.Enabled := False;
Edit2.Text := Copy(Edit1.Text, 1, Edit1.GetTextLen-4);
//Upload to Server
Button1.Enabled := True;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := Button1.Enabled;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Enabled := True;
Button2.Enabled := False;
end;
end.
Or, you could combine the two approaches, by enabling/disabling the TButton objects based on the current value of FileToBeTranferred at any given moment.
You can override the Form's virtual UpdateActions() method:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Math;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
protected
procedure UpdateActions; override;
private
{ Private declarations }
FileToBeTranferred: boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
//Do some calculation
//Edit1.Text := Output File Name
FileToBeTranferred := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Edit2.Text := Copy(Edit1.Text, 1, Edit1.GetTextLen-4);
//Upload to Server, wait for completion
FileToBeTranferred := False;
end;
procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
CanClose := not FileToBeTranferred;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
FileToBeTranferred := False;
end;
procedure TForm1.UpdateActions;
begin
inherited;
Button1.Enabled := not FileToBeTranferred;
Button2.Enabled := FileToBeTranferred;
end;
end.
Or, you can drop a TActionList on the Form and assign a TAction to each TButton, and then enable/disable the TAction objects in their OnUpdate events:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Math, Vcl.ActnList;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Button1: TButton;
Button2: TButton;
ActionList1: TActionList;
Action1: TAction;
Action2: TAction;
procedure Action1Update(Sender: TObject);
procedure Action2Update(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
FileToBeTranferred : Boolean;
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Action1Update(Sender: TObject);
begin
Action1.Enabled := not FileToBeTranferred;
end;
procedure TForm1.Action2Update(Sender: TObject);
begin
Action2.Enabled := FileToBeTranferred;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
//Do some calculation
//Edit1.Text := Output File Name
FileToBeTranferred := True;
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
Edit2.Text := Copy(Edit1.Text, 1, Edit1.GetTextLen-4);
//Upload to Server, wait for completion
FileToBeTranferred := False;
end;
end.
I am having one Delphi XE2 Project with 2 BitBtns and 2 TEdits. Both of the TEdits contain secret data, so I have hidden the contents. My requirement is copy the contents of TEdit1 to clipboard after BitBtn1 Click and similarly for TEdit2. Here is my sample code:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, Vcl.Buttons, Clipbrd;
type
TMainForm = class(TForm)
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
Label4: TLabel;
Label5: TLabel;
Label6: TLabel;
Label7: TLabel;
Label8: TLabel;
Label9: TLabel;
Label10: TLabel;
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Edit4: TEdit;
Edit5: TEdit;
BitBtn1: TBitBtn;
BitBtn2: TBitBtn;
BitBtn3: TBitBtn;
BitBtn4: TBitBtn;
BitBtn5: TBitBtn;
procedure BitBtn1Click(Sender: TObject);
procedure BitBtn2Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
MainForm: TMainForm;
implementation
{$R *.dfm}
procedure TMainForm.BitBtn1Click(Sender: TObject);
begin
Edit1.PasswordChar := #0;
Clipboard.Clear;
Edit1.CopyToClipboard;
Edit1.PasswordChar := '*';
end;
procedure TMainForm.BitBtn2Click(Sender: TObject);
begin
Edit2.PasswordChar := #0;
Clipboard.Clear;
Edit2.CopyToClipboard;
Edit2.PasswordChar := '*';
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
Edit1.Text := 'User Name';
Edit1.PasswordChar := '*';
Edit2.Text := 'Password';
Edit2.PasswordChar := '*';
end;
end.
But the problem is as follows:
1. If the PasswordChar := '*'; is set, the contents can not be copied to clipboard.
2. If I compile my sample code, TEdit1 Contents is copied to Clipboard after clicking BitBtn1 but TEdit2 Contents is not copied to Clipboard after clicking BitBtn2, though the first operation (Clipboard.Clear;) performs successfully.
3. If I double click on TEdit2 then click on BitBtn2 now TEdit2 Contents is copied to Clipboard.
I don't know why it is happening so?
If you want to place text in the clipboard, do so like this:
Clipboard.AsText := SecretEdit.Text;
or
Clipboard.AsText := SecretEdit.SelText;
The reason that the default behaviour of the control is to block copying to the clipboard is in case you walk away from your machine without realising that you left a password in plain text on your clipboard for a malicious attacker to steal. You should consider whether or not you want to take that risk with your application's users.
If no text is selected, CopyToClipboard does nothing.
Use this :
procedure TMainForm.BitBtn2Click(Sender: TObject);
begin
Edit2.SetFocus;
Edit2.PasswordChar := #0;
Clipboard.Clear;
Edit2.CopyToClipboard;
Edit2.PasswordChar := '*';
end;
procedure TMainForm.BitBtn1Click(Sender: TObject);
begin
Edit1.SetFocus;
Edit1.PasswordChar := #0;
Clipboard.Clear;
Edit1.CopyToClipboard;
Edit1.PasswordChar := '*';
end;
In order to understand interfaces I've realized a small application with a form, a data module with a simple database.
here is the form
The data module contains only a connection, a table and a TDataSource component.
The interface unit is this:
unit databaseInterface;
interface
uses
MSAccess;
type
IDBTest = interface
['{5B8CF4FF-66F7-402D-8E18-0159CB22F805}']
procedure SetTable(table: TMSTable);
function SetPriorRecord: Boolean;
function SetNextRecord: Boolean;
end;
implementation
end.
and it's implementation is this:
unit databaseImplementation;
interface
uses
databaseInterface, database, MSAccess;
type
TDBTest = class(TInterfacedObject, IDBTest)
protected
DBTable: TMSTable;
FbtnPriorStatus: Boolean;
procedure SetTable(Table: TMSTable);
function SetPriorRecord: Boolean;
function SetNextRecord: Boolean;
public
property Table: TMSTable read DBTable write SetTable;
end;
implementation
{ TDBTest }
procedure TDBTest.SetTable(Table: TMSTable);
begin
if DBTable <> Table then begin
DBTable := Table;
DBTable.Open;
end;
end;
function TDBTest.SetPriorRecord: Boolean;
begin
if not DBTable.Bof then begin
DBTable.Prior;
Result := DBTable.Bof;
end else
Result := True;
end;
function TDBTest.SetNextRecord: Boolean;
begin
if not DBTable.Eof then begin
DBTable.Next;
Result := DBTable.Eof;
end else
Result := True;
end;
end.
Now, this is the question. The code of my form is as below:
unit main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.ExtCtrls, databaseInterface, databaseImplementation, JvExMask,
JvToolEdit, JvMaskEdit, JvCheckedMaskEdit, JvDatePickerEdit,
Vcl.StdCtrls, Vcl.Mask, Vcl.DBCtrls, JvDBDatePickerEdit, JvExControls,
JvButton, JvTransparentButton, database;
type
TfrmMain = class(TForm)
pnlCommands: TPanel;
pnlData: TPanel;
pnlMessages: TPanel;
bvlIcons: TBevel;
bvlNavigation: TBevel;
lblId: TLabel;
lblFirstName: TLabel;
lblLastName: TLabel;
lblBirthday: TLabel;
edtId: TDBEdit;
edtFirstName: TDBEdit;
edtLastName: TDBEdit;
dtpBirthday: TJvDBDatePickerEdit;
btnPrior: TJvTransparentButton;
btnNext: TJvTransparentButton;
procedure btnNextClick(Sender: TObject);
procedure btnPriorClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
DBTest: IDBTest;
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure TfrmMain.FormCreate(Sender: TObject);
begin
DBTest := TDBTest.Create;
end;
procedure TfrmMain.FormActivate(Sender: TObject);
begin
DBTest.SetTable(dmAuthors.tblAuthors);
end;
procedure TfrmMain.btnPriorClick(Sender: TObject);
begin
btnPrior.Enabled := not DBTest.SetPriorRecord;
btnNext.Enabled := True;
end;
procedure TfrmMain.btnNextClick(Sender: TObject);
begin
btnNext.Enabled := not DBTest.SetNextRecord;
btnPrior.Enabled := True;
end;
end.
So I call the methods SetPriorRecord and SetNextRecord when the user click over the related button and then, accordingly with the status of the table (BOF or EOF), I disable or enable buttons.
I wonder if there is a way to set buttons status via interface, decoupling this operation from the form; for example binding buttons in any way or something else, but I don't know how to do it, if it is possible!
I hope I was clear in my explication of the problem.
The existing interface is not sufficient. You need to pass in some means of letting the client know the state of the table, but without exposing the TDataSet's detailed logic (preferably). A callback to an event handler would work; a way to trigger TAction would work; as would an anonymous method. You basically need to return a flag of some kind signifying BOF, EOF, or somewhere in between; possibly also a record# and record count.
I've modified the application interface in this way:
unit databaseInterface;
interface
uses
MSAccess;
type
IDBTest = interface
['{5B8CF4FF-66F7-402D-8E18-0159CB22F805}']
procedure SetTable(table: TMSTable);
procedure SetPriorRecord;
procedure SetNextRecord;
function GetIsBof: Boolean;
function GetIsEof: Boolean;
property IsBof: Boolean read GetIsBof;
property IsEof: Boolean read GetIsEof;
end;
implementation
end.
and this is the interface implementation:
unit databaseImplementation;
interface
uses
databaseInterface, database, MSAccess;
type
TDBTest = class(TInterfacedObject, IDBTest)
protected
DBTable: TMSTable;
FIsBof: Boolean;
FIsEof: Boolean;
procedure SetTable(Table: TMSTable);
procedure SetPriorRecord;
procedure SetNextRecord;
function GetIsBof: Boolean;
function GetIsEof: Boolean;
procedure SetCursorStatus;
public
property Table: TMSTable read DBTable write SetTable;
property IsBof: Boolean read GetIsBof;
property IsEof: Boolean read GetIsEof;
end;
implementation
{ TDBTest }
procedure TDBTest.SetTable(Table: TMSTable);
begin
if DBTable <> Table then begin
DBTable := Table;
DBTable.Open;
end;
end;
procedure TDBTest.SetPriorRecord;
begin
try
DBTable.Prior;
finally
SetCursorStatus;
end;
end;
procedure TDBTest.SetNextRecord;
begin
try
DBTable.Next;
finally
SetCursorStatus;
end;
end;
procedure TDBTest.SetCursorStatus;
begin
FIsBof := DBTable.Bof;
FIsEof := DBTable.Eof;
end;
function TDBTest.GetIsBof: Boolean;
begin
Result := FIsBof;
end;
function TDBTest.GetIsEof: Boolean;
begin
Result := FIsEof;
end;
end.
So the form code become this:
unit main;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants,
System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs,
Vcl.ExtCtrls, Vcl.StdCtrls, Vcl.Mask, Vcl.DBCtrls, JvExMask, JvToolEdit,
JvMaskEdit, JvCheckedMaskEdit, JvDatePickerEdit, JvDBDatePickerEdit,
JvExControls, JvButton, JvTransparentButton, database, databaseInterface,
databaseImplementation;
type
TfrmMain = class(TForm)
pnlCommands: TPanel;
pnlData: TPanel;
pnlMessages: TPanel;
bvlIcons: TBevel;
bvlNavigation: TBevel;
lblId: TLabel;
lblFirstName: TLabel;
lblLastName: TLabel;
lblBirthday: TLabel;
edtId: TDBEdit;
edtFirstName: TDBEdit;
edtLastName: TDBEdit;
dtpBirthday: TJvDBDatePickerEdit;
btnPrior: TJvTransparentButton;
btnNext: TJvTransparentButton;
procedure btnNextClick(Sender: TObject);
procedure btnPriorClick(Sender: TObject);
procedure FormCreate(Sender: TObject);
procedure FormActivate(Sender: TObject);
private
DBTest: IDBTest;
procedure SetNavButtonsStatus;
public
{ Public declarations }
end;
var
frmMain: TfrmMain;
implementation
{$R *.dfm}
procedure TfrmMain.FormCreate(Sender: TObject);
begin
DBTest := TDBTest.Create;
end;
procedure TfrmMain.FormActivate(Sender: TObject);
begin
DBTest.SetTable(dmAuthors.tblAuthors);
end;
{ Begin table navigation ----------------------------------------------------- }
procedure TfrmMain.btnPriorClick(Sender: TObject);
begin
DBTest.SetPriorRecord;
SetNavButtonsStatus;
end;
procedure TfrmMain.btnNextClick(Sender: TObject);
begin
DBTest.SetNextRecord;
SetNavButtonsStatus;
end;
procedure TfrmMain.SetNavButtonsStatus;
begin
btnPrior.Enabled := not DBTest.IsBof;
btnNext.Enabled := not DBTest.IsEof
end;
{ End table navigation ------------------------------------------------------- }
end.
Now I think buttons are decoupled, but I'm not sure abot the solution I've found. Can It be good?