Solved Continuous Sub forms (1 Viewer)

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
A while ago, I saw a post from a member asking help for having a continuous sub form in continuous Main form.
Since it's not actually possible, @MajP solved the problem by having multiple data sheet subforms. (If my memory serves me right)

My search doesn't bring up anything.
Does anybody happen to have a link to it?

thanks.
 

gemma-the-husky

Super Moderator
Staff member
Local time
Today, 16:18
Joined
Sep 12, 2006
Messages
15,657
It's possible, and not difficult. it's just that Access won't set it up automatically for you.

Off hand I am not sure whether you can set the correct linking relationships manually or not.
(the tool that lets you set the fields that bind the main form and sub form)

If not you can simply (in the current event code) use the ID (or other fields) of the active main form record, and requery the subform to select the records that match the value. I tend to use public variables, but you can use tempvars, or read the form values.

I often nest 3 forms, eg customers, orders, order items, all continuous. You just have to plan the use of the screen real estate.
 

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
@MajP spot on. Million thanks.

@gemma-the-husky thanks for the advice. I’ll do some tests to see what can do. I think I can have a text box and link the sub form to this text box (instead of linking sub form to main form)
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 11:18
Joined
May 21, 2018
Messages
8,529
@KitaYama IMO, multiple subforms is kind of an art. They can get confusing quick. Nested subforms are usually really confusing.
Here is a nice example from @Pat Hartman which is intuitive using synchronized subforms.
 

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
@MajP
As I explained in THIS post, our databases use a function to read and build the ribbon from 4 different tables (tblRibbons, tblTabs, tblGroups, tblControls) based on users’ language and their permissions.
I was thinking of using a single form for tblRibbons and 3 continuous forms for other three tables to be able to manage them better. I knew in the post I was looking for, you had offered a solution with tree view (post #22 in your above link)

I’ve never used a tree view, and I’m not sure if it can be used to show a data from 4 different tables. I simply thought it can be a good chance to study one of your tree view posts and if possible show the ribbons and their Tabs, Groups and controls. That was the main reason I was looking for your post.

You may not know how your posts have helped me in all problems I’ve had.
I really thank you for all your posts and the ideas you give us.
 
Last edited:

MajP

You've got your good things, and you've got mine.
Local time
Today, 11:18
Joined
May 21, 2018
Messages
8,529
I’ve never used a tree view, and I’m not sure if it can be used to show a data from 4 different tables.
If you look at the demo in the link, I load a tree using Customers, Orders, and Order Details. It is just a matter of following the union query exactly.
If you get the union query correct, it truthfully loads a treee view with only writing a single line of code.
All of the heavy lifting is in the class.

In fact in the link I posted with Pat's example, the tree I show has nodes from multiple tables. What ever node you click brings up the correct subform on the right and the correct record.

I can demo if you upload a database with just the tables.
 

isladogs

MVP / VIP
Local time
Today, 16:18
Joined
Jan 14, 2017
Messages
18,227
Place the continuous subform(s) in the main form footer
 

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
I can demo if you upload a database with just the tables.
I imported your form and class, but couldn't figure out what the third parameter in class initialize sub is (parentStartID). Since the parameter is string type, I added a RibbonPK AS RibPK to my query, but apparently it's not the correct way.

I was planning to have a tree view to have tblRibbon as its root node, then goes three level deep (tblTabs - > tblGroups -> tblControls) and after selecting any node in last node (tblControls) the left side sub form show a filtered result from tblControlLabels (linked by field ControlID - short text data type)
I really appreciate any advice on it.
 
Last edited:

Edgar_

Active member
Local time
Today, 10:18
Joined
Jul 8, 2023
Messages
430
You could embed a report inside another report.
 

Attachments

  • Database28.accdb
    460 KB · Views: 69

MajP

You've got your good things, and you've got mine.
Local time
Today, 11:18
Joined
May 21, 2018
Messages
8,529
Here is a skeleton to get you started. This required a single union query based on four identical queries. Then the code to load the tree is a singl initialze method.

Code:
Set TVW = New TreeviewForm
  TVW.Initialize Me.XTree.Object, "qryRibbons_Tabs_Groups_Controls", "None", , lt_fullload

ribbons.png


Now you can add a subform control to the right of the tree that shows the details for whatever node you are on. You would make a different subform for each record type (ribbons, tabs, groups) and load the correct subform into the subform control and go to the correct record. So whatever node you are clicked on you can see the details and edit.

Each node query is exactly done the same way. If you understand the query fields
ID
ParentID
NodeText
Identifier
You can load any table/s

The Node Text can be edited to show whatever you want. You can add images to this to help show your controls.
 

Attachments

  • MajP Treeview Ribbon Demo.accdb
    840 KB · Views: 82

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
I simply don't know how to thank you.
I'll check where I was doing something wrong during the lunch time.

million thanks.
 

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
@MajP
One more question if you don't mind.

If my memory serves me right, somewhere you wrote nodes can be dragged and dropped.
Not that I need this utility, I was just wondering if it's really possible or for some problems in my tables I'm not able to drag and drop nodes.

I possibly will hide the Expand/Collapse button because I don't need them. But just as a notification, you may want to correct the Collapse Branch button's behavior. It behaves exactly the same as Collapse Tree.

Again I really appreciate your help and time.
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 11:18
Joined
May 21, 2018
Messages
8,529
The e2e example demos full drag and drop.
 

KitaYama

Well-known member
Local time
Tomorrow, 00:18
Joined
Jan 6, 2022
Messages
1,541
@MajP I'm terribly sorry for asking another question.
I promise it'll be last one.

I couldn't find a method in the class that returns the max number of the levels.
I'm trying to run a function if the last node is clicked.
Of course I know the max number of levels is 4 (Ribbons,Tabs,Groups,Controls), but I'm trying to minimize the corrections when I copy the class to other projects.
Something like :
Code:
If Nz(TVW.SelectedNodeLevel(), 0)= TVW.MaxNodeLevel Then

If there's no method for this, maybe I'll add a loop and extract the max level of nodes.

Thanks.
 
Last edited:

MajP

You've got your good things, and you've got mine.
Local time
Today, 11:18
Joined
May 21, 2018
Messages
8,529
Really depends on what you mean by MaxLevel.
Longest branch in tree?
Longest branch that tree could have if all tables populated?
Last node in branch?

By MaxLevel I assume you mean the number of nodes in the longest branch of the tree. So if you click on Test2 it is has no children and it is the max node in that branch, but the tree has some branches with 4 levels.

In this case where you are unioning related tables the number of levels possible is the number of tables. You know how many tables and which table is the last. So it seems you could just provide a literal in your code. If you add more tables to your tree than modify your code. This is more reliable. Assume we know that the last possible nodes are Ribbon Controls. Their identifier is RibbonControl (explain later).
I would do

If TVW.SelectedNodeIdentifier = "RibbonControl" then ...
or
if TVW.getNodeIdentifier(TVW.SelectedNode) = "Ribbon Control" then ...

(There are Properties for the selected node and basically duplicate functions to get the same thing for any node that is why the two methods. In the Get functions you can pass any node not just the selected node.)

To explain how the queries work and help to tie the tree to records. Node queries get an "Identifier". This can be used to tell you which table a value comes from. (You can use the table name if you wanted but you will have to do a select case anyways so does not really help and may be harder to read.) The Identifier gets concatenated to the PK to and then used to form the node ID. The ParentID is the same thing with the parent Identifier concatenated to the parent FK.
When you load the tree the ID becomes the NodeKey which will be unique because event though all the PKs of the tables are autonumbers they now have the concatenated identifier. The Identifier gets stored in the Node tag property. Because of this, when you click on a node you can remove the Identifier from the Node key and get the PK. You can use the indentifier in a select case to then get the table.

qryNodeRibbonControl qryNodeRibbonControl

IDNodeTextParentIDIdentifier
RibbonControl1myButton1: button largeRibbonGroup2RibbonControl
RibbonControl2mybutton2: button largeRibbonGroup2RibbonControl
RibbonControl3myButton3: button largeRibbonGroup3RibbonControl
RibbonControl4mybutton4: button largeRibbonGroup3RibbonControl
RibbonControl5myButton5: button largeRibbonGroup4RibbonControl
RibbonControl6mybutton6: button largeRibbonGroup4RibbonControl
RibbonControl7myButton7: button largeRibbonGroup5RibbonControl
RibbonControl8mybutton8: button largeRibbonGroup5RibbonControl
RibbonControl9loginBtn: button largeRibbonGroup1RibbonControl
However, normally this is done with a self referencing table. Think family tree. So the levels on any branch are undetermined and in theory infinite because you could keep adding children.
If there's no method for this, maybe I'll add a loop and extract the max level of nodes.

You cannot really do this with a loop (what would you loop?) You have to do this recursively just like loading the tree. And if I was going to do this that is where I would do it. I would make a property MaxPotentialLevels and set this when recursively loading the tree. If the value of MaxPotentialLevels is < node level then MaxPotentialLevels = Node Level

However that is problematic too. The biggest problem is most of the time I do not load the entire tree. I have the option to do a light load which means I load only the visible nodes. This saves tremendous amount of time on large trees. The nodes are only loaded when you expand a node. That means if you really wanted to do this you now need a seperate method to fully recurse the tree to figure out the longest branch.

This could be easily added, but not a lot of utility IMO. And has those potential problems. If it is a union query you will know the max level and better yet the last Identifier. For a self referencing table each node is the same (example person) so you do not care about longest branch in the tree. Unlikely you would do something different in that case.

Bottom line I think the most utility and most accurate would be to check the Identifier of the node to determine if it is the lowest level.

To determine if a node has children you can do something like
TVW.childNodes(TVW.SelectedNode).Count
If the count is 0 then it is at the end of a branch, but not necessarily the max possible level.
 

Users who are viewing this thread

Top Bottom