Help : Details of the opened dialogs/windows in application

Help : Details of the opened dialogs/windows in application

Postby anserkk » Tue Sep 09, 2008 5:04 am

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
anserkk
 
Posts: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby xProgrammer » Tue Sep 09, 2008 6:23 am

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
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby anserkk » Tue Sep 09, 2008 7:33 am

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
anserkk
 
Posts: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby xProgrammer » Tue Sep 09, 2008 11:52 am

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
xProgrammer
 
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Postby anserkk » Tue Sep 09, 2008 12:26 pm

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
anserkk
 
Posts: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby James Bott » Tue Sep 09, 2008 4:09 pm

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  Expand view
   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  Expand view
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  Expand view
//--- 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
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby anserkk » Wed Sep 10, 2008 5:08 am

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: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby anserkk » Fri Sep 26, 2008 10:31 am

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
anserkk
 
Posts: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby James Bott » Fri Sep 26, 2008 8:41 pm

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
James Bott
 
Posts: 4840
Joined: Fri Nov 18, 2005 4:52 pm
Location: San Diego, California, USA

Postby anserkk » Sat Sep 27, 2008 4:56 am

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
User avatar
anserkk
 
Posts: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby Rochinha » Sat Sep 27, 2008 5:47 am

See if these codes to help you.

with this code you can open tables without closing them:
Code: Select all  Expand view
#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  Expand view
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.
Rochinha
 
Posts: 310
Joined: Sun Jan 08, 2006 10:09 pm
Location: Brasil - Sao Paulo

Postby James Bott » Sat Sep 27, 2008 5:50 am

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/homepages/jbott/program.htm

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

Postby anserkk » Sat Sep 27, 2008 8:17 am

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  Expand view
   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  Expand view
#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
User avatar
anserkk
 
Posts: 1332
Joined: Fri Jun 13, 2008 11:04 am
Location: Kochi, India

Postby Rochinha » Sun Sep 28, 2008 6:43 am

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
Rochinha
 
Posts: 310
Joined: Sun Jan 08, 2006 10:09 pm
Location: Brasil - Sao Paulo

Postby Antonio Linares » Sun Sep 28, 2008 9:21 am

Anser,

This code may help you:
Code: Select all  Expand view
#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
User avatar
Antonio Linares
Site Admin
 
Posts: 42080
Joined: Thu Oct 06, 2005 5:47 pm
Location: Spain

Next

Return to FiveWin for Harbour/xHarbour

Who is online

Users browsing this forum: Google [Bot] and 76 guests