Help : Details of the opened dialogs/windows in application

User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Help : Details of the opened dialogs/windows in application

Post by anserkk »

Friends,

Is there any function which returns or let us know the details of the opened windows and dialogs in my app. (Pls note : Details of opened windows and dialogs in my app)

I am planning to give my users both Modal and non modal dialogs in my app. which means there can be multiple instances of the same window in my app. But I should be able to restrict users from opening multiple instances of certain dialogs/windows for eg. the DBF Re-indexing window should be restricted. It can have only instance and once the user click on the reindex dialog, my app should check whether any dialogs/windows are still open. If other dialogs/windows are open, then my app should warn the users about the opened windows.


Regards

Anser
Last edited by anserkk on Tue Sep 09, 2008 11:21 am, edited 1 time in total.
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Anser

Is your application single user? If not then I don't think that determining what windows your application has open would do the trick. You would need to use flags and / or locks. I would suggest such an approach for a single user scenario also as it would be extensible.

Regards
xProgrammer
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Post by anserkk »

xProgrammer wrote:Hi Anser

Is your application single user? If not then I don't think that determining what windows your application has open would do the trick. You would need to use flags and / or locks. I would suggest such an approach for a single user scenario also as it would be extensible.

Regards
xProgrammer
My application is not a single user. It is supposed to be run on a Network with multiple users.

I am porting my existing Clipper 5.01 application to FWH. I don't want to restrict my users from having multiple windows opened simultaneously to a certain extent. Because of this reason I want to reduce the Modal Dialog as much as possible. For eg. A user who is already preparing the invoice need to check for an Item in the item Master. I want my user to open the Item Master even when the invoice preperation screen is open.

Why the user should be restricted from having such facilities, which I beleive is one of the major advantages of Windows GUI app over a DOS based Clipper application. I also understand that there are lot of complications as a programmer by allowing the user to open multiple windows.

I don't open all the DBF files from the Main Fucntion itself, instead I open only the required DBf files in each and every Menu/fucntions, and I close only the DBF files opened in that particular function.

I open DBF files with different unique ALIAS names in each and every function so that there will not be any clash with the work area.

But I don't want the same user to open multiple instances of the Invoicing window. For this reason I need to know whether the user is trying to open a window which is already remaining opened.

Hope u understand my requirement. I don't know whether I am right or not. I welcome other ideas too.

Regards

Anser
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Post by xProgrammer »

Hi Anser

Thanks for explaining what you want to achieve. If you want to control the number of times (typically max 1) that a user can open a specific window then there are a few possibilities.

If your application is object oriented (uses classes) then using a CLASSDATA property would be ideal. For example in the invoicing window class have a property:

CLASSDATA nCount

Then before opening the window check the value of ::nCount. If it is 0 increment to 1 and open the window. If its one then don't open what would be a second invoicing window. When you close the window decrement ::nCount - maybe in a VALID clause.

If you aren't using classes you can do the same thing - you just need to decide on the variables you need to keep the count and how you tie a particular window to a particular count variable. Not at all difficult - it just depends on how you want to do it.

You might, for example, have an array of counts. You could then have a define for each window so you might have

#define id_INVOICE_WINDOW 4

so aWindowCount[id_INVOICE_WINDOW] would be the count variable you increment / decrement and have a max value for ( 1 if you only want to allow a single invoicing window). That way yoy could write some generic code to be called as part of each window you wish to control. Something like

CanOpenWindow( nWindowID )

CloseWindow( nWindowID )

If you want to handle maximums other than 1 you might want another array aWindowMaxCount[] to hold these maximum values.

Happy Programming
xProgrammer
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Post by anserkk »

Thankyou xProgrammer,

That's a very useful input for me from your side. I shall apply it my work

Would have been better if FiveWin had some functions like

IsWindowDefined(WindowName) -> Returns .T. or .F. if Window is already open

aWindList:=GetOpenWindows() -> Returns Array of all OpenedWindows

Regards

Anser
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Anser,

Programmers that are converting DOS apps to Windows seem to always be enamored with the possibilities of MDI. However, it is it my opinion that MDI interfaces for databases are a poor design. MDI was invented for applications like word processing where all the windows are the same and are usually full screen.

The problem with using MDI in database applications is that every window is different and to have two visible at the same time is often difficult or impossible. Also, it usually requires a lot of manual manipulation by the user which is wasted effort.

If you are interested in more on this topic I suggest getting a copy of any of Alan Cooper's books "About Face The Essentials of User Interaction Design" (there are three editions).

If you still want to design MDI app, the information below may answer some of your questions. This is from my old notes. Use it at your own risk.

Regards,
James

-----------------------------------------------------
Checking for MDI child windows

If you need to check for MDI child windows you can look at oWnd:oWndClient:aWnd which is an array of MDI child windows objects.

You can check the captions:

Code: Select all

   oWnd:oWndClient:aWnd[1]:cCaption
Here is an example of counting the number of a certain type of MDI windows that are open.

Code: Select all

function WndCount(cCaption)
   local i:=0,nCount:=0,oWnd:=wndMain()
   if valtype(oWnd:oWndClient:aWnd)!=nil
      for i=1 to len(oWnd:oWndClient:aWnd)
         if oWnd:oWndClient:aWnd[i]:cCaption = cCaption
           nCount++
         endif
      next
   endif
return nCount
Here is a function to prevent opening more than one copy of a MDI child window. It also brings the window to the top and set the focus to it.

Code: Select all

//--- Sets focus to child MDI window with cTitle
static function wndSetFocus(cTitle)
   local i:=0,lSuccess:=.f.
   cTitle:=upper(cTitle)
   for i=1 to len(wndMain():oWndClient:aWnd)
      if upper( wndMain():oWndClient:aWnd[i]:cCaption )=cTitle
         wndMain():oWndClient:aWnd[i]:setFocus()
         lSuccess:=.t.
      endif
   next
return lSuccess
Then you can do something like this for a menu or button:

...ACTION if( ! wndSetFocus("Order"), TOrder():new():browse(),)
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Post by anserkk »

Mr.James,

Thank you for the code and for your opinion and views on MDI. I am in a very early development stage of my app. I am experimenting and learning few things using FWH.

Regards

Anser
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Post by anserkk »

Hi,

In an MDI environment OR DIALOG NOWAIT environment, I understand that the program execution does not pause after the ACTIVATE WINDOW oWnd and the next line in the prg will get executed which probably will be the Return NIL statement.

Because of this reason all the private & local variables will die as the statement RETURN NIL quits the function.

The GETs used in the MDICHILD window is giving VARIABLE does not exist error because I have used private & Local variables

Does that means that you will have to use either Static variables or Public variables. I would like to know how this situation is handled. As far as I know we should use less static and public variables. (Correct me if I am wrong.)

As a programmer's point of view it is easy or the effort is less to develop DIALOG based apps when compared to MDI, but as a user of the app. it applies lot of restriction to the user. A user will not be able to even minimise the app's main screen without quiting the DIALOG.
The above is just one of the examples.

I would like to get some suggestion, hints and views in this regard to try writing an MDI environment application

Regards

Anser
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Anser,

I would avoid privates like the plague--they often create very hard to find bugs. Locals will remain as long as they are in scope. As long the dialog or window is still in use, then the variables are still in scope. They will go out of scope when the dialog/window is closed. Resource objects like fonts and bitmaps need to be ended in the dialog/window's VALID clause.

>As a programmer's point of view it is easy or the effort is less to develop DIALOG based apps when compared to MDI,

You shouldn't even be asking this question. The question is, "What is a better interface design for the user?" Our job is to provide software to make the user's job easier and faster--even if it is more work for us.

Regards,
James
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Post by anserkk »

Dear Mr.James,

Thank you for your views & suggestions.

Let me make a summary statement of what I have understood about the tips of developing a database app in an MDI environment.

1. Never use Private variables
2. use only local variables
3. If the variable are required in sub functions then pass those variables as parameters to sub fuctions.
4. objects like fonts,bmp's which needs to be ended should be used via the windows valid clause.
5. Closing of DBF files opened in that particular function should be closed using the Windows Valid clause.

Mr.James, I never open all the DBF files together during the app start up. Instead I open the required DBF files only in each and every function and I close all the DBF opened in that particular fucntion when I quit the function.

Regards

Anser
Rochinha
Posts: 309
Joined: Sun Jan 08, 2006 10:09 pm
Location: Brasil - Sao Paulo
Contact:

Post by Rochinha »

See if these codes to help you.

with this code you can open tables without closing them:

Code: Select all

#command OPEN <(db)>                                                    ;
             [VIA <rdd>]                                                ;
             [ALIAS <a>]                                                ;
             [<new: NEW>]                                               ;
             [<ex: EXCLUSIVE>]                                          ;
             [<sh: SHARED>]                                             ;
             [<ro: READONLY>]                                           ;
             [INDEX <(index1)> [, <(indexn)>]]                          ;
       => if Select( <(db)> )==0                                        ;
         ;   dbUseArea( <.new.>, <rdd>, <(db)>, <(a)>, if(<.sh.> .or. <.ex.>, !<.ex.>, NIL), <.ro.>, 0 )[; dbSetIndex( <(db)> )];
         ;else                                                          ;
         ;   dbSelectArea( <(db)> )                                     ;
         ;end

   OPEN clients  SHARED NEW INDEX clients
   OPEN products SHARED NEW INDEX products 
with this code you can better control the opening of windows:

Code: Select all

function main()
   ...
   PUBLIC oChildWnd:=nil, cTitle, nChildNum
   ...
   return .t.

function module01( oWnd )
   PUBLIC lFecha := .f.
   //
   cTitle    := "Clients"
   nChildNum := 1               // Unique number for this window
   if lChildWnd                 // if any window is open...
      if nChildWnd == nChildNum // If the window is the same...
         return nil             // returns without modifying
      endif
      lFecha    := .t.          // free last window to close
      dbCommitAll()             // commit all changes
      dbCloseAll()              // free all areas
      oChildWnd:end()           // close last window
      oChildWnd := nil          // free object window
   endif
   //
   nChildWnd := nChildNum       // Renew a window control
   lChildWnd := .t.             // There window open
   DEFINE WINDOW oChildWnd TITLE cTitle MDICHILD STYLE nOr(WS_CHILD,DS_SYSMODAL,DS_MODALFRAME) 
   ACTIVATE WINDOW oChildWnd MAXIMIZED ON INIT BuildDialog( oChildWnd )
   return nil

function module02( oWnd )
   PUBLIC lFecha := .f.
   //
   cTitle    := "Clients"
   nChildNum := 2               // Unique number for this window
   if lChildWnd                 // if any window is open...
      if nChildWnd == nChildNum // If the window is the same...
         return nil             // returns without modifying
      endif
      lFecha    := .t.          // free last window to close
      dbCommitAll()             // commit all changes
      dbCloseAll()              // free all areas
      oChildWnd:end()           // close last window
      oChildWnd := nil          // free object window
   endif
   //
   nChildWnd := nChildNum       // Renew a window control
   lChildWnd := .t.             // There window open
   DEFINE WINDOW oChildWnd TITLE cTitle MDICHILD STYLE nOr(WS_CHILD,DS_SYSMODAL,DS_MODALFRAME) 
   ACTIVATE WINDOW oChildWnd MAXIMIZED ON INIT BuildDialog( oChildWnd )
   return nil

STATIC FUNCTION BuildDialog( oChild )
   LOCAL oDlg
   //
   DEFINE DIALOG oDlg RESOURCE "YOUR_DIALOG" OF oChild
   ...
   ACTIVATE DIALOG oDlg NOWAIT ; 
             ON INIT ChangeParent( oDlg, oChild ) ;
             CENTER 
   return .t.

STATIC FUNCTION ChangeParent( oDlg, oChild )
   ...
   return .t.
User avatar
James Bott
Posts: 4654
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA
Contact:

Post by James Bott »

Anser,

Yes to all points.

However, if you build your own class then all of the points 2-6 can be handled much easier. You can use class data and and an End method. With class data you don't need to pass all the needed variables to a method. With an End method you can end all resource objects and databases. For more information about this read the articles on object-oriented programming my website.

http://ourworld.compuserve.com/homepage ... rogram.htm

Regards,
James
User avatar
anserkk
Posts: 1280
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Post by anserkk »

Mr.James,

Thanks for the information. My level of knowledge on FWH and OOPS has to improve much more to make a CLASS of my own as you said. I am just reading the material in your web site.

Mr.Rochina,

I could not understand the purpose of the function ChangeParent( oDlg, oChild ) and what exactly it does and the advantage. Excuse me if my question is very silly, I am only a beginner in FWH as well as in developing Windows based apps.

Code: Select all

   ACTIVATE DIALOG oDlg NOWAIT ;
             ON INIT ChangeParent( oDlg, oChild ) ;
             CENTER
   return .t.

STATIC FUNCTION ChangeParent( oDlg, oChild )
   ...
   return .t. 
If I am not wrong
with this code you can open tables without closing them:
1) Regarding the closing of DBF files, you are taking a different approach ie instead of closing DBF's while closing the window, you are trying to close all open DBF files during the initialisation/opening of each and every module. Suppose a user opens a child window, the required DBF files are opened along with the module, but the files are left open till the user opens an another child window. And it has nothing to do with the command OPEN which you have given. Am I right ?

Code: Select all

#command OPEN <(db)>                                                    ;
             [VIA <rdd>]                                                ;
             [ALIAS <a>]                                                ;
             [<new: NEW>]                                               ;
             [<ex: EXCLUSIVE>]                                          ;
             [<sh: SHARED>]                                             ;
             [<ro: READONLY>]                                           ;
             [INDEX <(index1)> [, <(indexn)>]]                          ;
       => if Select( <(db)> )==0                                        ;
         ;   dbUseArea( <.new.>, <rdd>, <(db)>, <(a)>, if(<.sh.> .or. <.ex.>, !<.ex.>, NIL), <.ro.>, 0 )[; dbSetIndex( <(db)> )];
         ;else                                                          ;
         ;   dbSelectArea( <(db)> )                                     ;
         ;end

   OPEN clients  SHARED NEW INDEX clients
   OPEN products SHARED NEW INDEX products 
2. At any point of time there can be only one child window opened ( I am NOT talking about the Openening of a Child window which is already Open)

If you don't mind I would like to get more samples in this regard.

I have not tested your code.

Regards

Anser
Rochinha
Posts: 309
Joined: Sun Jan 08, 2006 10:09 pm
Location: Brasil - Sao Paulo
Contact:

Post by Rochinha »

Anserkk,
anserkk wrote:I could not understand the purpose of the function ChangeParent( oDlg, oChild ) and what exactly it does and the advantage...
It´s only one explanation, without functioning.
anserkk wrote:Regarding the closing of DBF files, you are taking a different approach ie instead of closing DBF's...
Yes. This avoids mistakes of openness.

Take a look in this code and sample in http://www.5volution.com/forum/custxbrw.zip
User avatar
Antonio Linares
Site Admin
Posts: 37481
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain
Contact:

Post by Antonio Linares »

Anser,

This code may help you:

Code: Select all

#include "FiveWin.ch"

function Main()

   local oDlg

   DEFINE DIALOG oDlg TITLE "Modal" FROM 3, 3 TO 15, 40

   @ 2, 2 BUTTON "Search" ACTION MsgInfo( SearchNonModal( "Non modal" ) )

   @ 2, 10 BUTTON "Create" ACTION CreateNonModal()

   ACTIVATE DIALOG oDlg ;
      ON INIT CreateNonModal()

return nil

function SearchNonModal( cNonModalTitle )

return AScan( GetAllWin(), { | o | ValType( o ) == "O" .and. ;
              Upper( o:ClassName() ) == "TDIALOG" .and. o:cTitle == "Non modal" } )

function CreateNonModal()

   local oDlg

   if SearchNonModal( "Non modal" ) != 0  // the non modal is already created
      MsgAlert( "already exists" )
      return nil
   endif    
    
   DEFINE DIALOG oDlg TITLE "Non modal"
   
   ACTIVATE DIALOG oDlg NOWAIT CENTERED
   
return nil    
regards, saludos

Antonio Linares
www.fivetechsoft.com
Post Reply