(unlicensed FireFly user evaluating PB8/FireFly)
Can someone please fill me in on the correct steps to building an MDI application. I have gone over and over the help under "Working with MDI Forms" and the sample MDI application. Sorry about the length of this posting.
I am not a VB programmer but have used a product called Clarion for Windows and a GUI designer for a multi-valued product so I do understand the concepts at least a little. My 20 years of subroutine coding is probably blocking my ability to see what is right in front of my eyes, though. My goal is to replace a currently running (beta) product that uses an MDI GUI interface through AccuTerm.
The "Working with MDI Forms" help topic states:
===================================
An MDI application has three kinds of windows: a frame window, an MDI client window, as well as a number of child windows. The frame window is like the main window of the application: it has a sizing border, a title bar, a system menu, a minimize button, and a maximize button.
====================================
Yet, the MDI sample only contains 2 forms.
--------------------------------------------------------------------
1)
This terminology has thrown me off somewhat. Is "window" here in the help referencing a "form" as used by FF?
-------------------------------------------------------------------
Continuing on... Later the help topic states:
======================================
To create an MDI application you need to add a new or existing MDI Form to your application. You do this through the "Project" menu, "Add MDI Form" option. The application can only have one MDI form although it can have many MDI child forms.
========================================
I have created what I hope is the main form using the steps described: Project/New MDI Form. (I found I had to leave the Caption property as "MDIform" or the compile failed).
--------------------------------------------------
2)
I am confused with the comment above about a "frame window" and an "MDI client window". Should I be expecting to build a minimum of 3 forms for an MDI application (frame/client/child)? I have not found any further explanation for how to set up these “three kinds of windows.†What am I missing and how do I find the instructions?
------------------------------------------------
I created two child forms using the "New Form" button. Reviewing the MDI sample, I noticed that the "MDIChild" property was set to true, so I set both of these forms MDIChild property to true.
------------------------------------------------------------
3)
It may seem obvious after you've done it a dozen times, but I have to admit to being quite flummoxed. Is this process what is meant by creating a child window?
-----------------------------------------------------------
In reviewing all of the MDI forum postings I ran across some code similar to :
hwndfirstwindow = FirstWindow_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
so... I added lines of code to MDIFORM_WM_CREATE such as:
Local hwndwindow As Dword
hwndwindow = frmChild1_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
hwndwindow = frmChild2_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
------------------------------------------------------------
4)
Can I assume this is the correct approach when I want both forms visible and active at start-up?
------------------------------------------------------------
In my first attempt with three forms (MDI client + 2 child), the program compiled but nothing at all appeared to run. If I set MDIChild to false, the child would open when I ran the application but with both child-forms properties set to true, I get nothing. So, I started over from scratch and the second attempt does open the windows. The first version shows up running in the WINDOWS Processes list when I click CTRL-ALT-DEL. I have to kill it from the windows Task Manager to do any additional compilation.
--------------------------------------------------------------
5)
For the life of me I cannot see any difference between the two projects. Any idea where to look for why my first attempt is not opening anything at all. I hate to just abandon it without knowing why it fails.
--------------------------------------------------------------
I would like the two child windows to open with them being tiled/offset by their border width or so down and to the right. I thought that would happen by setting the Startup Position property for the two child forms to "2-Windows Default". However, the child windows appear directly over the top of each other flush left against the left border of the container window. (I reviewed the help topic under "Handling Multiple Forms" and did not see any positioning parameters)
-----------------------------------------------------
6)
Do I have to pass some sort of positioning parameters when these forms are displayed? What does Windows Default mean, as this was what I recall using for this purpose in the past?
-----------------------------------------------------
That is it for now. I look forward to the Version 3 tutorials. I have agonized for 2 days to get to the point I'm at. I really want the FF/PB8 option to work out as I do not want the "bloat code" generated by Clarion. I really hope I can get an application built using FF in the month or so I have (evenings and weekends).
============================================
btw... I will have a number of tab controls each containing grid controls inserted into each of the child forms. If anyone can point me to a step-by-step explanation of how to construct these controls and how to code to manage them I would be most appreciative.
Since you've been kind enough to read this far, many thanks for your patience. :)
Dwight
Hi Dwight,
Happy to have you here. Ask as many questions as you like. I know that myself and the folks around here will try to help as much as possible.
Personally, I don't use MDI applications at all anymore. My impression is that these types of apps are reducing in popularity. Check out: http://en.wikipedia.org/wiki/Multiple_document_interface
Quote from: Dwight Scoles
An MDI application has three kinds of windows: a frame window, an MDI client window, as well as a number of child windows. The frame window is like the main window of the application: it has a sizing border, a title bar, a system menu, a minimize button, and a maximize button.
I can see why this would be confusing. For convenience, FireFly handles the frame and client windows as one. If you look at the MDIForm that you add to the project you can see in the Properties a couple of settings for the client window (e.g. "(MDIClient)", and "AutoSizeClient"). Therefore, in reality, you will normally have the MDIForm and a second form for the child for a total of two forms, not three.
QuoteI have created what I hope is the main form using the steps described: Project/New MDI Form. (I found I had to leave the Caption property as "MDIform" or the compile failed).
You should be able to change the Caption property without causing a compile to fail. I just created an MDI program from scratch and changed the Caption and it compiled correctly.
However, I did notice that if I click on "MDIClient" in the dropdown list in the code editor it creates a message handler for WM_CLOSE. If I try to compile with that handler (MDIFORM_MDICLIENT_WM_CLOSE) in the code editor then a GPF occurs :( That is certainly a bug that needs to be addressed - sorry.
QuoteIt may seem obvious after you've done it a dozen times, but I have to admit to being quite flummoxed. Is this process what is meant by creating a child window?
I haven't heard the word
flummoxed used in a long time! Good one. The MDI child windows need to have the MDIChild property set to True. This ensures that the form will be displayed in the MDIClient area of your MDIForm.
QuoteIn reviewing all of the MDI forum postings I ran across some code similar to :
hwndfirstwindow = FirstWindow_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
so... I added lines of code to MDIFORM_WM_CREATE such as:
Local hwndwindow As Dword
hwndwindow = frmChild1_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
hwndwindow = frmChild2_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
Can I assume this is the correct approach when I want both forms visible and active at start-up?
Yes. That will work. However, you do not have to create two separate Forms unless they will contain different controls. For example, if your frmChild1 contains your grid, etc, and you want multiple copies of that Form to display then you would do the following:
Local hwndwindow As Dword
hwndwindow = frmChild1_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
hwndwindow = frmChild1_Show( HWND_MDIFORM_MDICLIENT, %FALSE )
Basically, you are creating two instances of the same Form. Now if your second child Form contains different information that you want to display then your approach is exactly what you need.
QuoteFor the life of me I cannot see any difference between the two projects. Any idea where to look for why my first attempt is not opening anything at all. I hate to just abandon it without knowing why it fails.
I really wouldn't know unless I had both projects here so I could trace their execution to know why one did not unload from memory.
Quote
I would like the two child windows to open with them being tiled/offset by their border width or so down and to the right. I thought that would happen by setting the Startup Position property for the two child forms to "2-Windows Default". However, the child windows appear directly over the top of each other flush left against the left border of the container window. (I reviewed the help topic under "Handling Multiple Forms" and did not see any positioning parameters)
You are trying to display both child forms in the WM_CREATE handler. When WM_CREATE fires, Windows can not accurately position your child forms. You need to wait until after the WM_CREATE finishes executing. Here is the code that you need.
%MSG_DISPLAY_FORMS = %WM_USER + 1
'------------------------------------------------------------------------------------------------------------------------
Function MDIFORM_WM_CREATE ( _
hWndForm As Dword, _ ' handle of Form
ByVal UserData As Long _ 'optional user defined Long value
) As Long
' Post a custom message to the Form to tell it to display the two
' initial MDI Child Forms. We need this to happen AFTER the WM_CREATE
' finishes executing rather than doing it in the WM_CREATE. This is
' why we use a PostMessage (post a message to the Form's message queue).
PostMessage hWndForm, %MSG_DISPLAY_FORMS, 0, 0
End Function
'------------------------------------------------------------------------------------------------------------------------
Function MDIFORM_CUSTOM ( _
hWndForm As Dword, _ ' handle of Form
wMsg As Long, _ ' type of message
wParam As Dword, _ ' first message parameter
lParam As Long _ ' second message parameter
) As Long
Select Case wMsg
Case %MSG_DISPLAY_FORMS
frmChild1_Show HWND_MDIFORM_MDICLIENT, %FALSE
frmChild2_Show HWND_MDIFORM_MDICLIENT, %FALSE
End Select
End Function
Quote
That is it for now. I look forward to the Version 3 tutorials. I have agonized for 2 days to get to the point I'm at.
I understand and feel your pain. Tutorials, sample projects, and better documentation is definately at the top of the FireFly 3 project goals. The problem is that there is so much in Windows that it is impossible to describe everything in the level of detail that beginners would like.
Quote
btw... I will have a number of tab controls each containing grid controls inserted into each of the child forms. If anyone can point me to a step-by-step explanation of how to construct these controls and how to code to manage them I would be most appreciative.
TabControls are easy to use in FireFly.
(1) Create a TabControl on your Form.
(2) Create a Form for each of the Tabs on your TabControl. Set the "TabControlChild" property to True for each of these Forms.
(3) You now need to "link" each Tab on your TabControl to the child form that will display on that tab when the tab is clicked. To do this, you need to click on the "(Custom)" property of the TabControl. Using the dialog that pops up you can add/remove tabs and their captions/icons. You also select the child tab to display when the tab is clicked.
(4) You may need to resize your child tab control forms so that they fill the entire area of your tab control.
Thanks Paul,
I implemented the "show" commands in the MDIFORM_CUSTOM function. It worked great! Your response was quite extensive. My spouse says I should send you flowers! :D
(I don't know how to include a picture or I would)
I have a couple of questions (of course) from your code example...
1) You use %WM_USER to create %MSG_DISPLAY_FORMS. a) Why use that equate? b) Why not a variable that is incremented to allow creation of other custom message IDs? c) Is there a list of these $WM equates some place?
2) You positioned the line
%MSG_DISPLAY_FORMS = %WM_USER + 1 before the function MDI_FORM_WMCREATE. Why not just use the %WM_USER equate within the function?
3) In my app, the MDI interface is used as a shell. The application is not true MDI though. My goal is to create a container for two forms. There will only be one instance of each of these two forms. They both exist or they both go away. These two forms together form the main interface for my application. The user needs the flexibility to overlap these two forms or to place them side-by-side on an expanded screen. I'm not sure how that can be done in a TAB container environment. Other maintenance and display forms will then be spawned off of these, but again only one at a time. In my current application I control very closely which forms exist so that I can manage content and user behavior more closely. If you consider there is a better design I'm all ears (Like Ross Perot)!
4) Looking for a recommendation: My grid implementation is quite limited in needed functionality. I need to show a title (row one) on each grid (3 grids on one of the forms, a TAB container with 6 tabs and one grid filling each of the forms in those 6 tabs on the second form). Each grid only has from 3 to 6 columns. The important part is that I want to control the order of entry. If they click on row 3 and row 2 is empty, I switch them back to row 2. If they click on column 4 and column 2 is empty, I switch the focus back to column 2, etc.. Column 1 is a sequence number (label) ranging from 1 to the number of populated rows. I load the sequence after the user completes the row. If they leave the row without completing it, the row is blanked out after a warning message.
It is all quite simple except for the entry interaction.
+----------------------------------------------------+
| ##| title...| title2...| title3..........................|
| . 1 | Stuf..| Stuff....| Some more stuff.........|
| . 2 | Stuf..|............| <click> .......................| <-switch to col3
+----------------------------------------------------+
Just so I don't spend days going down the wrong path, what would you recommend as the simplest grid or multi-column interface that would allow me to do this job with the least custom coding.
Thanks for the great support!
Quote from: Dwight Scoles
1) You use %WM_USER to create %MSG_DISPLAY_FORMS. a) Why use that equate? b) Why not a variable that is incremented to allow creation of other custom message IDs? c) Is there a list of these $WM equates some place?
The use of %WM_USER is standard in Windows programming. Values above %WM_USER will not interfere with other Windows messages that are received by a Control or Form.
There are literally hundreds and hundreds of equates defined in the various *.inc include files in your \WinAPI directory of your PowerBASIC installation.
Quote
2) You positioned the line
%MSG_DISPLAY_FORMS = %WM_USER + 1 before the function MDI_FORM_WMCREATE. Why not just use the %WM_USER equate within the function?
That's easy... numeric equates are global in scope so I define them outside of any sub/function for greater clarity. Having the equate at the top of the source code also makes it easier to find and alter if necessary.
Quote
3) In my app, the MDI interface is used as a shell. The application is not true MDI though. My goal is to create a container for two forms. There will only be one instance of each of these two forms. They both exist or they both go away. These two forms together form the main interface for my application. The user needs the flexibility to overlap these two forms or to place them side-by-side on an expanded screen. I'm not sure how that can be done in a TAB container environment. Other maintenance and display forms will then be spawned off of these, but again only one at a time.
Given the need to overlap the Forms or display side-by-side then I would say that the MDI approach is just as good as anything else. :)
Quote
4) Looking for a recommendation: My grid implementation is quite limited in needed functionality... Just so I don't spend days going down the wrong path, what would you recommend as the simplest grid or multi-column interface that would allow me to do this job with the least custom coding.
I usually roll my own grid like controls when I need them based on a lot of custom drawing, etc... so I don't use any commercially available grid. I do know that the two most popular grid controls for PB'ers are probably eGrid32 and SIGrid. You would need to evaluate both for yourself to see what one is better for your purpose. I have included demo versions of both grids with FireFly.
QuoteThanks for the great support!
You are very welcome :) I try my best. Sometimes I have answers, other times I am in the dark just about as much as anyone else.
I appreciate the help. It seems you have cloned yourself to handle all of the questions users ask on the forum. You're the Best!
Dwight