Friday, 1 October 2010

Working with Microsoft Excel (.xlsx) files in Delphi 2010

Due to the improvement of the new format of Microsoft office 2007 files (.docx, .xlsx based on xml) the way we use to access this documents has changed. Instead of using OLE we can use the power of Delphi and the type library Borland (TLB Files).
In this article we'll talk about how to create the TLB files and the code we need to access the .Excel (.xlsx file) of the example I've created.
First of all, we need to import the components via -> Component -> Import a Type Library. Once we are there, we need to select the "Microsoft Excel 12.0 Object Library" and go on with the import. Mark the "Generate component wrappers" check-box and finally add the component to the working unit. This will generate the Excel_TLB.pas.
Once we have integrated this file into our project, we need to go on with importing the second component: Component -> Import a Type Library and then install the "Microsoft Office 12.0 Object Library". This will generate the Office_TLB.pas (this unit is necessary because it's used by Excel_TLB.pas).

1 - Knowing the number and name of the sheets of the Workbook.
The following code will open a excel file and will load all the sheets into a combo box. Even though it represents a small portion of code, the library is quite complicated to use.

procedure TForm1.LoadCombo();
var
    XLSXReader: Excel_TLB.TExcelApplication;
    newWorkbook: Excel_TLB._Workbook;
    objXLS: Excel_TLB.TExcelWorkbook;
    objSheet: Excel_TLB.TExcelWorksheet;
    i: Integer;
begin
    newWorkbook := XLSXReader.Workbooks.Add('C:\book1.xlsx', GetUserDefaultLCID);
    objXLS := Excel_TLB.TExcelWorkbook.Create(nil);
    objXLS.ConnectTo(newWorkbook);
    objSheet := Excel_TLB.TExcelWorksheet.Create(nil);
    for i := 1 to objXLS.Worksheets.count do
    begin
        objSheet.ConnectTo(objXLS.Worksheets[i] as _Worksheet);
        ComboBox1.Items.Add(objSheet.Name);
    end;
    newWorkbook.Close(false, EmptyParam, EmptyParam, GetUserDefaultLCID);
    FreeAndNil(objXLS);
    FreeAndNil(objSheet);
end;

2 - Accessing to Excel fields.
The following example will get the objSheet and will get all the data from the sheet and will dump into a dataset to display then the result into a grid.
procedure TForm1.Open(Sender: TObject);
var
    XLSXReader: Excel_TLB.TExcelApplication;
    newWorkbook: Excel_TLB._Workbook;
    objXLS: Excel_TLB.TExcelWorkbook;
    objSheet: Excel_TLB.TExcelWorksheet;
    objWrapper: TExcelWrapper;
begin
    newWorkbook := XLSXReader.Workbooks.Add('C:\book1.xlsx', GetUserDefaultLCID);
    objXLS := Excel_TLB.TExcelWorkbook.Create(nil);
    objXLS.ConnectTo(newWorkbook);
    objSheet := Excel_TLB.TExcelWorksheet.Create(nil);
    objSheet.ConnectTo(objXLS.Worksheets['sheet1'] as _Worksheet);
    objWrapper := TExcelWrapper.Create(objSheet);
    if cdsExcel.Active then
        cdsExcel.Close;
    objWrapper.FillDataSet(cdsExcel);
    cdsExcel.Open;
    cdsExcel.First;
    newWorkbook.Close(false, EmptyParam, EmptyParam, GetUserDefaultLCID);
end;

Then the code for getting the data from the sheet:

procedure TExcelWrapper.FillDataSet(var cdsExcel: TClientDataSet);
var
    count: Integer;
    i: Integer;
    bFinished, correct: boolean;
    Value: String;
begin
    if Assigned(FSheet) then
    begin
        try
            cdsExcel.DisableControls;
            count := 0;
            i := 2;
            LastModule := '';
            bFinished := false;
            while not bFinished do
            begin
                Value := FSheet.Cells.Item[i, 1];
                if Value = '' then
                    count := count + 1
                else
                begin
                    count := 0;
                    cdsExcel.Append;
                    cdsExcel.FieldByName('Column1').AsString := FSheet.Cells.Item[i, 1];
                    cdsExcel.FieldByName('Column2').AsString := FSheet.Cells.Item[i, 2];
                    cdsExcel.FieldByName('Column3').AsString := FSheet.Cells.Item[i, 3];
                end;
                if count > 2 then
                    bFinished := true;
                i := i + 1;
            end;
            cdsExcel.Post;
        finally
            cdsExcel.EnableControls;
        end;
    end;
end;

3 - Things to take into account.
You need to remember that the library creates an instance of Excel application, and you must close all the opened connections using the Close procedure.

newWorkbook.Close(false, EmptyParam, EmptyParam, GetUserDefaultLCID); 
 

Thursday, 30 September 2010

Reflexion time - Adaptation is the Key

First of all, I would like to thank all the positive comments I've received for my Blog. I'm truly happy because they inspire me to keep publishing interesting topics related with Delphi, Technology and Science. I can see that the page is widely visited throughout the world and the rate of daily visitors is quite good, but the users don't leave any feedback and sometimes this is a little disappointing. Anyway, I'll keep writing and doing my own research in order to improve myself and sharing my knowledge to the world.
Now I'm immersed on a reflexivity's period, thinking about job opportunities, new projects and new interesting articles to publish. This month I've been working on new interesting projects, migrating versions from Delphi 2007 to Delphi 2010, doing a big rewrite of code due to its internal changes with Indy10 and other new features like generics and working with parameters (I'm eager to test the new Delphi XE, but as soon as I finish the other projects). I've been as well working on a new system to improve the usability of working with Microsoft Office 2007 files such as Excel files (.xlsx) and Word files (.docx),  and some other projects as a photographer doing a catalogue for a company!. As you can see this month has been pretty hectic and I never stop running. I have other projects in mind that I need to put into gear, but I need some time to meditate about them, but I'll keep you posted!.
I've been providing services as a technological consultant to some companies in order to improve their IT departments in a wide range of aspects like: security, collaborative work and documentation. And all these experiences have been very rewarded to put into practise all the things learned during the last three years.
With all of this, I just want to motivate you, and remember to do what you love to achieve all what you want. I've been following this simple rule and everything is working fine. I can't complain of anything!.

Here you can see a very interesting video showing the power of adaptation:


Don't hesitate to comment in the blog and feel free to contact me through the web.
If you have time, you can take a look at my portfolio and check out my passion for photography!.

Thursday, 16 September 2010

LeanKit Kanban

This week I've been working with the LeanKit Kanban, a very interesting approach for using Kanban boards in Agile development. All of you know about my interests with the Agile approach, and I think that this interesting and free (limited) tool will help you to keep track of your daily work.

Here you can see a mock up of my kanban board:


In the Jesse Liberty blog, you can find a very interesting description of the Kanban tool:

What Kanban Does For You

What is not obvious in looking at the board is how quickly it reveals bottlenecks, where I’m wasting time, and how to be as effective as possible.  The fact that it is all very visual, that you are moving these cards around and can see at a glance all the relevant information, makes it very easy to see what is stuck, and what is moving nicely.

LeanKit Kanban has a number of features that I don’t personally use, but would have killed for in previous projects, such as advanced analytics that include diagrams for Cycle time, cumulative flow, process efficiency, work distribution and more.  The analytics allow a team to answer such critical questions  as “what is holding the project back?” and ”when will this item be ready?” with high confidence.

I do use the notification capabilities, which turns what is usually a “polling” exercise in frustration into an “interrupt-driven” management approach; much better.

The bottom line, for me, though, is that each “card” carries its entire history, its description, its priority, its due date and everything else I need to know about a sub-feature.  That is very clean and it fits well with the way I work.
Jesse Liberty.

Wednesday, 8 September 2010