I tried like this. First and Last names are added but phone number is not (Delphi 11, FMX)
procedure TForm1.ActionAddContactExecute(Sender: TObject);
var
Contact: TAddressBookContact;
Phones: TContactPhones;
eMails: TContactEmails;
Photo: TBitmapSurface;
begin
Contact := AddressBook1.CreateContact(FDefaultSource);
try
try
Contact.FirstName := edtFirstName.Text;
Contact.LastName := edtLastName.Text;
Phones := TContactPhones.Create;
try
Phones.AddPhone(TContactPhone.TLabelKind.Mobile, '767867679678');
Contact.Phones := Phones;
finally
Phones.Free;
end;
if not Image1.Bitmap.Size.IsZero then
begin
Photo := TBitmapSurface.Create;
try
Photo.Assign(Image1.Bitmap);
Contact.Photo := Photo;
Image1.Bitmap.SetSize(0, 0);
finally
Photo.Free;
end;
end;
// Add the work mail
eMails := TContactEmails.Create;
try
eMails.AddEmail(TContactEmail.TLabelKind.Work, edtWorkMail.Text);
Contact.eMails := eMails;
finally
eMails.Free;
end;
// Save a newly created contact to Address Book
AddressBook1.SaveContact(Contact);
except
on E: EAddressBookException do
ShowMessage('Cannot create the contact.' + E.Message);
end;
// Add the contact to the selected group, if any
try
if InRange(ComboBox1.ItemIndex, 0, FGroups.Count - 1) then
AddressBook1.AddContactIntoGroup
(FGroups.Items[ComboBox1.ItemIndex], Contact);
except
on E: EAddressBookException do
ShowMessage('Cannot add the newly created contact to group.' + E.Message);
end;
ListViewContacts.BeginUpdate;
try
AddListViewItem(Contact);
finally
ListViewContacts.EndUpdate;
end;
TabControl1.ActiveTab := TabItemContacts;
finally
Contact.Free;
end;
// Clear the Add Contact Form
ClearAddContactForm;
end;
Related
Delphi 10.3.
Cross platform application.
Android & IOS.
I am using the TAddressbook component and the following code adapted from the Delphi code examples.
I am able to get the names and photos but cannot workout the syntax for the phone numbers.
The code fills the Listview with firstname / surname & image but the Contact.Phones seems to be an array.
I found this in the documentation
Phones.AddPhone(TContactPhone.TLabelKind.Mobile, '+33-6-46-51-3531');
So I need somthing like this
Phones.Extract(TContactPhone.TLabelKind.Mobile); // Does not work.
procedure TformMain.FillContactList(Source: TAddressBookSource);
var
I: Integer;
Contacts: TAddressBookContacts;
begin
Contacts := TAddressBookContacts.Create;
try
AddressBook1.AllContacts(Source, Contacts);
ListViewContacts.BeginUpdate;
try
ListViewContacts.Items.Clear;
for I := 0 to Contacts.Count - 1 do
AddListViewItem(Contacts.Items[I]);
//AddListViewItem(Contacts.Items[I].Phones[0].Number)
finally
ListViewContacts.EndUpdate;
end;
finally
Contacts.Free;
end;
end;
procedure TformMain.AddListViewItem(Contact: TAddressBookContact);
var
ListViewItem: TListViewItem;
eMails: TContactEmails;
phones: TContactPhones;
c : TAddressBookContact;
begin
phones := Contact.Phones;
if Contact.DisplayName.Length > 0 then
begin
ListViewItem := ListViewContacts.Items.Add;
try
// ListViewItem.Data['Text2'] := Contact.Phones.Extract(TContactPhone.SupportedLabelKinds('Mobile'));
// ListViewItem.Data['Text2'] := Phones.ExtractItem.LabelText. (TContactPhone.TLabelKind.Mobile, '+33-6-46-51-3531');
//ListViewItem.Data['Text2'] := Phones.ex ExtractItem AddPhone(TContactPhone.TLabelKind.Mobile, '+33-6-46-51-3531');
ListViewItem.Data['Text1'] := Contact.DisplayName;
ListViewItem.Data['Text2'] := '07446944654'; // from sample eMails.AddEmail(TContactEmail.TLabelKind.Work, edtWorkMail.Text);
// TLabelKind = (Custom, Home, Mobile, Work, iPhone, FaxWork, FaxHome, FaxOther, Pager, Other, Callback, Car, CompanyMain,ISDN, Main, Radio, Telex, TTYTDD, WorkMobile, WorkPager, Assistant);
// ListViewItem.Data['Text2'] := c.Phones.First.LabelKind.Mobile.t;// Phones.IndexOf('Mobile');
// ListViewItem.Data['Text2'] := Contact.Phones.ExtractItem('Mobile');
// ListViewItem.Data['Text2'] := Contact.Phones.Extract.LabelKind('Mobile');
// ListViewItem.Data['Text2'] := Contact.Phones.ExtractAt.LabelKind.Mobile;//('Mobile');
// phones := Contact.Phones.ExtractItem.LabelKind.Mobile; //.TLabelKind.Mobile;// .Phones.Extract(Mobile);
// ListViewItem.Data['Text2'] := phones.ExtractAt.LabelKind.Mobile;// Extract.LabelKind.Mobile;// ExtractItem.LabelKind.Mobile;// Contact.Phones.Extract('Mobile').ToString;// Phones.Extract.TLabelKind.;
// ListViewItem.Data['Text2'] := phones.Extract.LabelKind.Mobile;// Contact.Phones Items[0].TLabelKind. .Number;// .Items[0];
ListViewItem.Data['Image3'] := Contact.PhotoThumbnail;
ListViewItem.Tag := Contact.ID;
finally
ListViewItem.Free;
end;
end;
end;
I am trying to get a list of all outlook contacts using delphi.
I found a couple of examples, all seemed to be outdated or flawed.
Currently I have the following code, but when I excecute the command at runtime I get the below error:
Code:
procedure Tinvite_friends.BitBtn2Click(Sender: TObject);
const
olFolderContacts = $0000000A;
var
outlook, NameSpace, Contacts, Contact: OleVariant;
i: Integer;
begin
Try
outlook:=GetActiveOleObject('Outlook.Application');
Except
outlook:=CreateOleObject('Outlook.Application');
End;
NameSpace := outlook.GetNameSpace('MAPI');
Contacts := NameSpace.GetDefaultFolder(olFolderContacts);
for i := 1 to Contacts.Items.Count do
begin
Contact := Contacts.Items.Item(i);
{now you can read any property of contact. For example, full name and
email address}
ShowMessage(Contact.FullName + ' <' + Contact.Email1Address + '>');
end;
Outlook := UnAssigned;
end;
Error Message:
Project appname.exe raised exception class EOLeSysError with message 'Invalid class string'.
The project does not get passed the below code before throwing the error.
Try
outlook:=GetActiveOleObject('Outlook.Application');
Except
outlook:=CreateOleObject('Outlook.Application');
End;
Is there an effective way to get a list of all contacts from outlook imported to a memo for example?
Maybe it's case sensitivity? I test for outlook.application:
const
scxOutlookApp = 'outlook.application';
scxNameSpace = 'MAPI';
function TDataModuleSyncOutlook.ConnectToOutlook(AUserSMTP: String = ''): Boolean;
var
lRecipient,
lVar : OleVariant;
lLog,
lLoginSMTP: String;
begin
Result := false;
FWasCreated := False; // Breakpoint 'Ignore subsequent exceptions'
try
FOutlookApp := GetActiveOleObject(scxOutlookApp); // Application object
Result := True;
except
try
FOutlookApp := CreateOleObject(scxOutlookApp);
FWasCreated := True;
Result := True;
except
on E:Exception do TSyncLogger.LogError(E.Message);
end;
end;
if Result then // Breakpoint 'Handle subsequent exceptions'
begin
FNameSpace := FOutlookApp.GetNamespace(scxNameSpace);
// Solution from http://stackoverflow.com/questions/18053110/retrieve-outlook-logged-in-user-smtp-address-after-connecting-through-ole/
lLog := Format('Connected to Outlook; Application.DefaultProfilename: %s, Application.Name: %s, Application.Version: %s, NameSpace.CurrentProfileName: %s, NameSpace.ExchangeMailboxServerName: %s, NameSpace.Type: %s',
[FOutlookApp.DefaultProfileName,
FOutlookApp.Name,
FOutlookApp.Version,
FNameSpace.CurrentProfileName,
FNameSpace.ExchangeMailboxServerName,
FNameSpace.Type]);
TSyncLogger.LogDetail(lLog);
lVar := FOutlookApp.Session; // NameSpace object for the current session
if not VarIsClear(lVar) then lVar := lVar.CurrentUser; // Recipient object for the currently logged-on user
if not VarIsClear(lVar) then lVar := lVar.AddressEntry; // AddressEntry object for the recipient
if not VarIsClear(lVar) then lVar := lVar.GetExchangeUser; // Returns an ExchangeUser object that represents the AddressEntry
if not VarIsClear(lVar) then lVar := lVar.PrimarySmtpAddress; // String representing the SMTP address for the ExchangeUser
if not VarIsClear(lVar) then
begin
lLoginSMTP := FOutlookApp.Session.CurrentUser.AddressEntry.GetExchangeUser.PrimarySmtpAddress;
TSyncLogger.LogDetail('Primary Exchange SMTP address detected as: ' + lLoginSMTP);
end
else
begin
TSyncLogger.LogError(sErrNoExchangeAccount);
DisConnectFromOutlook;
Exit;
end;
if LowerCase(AUserSMTP) <> Lowercase(lLoginSMTP) then
begin // Open shared calendar if it's a different user
lRecipient := FNameSpace.CreateRecipient(AUserSMTP);
try
FCalendarFolder := FNameSpace.GetSharedDefaultFolder(lRecipient, olFolderCalendar);
lLog := Format('Logging in as different user (%s), created recipient for %s, GetSharedDefaultFolder folder path = %s',[AUserSMTP,lRecipient.Address,FCalendarFolder.FolderPath]);
TSyncLogger.LogAlways(lLog);
except
on E:Exception do
begin
Result := false;
TSyncLogger.LogError(Format(sErrOpenGedeeldeAgenda,[AUserSMTP]));
end;
end;
end
else // ... otherwise open default calendar folder
begin
FCalendarFolder := FNameSpace.GetDefaultFolder(olFolderCalendar);
TSyncLogger.LogDetail('Opened default calendar folder, folder path = ' + FCalendarFolder.FolderPath);
end;
end;
FOleInitialized := Result;
if Result then TSyncLogger.LogDetail('Connected to Outlook') else TSyncLogger.LogAlways('Connection to Outlook failed');
end;
Notes:
1. This opens the default calendar for any user, but you would not need to go that far (besides, your issue is earlier)
2. TSyncLogger is our logging handler
3. FOleInitialized, FWasCreated: Boolean; FOutlookApp, FNameSpace, FCalendarFolder: OleVariant; are some private properties we maintain
4. Essential to this code is that it first does a GetActiveOleObject to catch a running instance of Outlook; if that fails it does a CreateOleObject
I tried this code to save some fields and an image.
I use MySQL and zzeos for connectinf to the database.
How to fix this code ?
procedure Tfbiodata.btnSaveClick(Sender: TObject);
var
gambar : TMemoryStream;
begin
if (edtnis.Text='') or (edtname.Text='') or (cmbjk.Text='') or (edtempat.Text='') or (edtgl.Text='') or (cmbtingkatan.Text='') then
begin
ShowMessage('Maaf !!! Data Anda Belum Lengkap ....');
exit;
end;
begin
zbiodata2.Open;
zbiodata2.Append;
zbiodata2.FieldByName('NIS').AsString := edtnis.Text;
zbiodata2.FieldByName('Nama_siswa').AsString := edtname.Text;
zbiodata2.FieldByName('Jenis_kelamin').AsString := cmbjk.Text;
zbiodata2.FieldByName('Tempat_lahir').AsString := edtempat.Text;
zbiodata2.FieldByName('Tanggal_lahir').AsString := edtgl.Text;
zbiodata2.FieldByName('Tingkatan').AsString := cmbtingkatan.Text;
zbiodata2.FieldByName('Hasil_indentifkasi').AsString := lblhasil.Caption;
zbiodata2.FieldByName('Metode_pembeaaran').AsString := memo1.Text;
try
convertobmp(openpicture.FileName);
gambar := TMemorystream.Create;
image1.Picture.Graphic.SaveToStream(gambar);
zbiodata2.SQL.Text := 'insert into biodata (gambar) values (:p0)';
zbiodata2.Params[0].LoadFromStream(gambar,ftBlob);
zbiodata2.Post;
zbiodata2.ExecSQL;
except
on E:Exception do
ShowMessage('sorry this a problem .' + #13 + 'Error : ' + E.Message);
end;
end;
end;
When I run this code, I get the error "sorry this is a problem . Error: List index out of bounds(2)"
After calling image1.Picture.Graphic.SaveToStream(gambar), set gambar.Position back to 0 before then calling zbiodata2.Params[0].LoadFromStream(gambar,ftBlob):
image1.Picture.Graphic.SaveToStream(gambar);
gambar.Position := 0; // <-- add this
zbiodata2.Params[0].LoadFromStream(gambar,ftBlob);
With that said, you are using zbiodata2 for two different operations at the same time - editing a new row that is being appended, and executing an SQL statement. Don't do that! Use separate components for each operation.
If the image is being saved into the same row that is being appended, don't bother executing a separate SQL INSERT statement at all. Save the image data directly into the row's gambar TField before then calling zbiodata2.Post():
procedure Tfbiodata.btnSaveClick(Sender: TObject);
var
gambar : TStream;
begin
if (edtnis.Text='') or (edtname.Text='') or (cmbjk.Text='') or (edtempat.Text='') or (edtgl.Text='') or (cmbtingkatan.Text='') then
begin
ShowMessage('Maaf !!! Data Anda Belum Lengkap ....');
Exit;
end;
try
convertobmp(openpicture.FileName);
zbiodata2.Open;
zbiodata2.Append;
try
zbiodata2.FieldByName('NIS').AsString := edtnis.Text;
zbiodata2.FieldByName('Nama_siswa').AsString := edtname.Text;
zbiodata2.FieldByName('Jenis_kelamin').AsString := cmbjk.Text;
zbiodata2.FieldByName('Tempat_lahir').AsString := edtempat.Text;
zbiodata2.FieldByName('Tanggal_lahir').AsString := edtgl.Text;
zbiodata2.FieldByName('Tingkatan').AsString := cmbtingkatan.Text;
zbiodata2.FieldByName('Hasil_indentifkasi').AsString := lblhasil.Caption;
zbiodata2.FieldByName('Metode_pembeaaran').AsString := memo1.Text;
if (image1.Picture.Graphic <> nil) and (not image1.Picture.Graphic.Empty) then
begin
gambar := TMemoryStream.Create;
try
image1.Picture.Graphic.SaveToStream(gambar);
gambar.Position := 0;
(zbiodata2.FieldByName('gambar') as TBlobField).LoadFromStream(gambar);
finally
gambar.Free;
end;
{
Alternatively:
gambar := zbiodata2.CreateBlobStream(zbiodata2.FieldByName('gambar'), bmWrite);
try
image1.Picture.Graphic.SaveToStream(gambar);
finally
gambar.Free;
end;
}
end;
zbiodata2.Post;
except
zbiodata2.Cancel;
raise;
end;
except
on E:Exception do
ShowMessage('sorry this a problem .' + #13 + 'Error : ' + E.Message);
end;
end;
If you are still having problems after that, you need to explain what is actually going wrong, what errors you are seeing, etc.
My code is the below, it's working correctly but, but after compiling program i see all the fullname and country listed vertically something like :
_________________________________
Fullname1
Country1
Fullname2
Country2
Fullname3
Country3
etc...
SQLQuery1.SQL.Text := 'SELECT * FROM users where user_age="'+age+'"';
SQLQuery1.Open;
rec := SQLQuery1.RecordCount;
SQLQuery1.First; // move to the first record
ListView1.Visible := false;
if rec>0 then
begin
while(not SQLQuery1.EOF)do begin
ListView1.Visible := true;
// do something with the current item
ListView1.AddItem('Full name: '+SQLQuery1['fullname'], Self);
ListView1.AddItem('Country: '+SQLQuery1['cntry'], Self);
// move to the next record
SQLQuery1.Next;
end;
But i want something Like :
First: add the column headers:
var
Col: TListColumn;
begin
Col := ListView1.Columns.Add;
Col.Caption := 'Name';
Col.Alignment := taLeftJustify;
Col.Width := 140;
Col := ListView1.Columns.Add;
Col.Caption := 'Country';
Col.Alignment := taLeftJustify;
Col.Width := 140;
end;
then add the records as follows:
var
Itm: TListItem;
begin
// start of your query loop
Itm := ListView1.Items.Add;
Itm.Caption := SQLQuery1['fullname'];
Itm.SubItems.Add(SQLQuery1['cntry']);
// end of your query loop
end;
Update:
Of course, in order to get the list as in your screenshot, you need to set the ListView's ViewStyle property to vsReport
Your code should look like that:
var
ListItem: TListItem;
...
ListView.Items.BeginUpdate;
try
while(not SQLQuery1.EOF)do begin
ListItem:= ListView.Items.Add;
ListItem.Caption:= 'Full name: '+SQLQuery1['fullname'];
with ListItem.SubItems do begin
Add('Country: '+SQLQuery1['cntry']);
// if you need more columns, add here
end;
SQLQuery1.Next;
end;
finally
ListView.Items.EndUpdate;
end;
You should also set ListView.Style to vsReport to show listview as grid.
I'm not sure how to get the listview to multiline, but I do know you're not using the Query correctly.
As it stands your code has an SQL-injection hole and the implicit reference to 'fieldbyname' inside the loop makes it slow.
var
FullName: TField;
Country: TField;
ListItem: TListItem;
begin
//Use Params or suffer SQL-injections
SQLQuery1.SQL.Text := 'SELECT * FROM users where user_age= :age';
SQLQuery1.ParamByName('age').AsInteger:= age;
SQLQuery1.Open;
if SQLQuery1.RecordCount = 0 then Exit;
//Never use `FieldByName` inside a loop, it's slow.
FullName:= SQLQuery1.FieldByName('fullname');
Country:= SQLQuery1.FieldByName('cntry');
ListView1.Style:= vsReport;
SQLQuery1.First; // move to the first record
SQLQuery1.DisableControls; //Disable UI updating until where done.
try
ListView1.Items.BeginUpdate;
//ListView1.Visible := false;
while (not SQLQuery1.EOF) do begin
//Code borrowed from #Serg
ListItem:= ListView.Items.Add;
ListItem.Caption:= 'Full name: '+Fullname.AsString;
ListItem.SubItems.Add('Country: '+Country.AsString);
SQLQuery1.Next;
end; {while}
finally
SQLQuery1.EnableControls;
ListView1.Items.EndUpdate;
end;
end;
The Delphi documentation contains this example that does exactly what you want.
procedure TForm1.FormCreate(Sender: TObject);
const
Names: array[0..5, 0..1] of string = (
('Rubble', 'Barney'),
('Michael', 'Johnson'),
('Bunny', 'Bugs'),
('Silver', 'HiHo'),
('Simpson', 'Bart'),
('Squirrel', 'Rocky')
);
var
I: Integer;
NewColumn: TListColumn;
ListItem: TListItem;
ListView: TListView;
begin
ListView := TListView.Create(Self);
with ListView do
begin
Parent := Self;
Align := alClient;
ViewStyle := vsReport;
NewColumn := Columns.Add;
NewColumn.Caption := 'Last';
NewColumn := Columns.Add;
NewColumn.Caption := 'First';
for I := Low(Names) to High(Names) do
begin
ListItem := Items.Add;
ListItem.Caption := Names[I][0];
ListItem.SubItems.Add(Names[I][2]);
end;
end;
end;
For all that the Delphi documentation is much maligned, it often has very useful examples like this. The gateway page to the examples is here and the examples are even available on sourceforge so you can check them out using your favourite svn client.
Procedure TForm1.GetUsers;
var
ListItem: TListItem;
begin
try
ListView1.Items.BeginUpdate;
try
ListView1.Clear;
MySQLQuery.SQL.Clear;
MySQLQuery.SQL.Add('select * from users;');
MySQLQuery.Open;
while (not MySQLQuery.EOF) do
begin
ListItem := ListView1.Items.Add;
ListItem.Caption:= VarToSTr(MySQLQuery['username']);
with ListItem.SubItems do
begin
Add(VarToSTr(MySQLQuery['password']));
Add(VarToSTr(MySQLQuery['maxscore']));
end;
MySQLQuery.Next;
end;
MySQLQuery.Close;
finally
ListView1.Items.EndUpdate;
end;
except
on E: Exception do
MessageDlg(PWideChar(E.Message), TMsgDlgType.mtError, [TMsgDlgBtn.mbOK], 0);
end;
end;
Hi there I have a problem
I need to auto fill in information from the database, but if i do it like this:
leemail.text := dm.atInlog['email'];
lenaam.text := dm.atInlog['naam'];
leAdres.text := dm.atInlog['adres'];
lePostcode.text := dm.atInlog['postcode'];
leTelefoonnummer.text := dm.atInlog['telefoon'];
leWoonplaats.Text := dm.atInlog['Woonplaats']
It just takes the first row. I want a specific row.
I can make it work with a button like this:
procedure TfmKlant.BTGegevensClick(Sender: TObject);
begin
//vraag gegevens van gebruiker op
dm.atInlog.Open;
while (not gevonden) and (not dm.atInlog.eof) do
begin
if dm.atInlog['email'] = fminloggen.inlognaam
then
begin
// plaats gegevens in de textboxen
gevonden := true;
leemail.text := dm.atInlog['email'];
lenaam.text := dm.atInlog['naam'];
leAdres.text := dm.atInlog['adres'];
lePostcode.text := dm.atInlog['postcode'];
leTelefoonnummer.text := dm.atInlog['telefoon'];
leWoonplaats.Text := dm.atInlog['Woonplaats']
end
else dm.atInlog.Next;
end;
But It does not do this in create form. How can I auto fill in the labeledit with the requested data?
thanks in advance
You could use TDataSet.Locate or Lookup:
type
TfmKlant = class(TForm)
// ... other declarations
private
procedure ShowData(p_Email: string);
end;
...
procedure TfmKlant.FormCreate(Sender: TObject);
begin
// assuming the data set is already open, and fminloggen.inlognaaem is already set
if dm.atInLog.Locate('email', fminloggen.inlognaam, []) then
begin
ShowData(fminloggen.inloognam);
end;
end;
procedure TfmKlant.ShowData(p_Email: string);
begin
gevonden := true;
leemail.text := dm.atInlog['email'];
lenaam.text := dm.atInlog['naam'];
leAdres.text := dm.atInlog['adres'];
lePostcode.text := dm.atInlog['postcode'];
leTelefoonnummer.text := dm.atInlog['telefoon'];
leWoonplaats.Text := dm.atInlog['Woonplaats']
end;