Skip to main content
Table of Contents

Adding Messages

TTMSFNCChat stores messages in the ChatMessages collection. Messages can be added programmatically or typed by the user via the built-in message field.


The built-in message field

Set ShowMessageField := True to show a TMemo input and a send button at the bottom:

The built-in message fieldPascalC++
TMSFNCChat1.ShowMessageField := True;
TMSFNCChat1->ShowMessageField = true;

When the user presses the send button or Enter, a new right-aligned message is added. Use OnBeforeSendMessage to validate or modify the text before it is added:

The built-in message fieldPascalC++
procedure TForm1.TMSFNCChat1BeforeSendMessage(Sender: TObject;
  var AText: string; var AAllow: Boolean);
begin
  if Trim(AText) = '' then
    AAllow := False;
end;
void __fastcall TForm1::TMSFNCChat1BeforeSendMessage(TObject *Sender,
  System::UnicodeString &AText, bool &AAllow)
{
  if (Trim(AText) == "")
    AAllow = false;
}

Adding messages in code

Add chat messages, images and filesPascalC++
// Add messages via collection
procedure TForm1.Button1Click(Sender: TObject);
var
  itm: TTMSFNCChatItem;
begin
  itm := TMSFNCChat1.ChatMessages.Add;
  itm.Text            := 'How was your day?';
  itm.Title           := 'Mom';
  itm.Fill.Color      := gcGray;
  itm.MessageLocation := cmlLeft;

  // Add messages via helper functions
  itm := TMSFNCChat1.AddMessage('Hello!', cmlRight);                    // right-aligned
  itm := TMSFNCChat1.AddMessage('Hi there!', 'Alice', cmlLeft);         // with title

  // Add an image
  TMSFNCChat1.AddImage('C:\Photos\photo.jpg');
  TMSFNCChat1.AddImage('C:\Photos\photo.jpg', 'Look at this!', cmlLeft);
  // With named image in BitmapContainer:
  TMSFNCChat1.AddImageWithName('C:\Photos\photo.jpg', 'my-photo');

  // Add a file link
  TMSFNCChat1.AddFile('file://C:\Reports\report.pdf', 'Monthly Report', 'Attached');

  // Clear all messages
  TMSFNCChat1.Clear;

  // Scroll to the latest item
  TMSFNCChat1.ScrollToBottom;

  // Show the message input field at the bottom
  TMSFNCChat1.ShowMessageField := True;
end;

// Intercept the send button
procedure TForm1.TMSFNCChat1BeforeSendMessage(Sender: TObject;
  var AText: string; var AAllow: Boolean);
begin
  if Trim(AText) = '' then
    AAllow := False;  // block empty messages
end;
// Add messages via collection
void __fastcall TForm1::Button1Click(TObject *Sender)
{
  TTMSFNCChatItem *itm = static_cast<TTMSFNCChatItem *>(TMSFNCChat1->ChatMessages->Add());
  itm->Text            = "How was your day?";
  itm->Title           = "Mom";
  itm->Fill->Color     = gcGray;
  itm->MessageLocation = cmlLeft;

  // Add messages via helper functions
  itm = TMSFNCChat1->AddMessage("Hello!", cmlRight);                    // right-aligned
  itm = TMSFNCChat1->AddMessage("Hi there!", "Alice", cmlLeft);         // with title

  // Add an image
  TMSFNCChat1->AddImage("C:\\Photos\\photo.jpg");
  TMSFNCChat1->AddImage("C:\\Photos\\photo.jpg", "Look at this!", cmlLeft);
  // With named image in BitmapContainer:
  TMSFNCChat1->AddImageWithName("C:\\Photos\\photo.jpg", "my-photo");

  // Add a file link
  TMSFNCChat1->AddFile("file://C:\\Reports\\report.pdf", "Monthly Report", "Attached");

  // Clear all messages
  TMSFNCChat1->Clear();

  // Scroll to the latest item
  TMSFNCChat1->ScrollToBottom();

  // Show the message input field at the bottom
  TMSFNCChat1->ShowMessageField = true;
}

// Intercept the send button
void __fastcall TForm1::TMSFNCChat1BeforeSendMessage(TObject *Sender,
  System::UnicodeString &AText, bool &AAllow)
{
  if (Trim(AText) == "")
    AAllow = false;  // block empty messages
}
TTMSFNCChat showing left and right message bubbles

Via ChatMessages collection

Via ChatMessages collectionPascalC++
var itm: TTMSFNCChatItem;
begin
  itm := TMSFNCChat1.ChatMessages.Add;
  itm.Text            := 'How was your day?';
  itm.Title           := 'Mom';
  itm.Fill.Color      := gcGray;
  itm.MessageLocation := cmlLeft;  // cmlLeft or cmlRight
end;
TTMSFNCChatItem *itm = static_cast<TTMSFNCChatItem *>(TMSFNCChat1->ChatMessages->Add());
itm->Text            = "How was your day?";
itm->Title           = "Mom";
itm->Fill->Color     = gcGray;
itm->MessageLocation = cmlLeft;  // cmlLeft or cmlRight

Via AddMessage helpers

Via AddMessage helpersPascalC++
TMSFNCChat1.AddMessage('Hello!');                         // right-aligned
TMSFNCChat1.AddMessage('Hi there!', 'Alice', cmlLeft);    // with title, left-aligned
TMSFNCChat1->AddMessage("Hello!");                         // right-aligned
TMSFNCChat1->AddMessage("Hi there!", "Alice", cmlLeft);    // with title, left-aligned

DefaultLeftItem and DefaultRightItem provide the appearance template applied to messages added via AddMessage.


Adding images

Adding imagesPascalC++
// From file path
TMSFNCChat1.AddImage('C:\Photos\photo.jpg');
TMSFNCChat1.AddImage('C:\Photos\photo.jpg', 'Look at this!', cmlLeft);

// With a named key for BitmapContainer storage
TMSFNCChat1.AddImageWithName('C:\Photos\photo.jpg', 'photo-key');
// From file path
TMSFNCChat1->AddImage("C:\\Photos\\photo.jpg");
TMSFNCChat1->AddImage("C:\\Photos\\photo.jpg", "Look at this!", cmlLeft);

// With a named key for BitmapContainer storage
TMSFNCChat1->AddImageWithName("C:\\Photos\\photo.jpg", "photo-key");

Assign a TTMSFNCBitmapContainer to BitmapContainer and set AddImagesToBitmapContainer := True so images are stored by name rather than embedded as base64 (which can slow down rendering with many images).

Note

On the WEB platform without a BitmapContainer, pass a base64-encoded data URI as the image path.


Adding file linksPascalC++
TMSFNCChat1.AddFile('file://C:\Reports\report.pdf', 'Monthly Report', 'Attached');
TMSFNCChat1->AddFile("file://C:\\Reports\\report.pdf", "Monthly Report", "Attached");

The first parameter is the URL opened on click; the second is the display name.


Drag and drop

TTMSFNCChat detects files dragged over the message area. Handle OnFileDragOver to allow the drop, then read the dropped files in OnFileDrop:

Drag and dropPascalC++
procedure TForm1.TMSFNCChat1FileDragOver(Sender: TObject;
  AFileList: TStringList; var AAllow: Boolean);
begin
  AAllow := True;
end;

procedure TForm1.TMSFNCChat1FileDrop(Sender: TObject; AFileList: TStringList);
var
  i: Integer;
begin
  for i := 0 to AFileList.Count - 1 do
    TMSFNCChat1.AddFile('file://' + AFileList[i], ExtractFileName(AFileList[i]));
end;
void __fastcall TForm1::TMSFNCChat1FileDragOver(TObject *Sender, bool &AAllow)
{
  AAllow = true;
}

void __fastcall TForm1::TMSFNCChat1FileDrop(TObject *Sender, TTMSFNCChatDropFileList AFileList)
{
  for (int i = 0; i < AFileList.Length; i++)
    TMSFNCChat1->AddFile("file://" + AFileList[i], ExtractFileName(AFileList[i]));
}
Chat after two files were dropped on it, each added by OnFileDrop as a file-link message Chat after two files were dropped on it, each added by OnFileDrop as a file-link message

The document icon that AddFile places in front of the file link is drawn in the message's TextColor (SelectedTextColor while the message is selected), so it stays readable on every bubble fill and theme. To change the icon colour, set TextColor on the returned item or on DefaultLeftItem / DefaultRightItem; the link itself uses URLColor. Images you embed yourself in the message text are drawn unchanged.


Reload (pull-to-refresh)

Reload (pull-to-refresh)PascalC++
TMSFNCChat1.Reload.Enabled := True;
TMSFNCChat1->Reload->Enabled = true;

Dragging down on the chat list starts a reload animation and fires OnStartReload. When your background fetch is done, call StopReload:

Reload (pull-to-refresh)PascalC++
procedure TForm1.TMSFNCChat1StartReload(Sender: TObject);
begin
  TThread.CreateAnonymousThread(procedure
  begin
    // load older messages...
    TThread.Synchronize(nil, procedure
    begin
      TMSFNCChat1.StopReload;
    end);
  end).Start;
end;
void __fastcall TForm1::TMSFNCChat1StartReload(TObject *Sender)
{
  TThread::CreateAnonymousThread([this]()
  {
    // load older messages...
    TThread::Synchronize(nullptr, [this]()
    {
      TMSFNCChat1->StopReload();
    });
  })->Start();
}

Combining drag-and-drop, validation, and reload

This pattern connects file drag-and-drop, send validation, and pull-to-refresh in one form:

Combining drag-and-drop, validation, and reloadPascalC++
procedure TForm1.TMSFNCChat1BeforeSendMessage(Sender: TObject;
  var AText: string; var AAllow: Boolean);
begin
  AAllow := Trim(AText) <> '';
end;

procedure TForm1.TMSFNCChat1FileDrop(Sender: TObject; AFileList: TStringList);
var
  i: Integer;
begin
  for i := 0 to AFileList.Count - 1 do
    TMSFNCChat1.AddFile('file://' + AFileList[i], ExtractFileName(AFileList[i]));
end;

procedure TForm1.TMSFNCChat1StartReload(Sender: TObject);
begin
  TThread.CreateAnonymousThread(procedure
  begin
    TThread.Synchronize(nil, procedure begin TMSFNCChat1.StopReload; end);
  end).Start;
end;
void __fastcall TForm1::TMSFNCChat1BeforeSendMessage(TObject *Sender,
  System::UnicodeString &AText, bool &AAllow)
{
  AAllow = Trim(AText) != "";
}

void __fastcall TForm1::TMSFNCChat1FileDrop(TObject *Sender, TTMSFNCChatDropFileList AFileList)
{
  for (int i = 0; i < AFileList.Length; i++)
    TMSFNCChat1->AddFile("file://" + AFileList[i], ExtractFileName(AFileList[i]));
}

void __fastcall TForm1::TMSFNCChat1StartReload(TObject *Sender)
{
  TThread::CreateAnonymousThread([this]()
  {
    TThread::Synchronize(nullptr, [this]() { TMSFNCChat1->StopReload(); });
  })->Start();
}
Chat with the pull-to-refresh reload indicator running above a conversation that contains a dropped file, with text in the message field Chat with the pull-to-refresh reload indicator running above a conversation that contains a dropped file, with text in the message field

See also