Home End User
New Blog Posts: Merging Reports - Part 1 and Part 2

Creating hierarchical groups dinamically...

edited July 2003 in End User
Hi,
My client has a tree of product groups and products inside the tree nodes.
He wants to have a report where groups would represent tree enlosure.
For example:
We have a product groups tree:

ALL
|
|------Alcohol
| |
| |-------Vodka
| |
| |-------Wine
|
|------Tobacco
| |
| |------Cigarettes
| |
| |------Cigar
|
|------Coffee

Each of the groups contains several products.
I need to create dynamically groups in report that would correspond to this
tree.
They need to conatin name of the group in the header and totals in the
footer.
It would look like this:

ALL
Alochol
--products
Vodka
--products
[Total by Vodka]
Wine
--products
[Total by Wine]
[Total by Alcohol]
Tobacco
--products
Cigarettes
--products
[Total by Cigarettes]
Cigar
--products
[Total by Cigar]
[Total by Tobacco]
Coffee
--products
[Total by Coffee]
[Total by ALL]

How can I create such a report?

Thanks,
MB.

Comments

  • edited July 2003
    You have to order the data first by group and then by product. Then you can
    create logical groups in the report. In this example it shows how to create
    a group in code:

    http://www.digital-metaphors.com/tips/DynamicReportCreation.zip


    Cheers,

    Jim Bennett
    Digital Metaphors


  • edited July 2003
    Hi,

    I need to create groups bands DYNAMICALLY AT RUN TIME.
    Also the amount of groups enlosements into each other must be UNLIMITED.
    The (report) groups bands must have the same hierarhy as the tree. (It is
    being kept in the database in the the id - parent_id relation).

    How do I generate groups in RAP? (Also in what event?) But I need to do it
    after pipelines generation...?
    How do I organize the (group) data if I need to create several groups
    enclosed into each other? (Not just one group after another). Would that be
    like this: 1,1,1,2,2,2,3,3,4,3,3,3,1,1 ?
    How do I "order the data first by group and then by product"? If I don't
    even have such convinient group field at all? (Just group tree table, with
    "id" - "parent_id" relation)?

    Is it still too confusing to understand?

    Thanks,
    MB.


  • edited July 2003
    The table you have is simply full of records and you can use fields in the
    table to order the data. Create a query like this and change the ORDER BY
    clause at runtime to change the ordering of the data. Also, set the group
    object's break name propery to match the ordering that you specify in the
    query.

    SELECT *
    FROM ProductTreeTable
    ORDER BY GroupCategory, ProductID

    The link to a tip provided earlier is to a project which shows how to create
    TppGroup objects at runtime. Get it working in Delphi code first, then port
    it to RAP. When you move the code to RAP, you'll want to use the earliest
    possible event, the global OnCreate event to create the group objects and
    related report components in the layout for those group bands.

    On a related note if your data is already in tree format, there is a
    treeview component listed on our website to print the tree data:
    http://www.choosepill.com/components/cpcrbtree.htm


    Cheers,

    Jim Bennett
    Digital Metaphors


  • edited July 2003
    Hi,
    Thanks for the help, I have just 2 questions left:

    1.) How can I assign record to the specific group manually at runtime? Let's
    say I have a set of records. I need to put them into one of the, let's say,
    4 groups based on some field value. Do I override some kind of group
    traversal method or something?
    2.) How can I hide some of the groups bands? Let's say I have 2 groups where
    1st is the master and 2nd is detail. When there is only one 2nd group I want
    it to be hidden, so that only 1st groups would be shown. How can I do it?

    Thanks,
    MB.

  • edited July 2003
    When the report is connected to a datapipeline, and it has groups defined in
    it, then it checks the Group.Breakname value on the pipeline to see if it
    should cause a group break. You can also control the group break by basing
    the group on a static label and then coding the Group.OnGetBreakValue event
    so that you can cause a break whenever you want to.

    Create two group objects, one for the master and one for the detail instead
    of using one group object and trying to make the first group printed the
    master and the second the detail.

    In order to not print the group bands, you have to traverse the data at
    least once in order to know ahead of time that a particular group shouldn't
    print its group bands. An alternative is to let the report generate this
    one record group detail, but then free the draw commands for it. Are you
    using new page groups? I'd say if you were using new page groups, then free
    the draw commands for a one detail group. Basically, you have to use each
    control's OnDrawCommandCreate event and store that in a new class of object
    which has the group break value and the draw command. Then store a list of
    groups that should have their group draw commands freed. Use the
    Report.OnEndPage event to free the draw commands. Group.KeepTogether should
    be false to allow you to free the draw commands. (Just thought of this)Then
    if you aren't using new page groups, you could shift all the other draw
    commands on the page up after you free the group draw commands. So, store
    another value in the object with the draw command and group value and group
    height in microns. When you change the drawcommand's Top property, use the
    micron unit of measure. There are two conversion routines in ppUtils.pas
    ppFromMMThousandths and ppToMMthousandths that you can use to convert report
    units.


    Cheers,

    Jim Bennett
    Digital Metaphors


  • edited July 2003
    Thank you very much for your detailed reply.
    But since I don't quite understand everything I would like to ask you to
    clarify several things.
    1.) By the following "then it checks the Group.Breakname value on the
    pipeline to see if it should cause a group break. You can also control the
    group break by basing the group on a static label" you mean that I need to
    assign static label name to Group.Breakname property? So that it would not
    depend from the pipeline?
    2.) "coding the Group.OnGetBreakValue event so that you can cause a break
    whenever you want to". How exactly do I need to use this event ? If I assign
    different (or new) value to the BreakValue variable then the last one then
    the groups breaks? Or the conditions for breaking are different?
    3.) By the "An alternative is to let the report generate ..." words you mean
    this is the other (2nd) way? Then could you please explain the first method
    for hiding bands in more details? I'm afraid the second one is a bit hard
    for me. I particualry don't understand how to store information about the
    bands I need and don't need to hide, how to use 1st and 2nd traversal
    (discern between them), and hide the bands (I guess it can be done easier
    than in 2nd method because of your words: "particular group shouldn't print
    its group bands".)
    4.) If I'm wrong and it is only one method, then please explain the
    following: how do I free the DrawCommand? What does that mean: "and store
    that in a new class of object which has the group break value and the draw
    command." ? What is "that"? What is "new class of object"?
    How do I store "a list of groups that should have their group draw commands
    freed"?

    Thanks,
    MB.

  • edited July 2003
    1. Yes, you can create a group on a static label and set its text to force a
    group break when you want, simply by changing the string value.

    2. The TppGroup.OnGetBreakValue is the same thing as coding the group break
    with a label. All the group needs is a string to compare to the last group
    break value and it will break when the string is different than the last
    record's group break value.

    3. My suggestion is complicated (I haven't coded it, but it should work
    based on similar techniques I've researched in the past), so lets put that
    on the back burner for now as it requires more code than may be necessary.
    Try to preprocess the data so that you only get the records in the dataset
    that you want to print. That way you don't have to try to hide group bands.
    Trying to hide output created by RB is generally more difficult than trying
    to keep it from printing in the first place, though it is possible.

    [quote]What is "new class of object"?[/quote] I simply meant a class, as in
    a TObject descendent, and phrased it as if you would say 'category of
    automobile.' Sorry for the confusion. The class I was thinking of would have
    an object reference property to the draw command object created by RB and a
    string property for the group break value to determine which group it
    belonged to. You can free a draw command by falling aDrawCommand.Free.


    Cheers,

    Jim Bennett
    Digital Metaphors


This discussion has been closed.