Create controls dynamically

I want to build a meta-database.
This database contains all information about objects to be created.

e.g.
Forms:
id   text  x  y height width ...
1    cust  0  0 500    600

Fields:
id  type  name  x   y   height  width...
1   CEdit name  10  10  50      300

In my app I have to create the
form and within this form all the controls

My question:
there's no problem to create these objects - but:
- how do I interact with these objects?
- how do I know, what's the text of a specific edit control?
- how do I capture and identify the messages sent by any of these objects?

Of course, I can create an application with any controls and VC 6.0 does everything for me. But that's not the way because I want that the description of everything is described externally and the creation is dynamically...
jaroslavAsked:
Who is Participating?

[Webinar] Streamline your web hosting managementRegister Today

x
 
NeveringConnect With a Mentor Commented:
Ok, assuming MFC or object library

Create a CForm object that encapulates the responsibility for creating, draw, etc for your form.
You pass CForm a structure that defines the form that was selected by the user, that has the database info in it, so basically the user is telling you which record to grab in the database table.
You then open the table and start your read and for each field you have a case statement that (based on field type) that creates the field.... say CEdit. Then you create a CField class passing it the CEdit class and some info about the CEdit. Your CField will have to have coordinates, scaling info (if you do that) field type, etc.
Then back in the CForm class where you're still reading the db table, you add the newly created CField class to a CPtrList called something like FieldList. At the end of this function you have only created the classes, but not displayed the fields yet. You CField class can contain methods for displaying, and destroying the fields. The CField class should also have methods for getting the info from the database and putting information into the database.
So to process fields in a batch you do something like this:
This is an example of starting to get rid of the fields in the destructor for CForm. Note that FieldList is an array, meaning that there are several pages to this form.

CField *aField;
POSITION pos;
for (i=0; i<FormPages; i++)
{                  
for (pos = FieldList[i].GetHeadPosition(); pos != NULL; )
{
aField = (CField *)FieldList[i].GetNext(pos);
if (aField->DestroyControlWindow(FALSE))
PageModified[i] = TRUE;
}
}

So basically all you edit controls pass information back and forth to your CField class, and you control you CField class from your CForm, which is controled from your CScrollView class.

Following is some code in the CScrollView that controls some behavior between fields on the form. For example, what do you do when someone hits the tab key, what do you do when they tab into a field that is off the screen?  You can have the controls pass messages to the parent window (the view here) and let the view decide.

Again this is complicated stuff and not something that can be accomplished overnight, good luck.

LRESULT CMyScrollView::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam)
{
      // TODO: Add your specialized code here and/or call the base class
      LRESULT result = 0;
//      int         sx, sy, X, Y, W, H;
      CRect        r;
      CPoint      upperLeft, bottomRight;
      //int                  scrolloffset = 15;
      int                  scrolloffset;

//      HWND        nextChild;
      HWND        aChild = (HWND)(lParam);
      CRect              viewRect;
      CPoint            pt, currScrollpos;
      int                  diff, change;
      BOOL            scrolltop = FALSE;

      int AId = HIWORD(wParam);
      int mycommand = LOWORD(wParam);

      if (!theForm || (AId < ADD_ID_FIRST) || (message != WM_COMMAND))
            goto out;

      switch (mycommand)
      {
              case EN_SETFOCUS:
              case BN_SETFOCUS:
                        if (noScroll) break;
                        if (!aChild) break;
                        if (scrolltop)
                        {
                              currScrollpos.x = currScrollpos.y = 0;
                              ScrollToPosition(currScrollpos);
                              scrolltop = FALSE;
                        }
                        else
                        {
                              ::GetWindowRect(aChild, &r);
                              GetWindowRect(viewRect);
                              currScrollpos = GetDeviceScrollPosition();
                              change = 0;
                              if (r.top < viewRect.top)
                              {
                                    diff = viewRect.top - r.top;
                                    scrolloffset = (r.top - viewRect.top) + (viewRect.Height() >> 1);
                                    currScrollpos.y -= (diff+scrolloffset);
                                    if (currScrollpos.y < 0) currScrollpos = 0;
                                    change++;
                              }
                              if (r.left < viewRect.left)
                              {
                                    diff = viewRect.left - r.left;
                                    scrolloffset = (r.left - viewRect.left) + (viewRect.Width() >> 1);
                                    currScrollpos.x -= (diff+scrolloffset);
                                    if (currScrollpos.y < 0) currScrollpos = 0;
                                    change++;
                              }
                              if (r.bottom > (viewRect.bottom-GetSystemMetrics(SM_CYHSCROLL)))
                              {
                                    diff = r.bottom - viewRect.bottom;
                                    scrolloffset = (r.bottom - viewRect.bottom) + (viewRect.Height() >> 1);
                                    currScrollpos.y += (diff+scrolloffset);
                                    if (currScrollpos.y < 0) currScrollpos = 0;
                                    change++;
                              }
                              if (r.right > (viewRect.right-GetSystemMetrics(SM_CXVSCROLL)))
                              {
                                    diff = r.right - viewRect.left;
                                    scrolloffset = (r.right - viewRect.right) + (viewRect.Width() >> 1);
                                    currScrollpos.x += (diff+scrolloffset);
                                    if (currScrollpos.y < 0) currScrollpos = 0;
                                    change++;
                              }

                              if (change)
                                    ScrollToPosition(currScrollpos);
                        }

                        FocusChildHandle = aChild;      //->HWindow;
                        break;

              case EN_TABNEXT:
                        aChild = (HWND)::GetWindow((HWND)(lParam), GW_HWNDNEXT);
                        if (!aChild)
                        {
                              scrolltop = TRUE;
                              aChild = (HWND)::GetWindow((HWND)(lParam), GW_HWNDFIRST);
                        }

                        if (aChild)
                        {
                               ::SetFocus(aChild);
                               ::SendMessage(aChild, EM_SETSEL, 0, -1);
                        }
                        return result;

              case EN_TABPREV:
                        aChild = (HWND)::GetWindow((HWND)(lParam), GW_HWNDPREV);
                        if (!aChild) aChild = (HWND)::GetWindow((HWND)(lParam), GW_HWNDLAST);

                        if (aChild)
                        {
                        ::SetFocus(aChild);
                              ::SendMessage(aChild, EM_SETSEL, 0, -1);
                        }
                        return result;

              default:
                        break;
       }
      
out:      

      return CScrollView::DefWindowProc(message, wParam, lParam);
}
0
 
KangaRooCommented:
You want the application to fetch form layout from this db or create resource scripts from the db?
0
 
inprasCommented:
Hi jaroslav
lets take a example of a edit box U have created
in .h file
CEdit edit;

in implimentation file
CRect editrect(100,270,220,290);
edit.Create(WS_CHILD | WS_VISIBLE |WS_BORDER|ES_CENTER|ES_AUTOHSCROLL,editrect,this,200);

1. To interact with the object U can do like this
U have id lets say 200 which U have used while creating.
U can use the variable to interact say U want to set some text then
edit.SetWindowText("MyText");
2.to know text of this edit control
CString strMyString;
edit.GetWindowText(strMyString);

3.To capture the messages sent U have to do the following

a. in UR BEGIN_MESSAGE_MAP code

put
ON_EN_KILLFOCUS(200, OnKillfocusEdit1)

and in the header file add entry

afx_msg void OnKillfocusEdit1();

as soon as kill focus happens the function OnKillfocusEdit1(){} will be called.

Hope this helps
inpras



0
Never miss a deadline with monday.com

The revolutionary project management tool is here!   Plan visually with a single glance and make sure your projects get done.

 
akalmaniCommented:
Hi inpras !!
   But he/she doesn't know what type of control it is, he/she reads it from the database.
 Am i right jaroslav
0
 
jaroslavAuthor Commented:
Inpras, thank's for your feedback.

What akalmani wrote, is correct.

Just my db knows what kind and how much objects I am to create. There can be different controls (e.g. 5 edit boxes, 2 buttons, 3 list views, ...). The content of these controls is linked in my meta-database to real database fields (e.g. there is a sql-command: select id, name, address from customers
the db fields are mapped to controls:
- Form:
name=customers x=0 y=0 h=500 ...
- Fields:
ID 1: name=Customer Name type=CEdit x=10 y=10 ...
ID 2: name=Customer Address type=CEdit x=10 y=80 ...

So I'll have to create all these controls, perform my sql-command, set the values of the controls to the corresponding value from my query.

Then I'll have to catch all the modifications made in any of the controls and write them back to db:
update customers set name=<value of corresponding CEdit control (ID=1 - name = Customer Name)>

Hope, there's a way for that!

regares - jaroslav
0
 
KangaRooCommented:
Yep, it's called MS Access ;) ,Just kidding, even this kind of control repository is not in its trick-box.
0
 
NeveringCommented:
Obviously, this is not a trivial problem. My application does this, and the way that I've implemented it is with a Field object that keeps track of all the Edit controls (various types).
The Field stores a master copy of the data. The Field is also responsible for reads and writes, creating the fields, resizing, etc.
Then I keep a list of these fields in the Form object and iterate thru the fields when I need to access them. There are problems such as tabbing and handling other Windows messages at the edit control and keeping track of the which field you're in (which isn't really important), just has to appear correct to the user.  You do this by sending messages to the parent and let the parent handle the tabbing etc, by sending messages back.
When the form closes, you then iterate thru the lists to close everything.
Good luck, hopefully I've given you enough of an idea to get you going.
0
 
jaroslavAuthor Commented:
Thank's for the feedback.

The described way sounds good - but I need an example, part of a source doing that.

jaroslav
0
 
NeveringCommented:
You're welcome. But the source to describe it would be too large. There are many interrelated classes, such as fonts, different styles of edit boxes, such as single line edit/ multiline, checkboxes, popups, etc.

Good luck with your hunt.
0
 
bholzCommented:
You could do like inpras said and use ranges for your ID's:

100-199 = Edit
200-299 = List
....

Regards,

Bernd
0
 
jaroslavAuthor Commented:
An example would be great. I need a logical walkthrou in order to be able to construct the app.

Hey, I don't have much more points to give!

Or, is that, what I want so extraordinary or complicated?

I started with C++ some months ago (I worked with PowerBuilder) just because I like this language and thougt, that I could do anything, things I wasn't able to do with other languages. Sometimes, it needs just a litte help...

thank's and regards

jaroslav
0
 
KangaRooCommented:
As stated before, it's quite complicated.
You may want to take a look at the patterns book "Design patterns, elements of reusable, object oriented software" from Gamma, Helm et al (also know as the GoF).
0
 
NeveringCommented:
Tell me what your app what to do, and I'll try to give you a brief walk thru.




0
 
jaroslavAuthor Commented:
Nevering, thank's for your reply.

Usally, I have programs with a static design. After having written an application, I had to add some fields, modify the position of existing fields, grids, buttons...

Most of my applications are designed for customers like wholesalers, let's say, database-application with quite a known set of functions, e.g.:
- work with simple data (customer, item, supplier...)
- reports
- forecast
- navigation (first record, next record..., insert, update, delete, ...)

As you can see from earlier messages I quoted, I'd like to describe the forms, fields, grids, validations, relations in a separate part of my db - in configuration-tabels.

My goal:
- user starts app
- select what he/she wants to do (e.g. add customer)
- what will happen, is described in my db (load form, load fields, connect to table(s), load db-fields into form-fields)
- user makes modifications
- request for saving data
- validation
- update table(s) from form-fields

Reading the required values from these configuration-tables, that's not my problem. But how do I create all the forms, fields, etc., dynamically and I still do know, what the user is doing, which fields the user is modifying and how can I create shortcuts for dynamically created fields.

Thank's for your effort trying to help me.

Regards

jaroslav

0
 
jaroslavAuthor Commented:
Sorry for my late reply - have been out of work for a while...

I had a look at your code and tried to build my own code using your input.

It's a lot of work - but it will work this way.

Thank's a lot.

Regards - jaroslav
0
All Courses

From novice to tech pro — start learning today.