Link to home
Start Free TrialLog in
Avatar of nathc
nathc

asked on

Saving a user defined label layout for use later on

Hi,
Newbie here.
I'm about to start developing a label printing program in which the user can create a label which will be used over and over again for printing item, supplier, customer labels etc.
The user will drop fields onto a label template then resize, adjust fonts and then assign a database field to the graphical field on the label layout.
So once this label layout has been created and saved the user will use the second part of the program to select, let's say, a list of customers from their SQL Server database. Then select the predefined label format and print a specified number of labels for the selected customers.

I guess my real issue is this.
I have a rough idea of how to do the first part of the program i.e setting up a label representation on screen that the user can modify to suit. I know how to do the second part i.e pulling user selected fields from the underlying database ready for printing. But how do I merge the two together:)

How do I save the layout from the first part in a way that I can easily access it in the second, assign the appropriate user selected database fields and print them in the right format.

Basically this is a very general question which will clear up some conceptual design issues for me before I start and any little tidbits would be appreciated. Clues on which components could be useful etc.

Anyway thanks heaps
Nathan



Avatar of sftweng
sftweng

You should use the VCL components from the Data Access (e.g., TDataSet) and Data Controls (e.g., DBEdit, DBText, DBMemo) tabs and connect to your available datbase system. You might do this with the BDE (e.g., TTable) or ADO components or some other of your choosing. You might also use the Delphi Database Desktop to to define and manage the database. You'll find a number of example projects in %DELPHI%\Demos\Db.

You should also look at the Delphi Help "Designing Database Applications":

Database applications let users interact with information that is stored in databases. Databases provide structure for the information, and allow it to be shared among different applications.
Delphi provides support for relational database applications. Relational databases organize information into tables, which contain rows (records) and columns (fields). These tables can be manipulated by simple operations known as the relational calculus.
When designing a database application, you must understand how the data is structured. Based on that structure, you can then design a user interface to display data to the user and allow the user to enter new information or modify existing data.

The following topics introduce common considerations when designing a database application:

Using databases
      Database architecture
      Designing the user interface

You can get a text representation of
the label graphic object (assuming
that the objects inside are also Delphi
components, not just some kind of
"ghost" things) using the function
ObjectBinaryToText and its counterpart
ObjectTextToBinary.

See Delphi help for examples.
First time around I missed the point about user customization of the label. Delphian triggered a review with his approach concerning saving the graphic. I the case where you might use components from the "Data Controls", you might allow the user to use drag-and-drop and docking to tailor the format on the screen, saving the component's coordinates and characteristics into a separate profile file or database. You would save awat things like the component's top, left, width and height and it's colour. To get and set the latter, you could use a right-click popup menu to invoke a colour dialogue.
Avatar of nathc

ASKER

Hi guys,
I think I'm beginning to get a clearer picture.
So you're saying I can capture the characteristics of the components on the page as the user modifys them. e.g height, width, position etc. Is this saved to text and then converted to something the printer can recognise at a later time??
If I capture all of these properties as the user sets them, how do I save this template so I can load fields from the database into it for printing at a later time?
What sort of file should I be saving the template as??

Cheers for your help so far.
I suggest a TIniFile:

TIniFile stores and retrieves application-specific information and settings from INI files.

Unit

IniFiles

Description

TIniFile enables handling the storage and retrieval of application-specific information and settings in a standard INI file. The INI file text format is a standard introduced in Windows 3.x for storing and retrieving application settings from session to session. An INI file stores information in logical groupings, called “sections.” For example, the WIN.INI file contains a section called “[Desktop]”. Within each section, actual data values are stored in named keys. Keys take the form:

<keyname>=<value>

A FileName is passed to the TIniFile constructor and identifies the INI file that the object accesses.

A related object, TMemIniFile, works the same way as TIniFile, but buffers writes in memory to minimize disk access.

Tip:      You may choose to store information using the system registry instead of INI files. In this case, you can use TRegistryIniFile (which shares a common ancestor with TIniFile and so can be used in common code) or TRegistry.
As to printing, you could print the canvas of the form as a graphic image or you could use some other dynamically settable printing interface (e.g., QReport). It's probably much simpler just to print the canvas as a graphic image
Avatar of nathc

ASKER

Ah OK,
So I capture the properties of the different components on the label layout at the time the user saves it.
I write these to the INI file effectively storing an image of how the label should look.
When it comes time for the user to print labels using this layout I pull the details of the layout from the INI file.
I then insert the fields from the database into this layout and create a canvas to send to the printer??
I have a basic understanding of TCanvas but shall do some more research.
Is it easy to incorporate database fields into the canvas for printing??

I have used QReports recently for some static reports. I havn't discovered an easy way to allow users to layout the reports at runtime using this utility. I like the canvas idea.
I'd stick with just printing the canvas. It will show the form as it exists on the screen, so once you have placed the components, the printed output will be "WYSIWYG".

I'm going to send a small example in several minutes of configuring with the ini file, minus the database and printing linkage.
Here's a sample TIniFile program and a resulting ini file:

===================Program
unit uQ_21145118;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, IniFiles, StdCtrls;

type
  TForm1 = class(TForm)
    NameLabel: TLabel;
    NameEdit: TEdit;
    CityLabel: TLabel;
    CityEdit: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  myIniFile : TIniFile;
  myIniFileName : String;

implementation

{$R *.dfm}

procedure TForm1.FormCreate(Sender: TObject);
begin
  try
    myIniFileName := 'MyIniFile.ini';
    myIniFile := TIniFile.Create(myIniFileName);
    with myIniFile do
    begin
      ReadString('Form','Caption','Form Name');
      ReadInteger('Form','Top',0);
      ReadInteger('Form','Left',0);
      ReadInteger('Form','Width',200);
      ReadInteger('Form','Height',200);
      ReadString('NameLabel','Caption','Name');
      ReadInteger('NameLabel','Top',2);
      ReadInteger('NameLabel','Left',2);
      ReadInteger('NameLabel','Width',50);
      ReadInteger('NameLabel','Height',40);
      ReadString('NameEdit','Caption','');
      ReadInteger('NameEdit','Top',NameLabel.Top);
      ReadInteger('NameEdit','Left',NameLabel.Left+NameLabel.Width+5);
      ReadInteger('NameEdit','Width',50);
      ReadInteger('NameEdit','Height',NameLabel.Height);
      ReadString('CityLabel','Caption','City');
      ReadInteger('CityLabel','Top',NameLabel.Top+NameLabel.Height+5);
      ReadInteger('CityLabel','Left',NameLabel.Width);
      ReadInteger('CityLabel','Width',50);
      ReadInteger('CityLabel','Height',40);
      ReadString('CityEdit','Caption','');
      ReadInteger('CityEdit','Top',CityLabel.Top);
      ReadInteger('CityEdit','Left',CityLabel.Left+CityLabel.Width+5);
      ReadInteger('CityEdit','Width',50);
      ReadInteger('CityEdit','Height',CityLabel.Height);
    end {with};
  except
    ShowMessage('Exception trying to read customization ini file '+myIniFileName);
  end {try};
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  with myIniFile do
  begin
    WriteString('Form','Caption',self.Caption);
    WriteInteger('Form','Top',self.Top);
    WriteInteger('Form','Left',self.Left);
    WriteInteger('Form','Width',self.Width);
    WriteInteger('Form','Height',self.Height);
    WriteString('NameLabel','Caption',NameLabel.Caption);
    WriteInteger('NameLabel','Top',NameLabel.Top);
    WriteInteger('NameLabel','Left',NameLabel.Left);
    WriteInteger('NameLabel','Width',NameLabel.Width);
    WriteInteger('NameLabel','Height',NameLabel.Height);
    WriteString('NameEdit','Caption',NameEdit.Text);
    WriteInteger('NameEdit','Top',NameEdit.Top);
    WriteInteger('NameEdit','Left',NameEdit.Left);
    WriteInteger('NameEdit','Width',NameEdit.Width);
    WriteInteger('NameEdit','Height',NameEdit.Height);
    WriteString('CityLabel','Caption',CityLabel.Caption);
    WriteInteger('CityLabel','Top',CityLabel.Top);
    WriteInteger('CityLabel','Left',CityLabel.Left);
    WriteInteger('CityLabel','Width',CityLabel.Width);
    WriteInteger('CityLabel','Height',CityLabel.Height);
    WriteString('CityEdit','Caption',CityEdit.Text);
    WriteInteger('CityEdit','Top',CityEdit.Top);
    WriteInteger('CityEdit','Left',CityEdit.Left);
    WriteInteger('CityEdit','Width',CityEdit.Width);
    WriteInteger('CityEdit','Height',CityEdit.Height);
  end {with};
end;

end.
===================Ini file
[Form]
Caption=Customizable Label Printer
Top=192
Left=282
Width=405
Height=192
[NameLabel]
Caption=Name
Top=32
Left=56
Width=28
Height=13
[NameEdit]
Caption=
Top=32
Left=128
Width=121
Height=21
[CityLabel]
Caption=CityLabel
Top=72
Left=56
Width=43
Height=13
[CityEdit]
Caption=
Top=72
Left=128
Width=121
Height=21
Oops - forget to assign the read values in the OnCreate event

e.g.,
  self.Caption :=  ReadString('Form','Caption','Form Name');
So here's what the FormCreate event should look like:

procedure TForm1.FormCreate(Sender: TObject);
begin
  try
    myIniFileName := 'C:\MyIniFile.ini';
    myIniFile := TIniFile.Create(myIniFileName);
    with myIniFile do
    begin
      self.Caption := ReadString('Form','Caption','Form Name');
      self.Top := ReadInteger('Form','Top',0);
      self.Left := ReadInteger('Form','Left',0);
      self.Width := ReadInteger('Form','Width',200);
      self.Height := ReadInteger('Form','Height',200);
      NameLabel.Caption := ReadString('NameLabel','Caption','Name');
      NameLabel.Top := ReadInteger('NameLabel','Top',2);
      NameLabel.Left := ReadInteger('NameLabel','Left',2);
      NameLabel.Width := ReadInteger('NameLabel','Width',50);
      NameLabel.Height := ReadInteger('NameLabel','Height',40);
      NameEdit.Text := ReadString('NameEdit','Caption','');
      NameEdit.Top := ReadInteger('NameEdit','Top',NameLabel.Top);
      NameEdit.Left := ReadInteger('NameEdit','Left',NameLabel.Left+NameLabel.Width+5);
      NameEdit.Width := ReadInteger('NameEdit','Width',50);
      NameEdit.Height := ReadInteger('NameEdit','Height',NameLabel.Height);
      CityLabel.Caption := ReadString('CityLabel','Caption','City');
      CityLabel.Top := ReadInteger('CityLabel','Top',NameLabel.Top+NameLabel.Height+5);
      CityLabel.Left := ReadInteger('CityLabel','Left',NameLabel.Width);
      CityLabel.Width := ReadInteger('CityLabel','Width',50);
      CityLabel.Height := ReadInteger('CityLabel','Height',40);
      CityEdit.Text := ReadString('CityEdit','Caption','');
      CityEdit.Top := ReadInteger('CityEdit','Top',CityLabel.Top);
      CityEdit.Left := ReadInteger('CityEdit','Left',CityLabel.Left+CityLabel.Width+5);
      CityEdit.Width := ReadInteger('CityEdit','Width',50);
      CityEdit.Height := ReadInteger('CityEdit','Height',CityLabel.Height);
    end {with};
  except
    ShowMessage('Exception trying to read customization ini file '+myIniFileName);
  end {try};
end;
Avatar of nathc

ASKER

Ahh nice, nice.
One more question sfteng.
When I build the canvas object using this information does it allow me to alter the look of the label. That is I don't want the label that prints to look exactly like the label image that the user creates on the screen. Different background etc.
Does TCanvas provide a lot of flexibility in adjusting the way the label actually prints??
This is the last question. I don't want you to have to write the actual program for me :)
ASKER CERTIFIED SOLUTION
Avatar of sftweng
sftweng

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of nathc

ASKER

Thanks for all your help sfteng.
I'm happy to have been of assistance. I hope that you will enjoy using Delphi - it's the most powerful development system available for Windows, in my opinion, and does much to encourge good development habits.