Page 1 of 1

FWH 1808: Dialog as Mdichild

Posted: Mon Oct 22, 2018 5:42 pm
by nageswaragunupudi
Introducing enhanced command:

Code: Select all

ACTIVATE DIALOG oDlg AS MDICHILD
 
While developing applications in MDI environment, we may like to design some mdichild windows with a resource editor, but it is not directly possible. So, we adopt a workaround by first creating a dialog from resources and then transferring the controls to mdichild.

Present method:

A typical implementation looks like this:

Code: Select all

   DEFINE DIALOG oDlg RESOURCE "resname"
   // <REDEFINE all controls>
   DEFINE WINDOW oWnd MDICHILD OF WndMain()

   ACTIVATE DIALOG oDlg NOWAIT ON INIT ( ChangeParent( oDlg, oWnd ) )
   oDlg:End()

   ACTIVATE WINDOW oWnd

//---------------------------------------//

static function ChangeParent( oDlg, oWnd )

   local oControl

   for each oControl in oDlg:aControls
      SetParent( oControl:hWnd, oWnd:hWnd )
      AAdd( oWnd:aControls, oControl )
      oControl:oWnd  := oWnd
   next

   oWnd:SetSize( oDlg:nWidth, oDlg:nHeight )
   oWnd:SetColor( oDlg:nClrText, oDlg:nClrPane, oDlg:oBrush )

return nil
 
Individual programmers may adopt different code but essentially the underlying theme is the same.

FWH18.08: New simplified and better approach:
The entire above code is replaced with

Code: Select all

   DEFINE DIALOG oDlg RESOURCE "resname"
   // <REDEFINE all controls>
   ACTIVATE DIALOG oDlg AS MDICHILD
 
Adding the clause CENTERED centers the mdichild window inside the main mdi window.

Note:
If the definition of DIALOG in the Resource file contains the style WS_VISIBLE, that should be removed.

Advantages over the previous implementation:

1) Simplified code and lesser chance to commit mistakes/bugs.

2) Flicker: With the previous implementation, the dialog appears on the screen briefly for a fraction of a second and then disappears before the mdichild window is displayed. This flicker is eliminated.

3) After activation, the variable "oDlg" refers to the new mdichild window and not to the dialog object anymore.
oDlg can be used to refer to the mdichild window.

4) All codeblocks created with the dialog object oDlg are transferred to the new mdichild object, including contents of Cargo.

5) Though these codeblocks were written refering the oDlg object, during execution they act on the mdichild window but not on the dialog object, which anyway is already ended.
Eg: ACTION oDlg:End() now closes mdichild window.
oDlg:bRClicked now acts on mdichild window
etc.

Known issues (with both old and new methods):

1) Some controls like Say, Combobox, etc. flicker when the mdichild window is resized.
2) FocusRect is not painted around some controls like CheckBox, etc.

These are issues inherent with mdichild and have nothing to do with the method adopted. Even controls directly created on mdichild window have these issues. We are still working to eliminate them.

fwh\samples\mdidlg.prg: Demonstrating old and new methods:

Code: Select all

#include "fivewin.ch"

#define AS_MDICHILD  1
#define AS_DIALOG    2

//----------------------------------------------------------------------------//

function Main()

   local oWnd, oBar, oMenu

   SetGetColorFocus()

   DEFINE WINDOW oWnd MDI TITLE "FWH18.08: DIALOG IN MDICHILD WINDOW"
   DEFINE BUTTONBAR oBar OF oWnd SIZE 100,32 2007
   DEFINE BUTTON OF oBar PROMPT "MDIDLG-OLD" CENTER ACTION DlgInMdiChildOld()
   DEFINE BUTTON OF oBar PROMPT "MDIDLG-NEW" CENTER ACTION CreateDialog( AS_MDICHILD )
   DEFINE BUTTON OF oBar PROMPT "DIALOG"     CENTER ACTION CreateDialog( AS_DIALOG )
   ACTIVATE WINDOW oWnd

return nil

//----------------------------------------------------------------------------//

static function CreateDialog( nAs )

   local oDlg, oCbx, oChk, oFont, oBrush
   local cVar1, cVar2
   local lSwitch1, lSwitch2, lSwitch3
   local cVar     := "Two"
   local aGrad    := {{1, CLR_WHITE, CLR_HBLUE }}

   cVar1 := cVar2 := Space( 50 )
   lSwitch1 := lSwitch2 := lSwitch3 := .f.

   DEFINE BRUSH oBrush GRADIENT aGrad
   DEFINE FONT oFont NAME "Segoe UI" SIZE 0,-14

   DEFINE DIALOG oDlg RESOURCE "MDIDLG" FONT oFont TITLE "MDI-DLG" BRUSH oBrush

   RELEASE FONT oFont
   RELEASE BRUSH oBrush

   REDEFINE CHECKBOX oChk VAR lSwitch1 ID 1001 OF oDlg
   oChk:lTransparent := .t.
   REDEFINE CHECKBOX oChk VAR lSwitch2 ID 1002 OF oDlg
   oChk:lTransparent := .t.
   REDEFINE GET cVar1 ID 1005 OF oDlg
   REDEFINE CHECKBOX oChk VAR lSwitch3 ID 1010 OF oDlg WHEN lSwitch1
   oChk:lTransparent := .t.
   REDEFINE COMBOBOX oCbx VAR cVar ITEMS { "One", "Two", "Three" } ID 1015 OF oDlg WHEN lSwitch2
   REDEFINE GET cVar2 ID 1020 OF oDlg
   REDEFINE SAY ID 1200 OF oDlg TRANSPARENT COLOR CLR_WHITE,CLR_WHITE
   REDEFINE BTNBMP PROMPT "CLOSE" ID 2001 OF oDlg CENTER 2007 ACTION oDlg:End()

   if nAs == AS_MDICHILD

      ACTIVATE DIALOG oDlg AS MDICHILD ;
         ON PAINT oDlg:Box( 8,8, 373, 584, CLR_HRED ) ;
         ON RIGHT CLICK MsgInfo( oDlg:ClassName(), "oDlg:ClassName" )

   elseif nAs == AS_DIALOG

      ACTIVATE DIALOG oDlg CENTERED

   endif

return oDlg

//----------------------------------------------------------------------------//

static function DlgInMdiChildOld()

   local oWnd, oDlg

   oDlg     := CreateDialog()

   DEFINE WINDOW oWnd MDICHILD OF WndMain() TITLE "Dialog"
   ACTIVATE DIALOG oDlg NOWAIT ON INIT ( ChangeParent( oDlg, oWnd ) )
   oDlg:End()
   ACTIVATE WINDOW oWnd

return nil

//----------------------------------------------------------------------------//

static function ChangeParent( oDlg, oWnd )

   local oControl

   for each oControl in oDlg:aControls
      SetParent( oControl:hWnd, oWnd:hWnd )
      AAdd( oWnd:aControls, oControl )
      oControl:oWnd  := oWnd
   next

   oWnd:SetSize( oDlg:nWidth, oDlg:nHeight )
   oWnd:SetColor( oDlg:nClrText, oDlg:nClrPane, oDlg:oBrush )

return nil

//----------------------------------------------------------------------------//
 
mdidlg.rc

Code: Select all

#include <windows.h>

#ifndef __64__
  1 24 "WinXP/WindowsXP.Manifest"
#else
  1 24 "WinXP/WindowsXP.Manifest64"
#endif

MDIDLG DIALOG 0, 0, 394, 234
STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
CAPTION "TXBrowse demo"
FONT 8, "MS Sans Serif"
{
    AUTOCHECKBOX    "Switch-1", 1001, 44, 22, 69, 9, 0, WS_EX_LEFT
    AUTOCHECKBOX    "Switch-2", 1002, 219, 23, 94, 8, 0, WS_EX_LEFT
    EDITTEXT        1005, 45, 54, 294, 18, ES_AUTOHSCROLL, WS_EX_LEFT
    AUTOCHECKBOX    "CheckBox When Switch-1", 1010, 47, 86, 123, 12, 0, WS_EX_LEFT
    COMBOBOX        1015, 202, 85, 139, 30, CBS_DROPDOWNLIST | CBS_HASSTRINGS, WS_EX_LEFT
    EDITTEXT        1020, 46, 116, 294, 18, ES_AUTOHSCROLL, WS_EX_LEFT
    CTEXT           "TRANSPARENT SAY", 1200, 44, 174, 131, 22, SS_CENTER, WS_EX_TRANSPARENT
    PUSHBUTTON      "OK", 2001, 256, 178, 69, 24, 0, WS_EX_LEFT
}
 
Image

Re: FWH 1808: Dialog as Mdichild

Posted: Mon Oct 22, 2018 6:03 pm
by TimStone
Interesting. Looking forward to working with it.

Re: FWH 1808: Dialog as Mdichild

Posted: Tue Oct 23, 2018 7:56 am
by Silvio.Falconi
Nages,
on oldes prg I made

Code: Select all

 
Function Product()
  LOCAL oItem:=oMOpc, oBtnB:=oBBar
   local oDlg, oWChld
   LOCAL oCbx, cVar, aIdx:={}, oIcon, aX[6], nW, nH
   LOCAL oLin, oMar, aLins:={}, aMars:={}
   LOCAL cHead1, cHead2, nS1, nS2
   LOCAL oDTab, oDCam, oLim


   // archive
   use catalogo alias Cat

   cHead1:="Codice"
   cHead2:="Descrizione"

   nS1:=125
   nS2:=365

DEFINE WINDOW oWChld MDIChild OF oWnd TITLE "Anagrafica " NOZOOM ICON oIcon
   
  DEFINE DIALOG oDlg RESOURCE "CAW130"  OF oWChld


      //listbox

      REDEFINE LISTBOX oBCat ;
      FIELDS cat->CvePro, Cat->MR, cat->Descri ;
      HEADER cHead1  , "MR", cHead2        ;
      SIZES  nS1, 25,nS2            ;
      ID 110 OF oDlg

      // click doubleclick
     oBCat:bLDblClick:={|| Disp_Men(oDlg,70,250)}


   nW:=IF(IsWinNT(), 8, 8)
   nH:=IF(IsWinNT(),33,27)

   oWChld:bGotFocus:={|| oBCat:SetFocus() }

   ACTIVATE DIALOG oDlg NOWAIT VALID (oWChld:End(),.T.)

     ACTIVATE WINDOW oWChld ;
      ON INIT   (oDlg:Move(0,0)) ;
      ON RESIZE (oWChld:SetSize(oDlg:nWidth+nW,oDlg:nHeight+nH)) ;
      VALID     (oWChld:=Nil,Chiudi_Dlg() ,.T.)

RETURN (NIL)

 
and I have the same effect...thanks to Alfredo Arteaga

Re: FWH 1808: Dialog as Mdichild

Posted: Tue Oct 23, 2018 11:53 am
by nageswaragunupudi
Mr. Silivio

As I said above, different programmers are using different code to achieve this. The code you are using is a close variant of the logic used in "fwh\samples\testmdi4.prg".

Using this logic, the mdichild window does not behave like any other mdichild window. No zooming and no resizing. We want the mdichild window to behave like any other normal mdichild window. If not, there is no need to take all this trouble. We could just leave it as a nowait dialog.

Not only the new improvement makes the process simpler but also overcomes many shortcomings of the different present approaches being used.

Re: FWH 1808: Dialog as Mdichild

Posted: Tue Oct 23, 2018 3:04 pm
by richard-service
Mr.Rao

How to control Resource Dialog within ChildWindows?
Ex.
I open Customer Dialog, don't open Customer Dialog again...etc
or Disable MenuItem or ButtonBar Button ...etc

Re: FWH 1808: Dialog as Mdichild

Posted: Wed Oct 24, 2018 12:34 am
by nageswaragunupudi
Mr. Richard

Please test this program and use the same logic in your application.

Code: Select all

#include "fivewin.ch"

function Main()

   local oWnd, oMenu, oBar

   MENU oMenu
      MENUITEM "Main"
      MENU
         MENUITEM "TestWnd" ACTION TestMdiChild()
         SEPARATOR
         MENUITEM "Quit" ACTION WndMain():End()
      ENDMENU
   ENDMENU

   DEFINE WINDOW oWnd MDI MENU oMenu
   DEFINE BUTTONBAR oBar SIZE 100,32 2007
   DEFINE BUTTON OF oBar PROMPT "TestWnd" CENTER ACTION TestMdiChild()

   ACTIVATE WINDOW oWnd

return nil

function TestMdiChild()

   static oWnd

   if oWnd != nil
      if oWnd:IsIconic()
         oWnd:Restore()
      endif
      oWnd:SetFocus()
      return nil
   endif

   DEFINE WINDOW oWnd MDICHILD OF WndMain() TITLE "Customer Dialog"

   oWnd:bPostEnd := { || oWnd := nil }

   ACTIVATE WINDOW oWnd

return nil
 

Re: FWH 1808: Dialog as Mdichild

Posted: Tue Jun 25, 2019 1:57 pm
by Horizon
Hi Mr. Rao,

I use one main sdi window and modal dialogs.
Can this new feature increase the dialog's activate time?

Re: FWH 1808: Dialog as Mdichild

Posted: Wed Jun 26, 2019 2:32 pm
by nageswaragunupudi
I use one main sdi window and modal dialogs.
Excellent. This is clean, simple and safe.
Can this new feature increase the dialog's activate time?
This topic relates to MDI windows only. Nothing to do with SDI windows.
You may just ignore this topic.

Re: FWH 1808: Dialog as Mdichild

Posted: Sun Aug 09, 2020 6:39 am
by Max HK
If the dialog is activated as normal, when pressing <Tab>, the sequence of active controls is:
1. Checkbox Switch-1
2. Checkbox Switch-2
3. GET cVar1
4. GET cVar2
5. Button
This is the normal operation.

But if the dialog is activated as MDIChild, the sequence is reverse when pressing <Tab>:
1. GET cVar2
2. GET cVar1
3. Checkbox Switch-2
4. Checkbox Switch-1
5. Button
Pressing <Enter> or Up-arrow have the same reverse sequence. :?:

Re: FWH 1808: Dialog as Mdichild

Posted: Thu Aug 13, 2020 5:11 am
by Max HK
To: Mr. nageswaragunupudi

No one found this wrong behaviour in Dialog AS MDICHILD?

I am using FWH 1912. Is this bug fixed in later version?

Thanks.

Re: FWH 1808: Dialog as Mdichild

Posted: Thu Aug 13, 2020 6:10 am
by nageswaragunupudi
We are looking into this.
We will get back on this.

Re: FWH 1808: Dialog as Mdichild

Posted: Sun Aug 16, 2020 2:01 pm
by nageswaragunupudi
You are right.
Nobody reported the issue earlier and we ourselves do not use this feature.

We will look into this and come up with a solution.

Re: FWH 1808: Dialog as Mdichild

Posted: Sun Aug 16, 2020 3:19 pm
by nageswaragunupudi
Thanks for pointing out.
This is fixed in FWH2008.

Re: FWH 1808: Dialog as Mdichild

Posted: Sun Aug 16, 2020 3:34 pm
by nageswaragunupudi
Revised fwh\samples\mdidlg.prg

Code: Select all

#include "fivewin.ch"

#define AS_MDICHILD  1
#define AS_DIALOG    2


//----------------------------------------------------------------------------//

function Main()

   local oWnd, oBar, oMenu

   SetGetColorFocus()

   DEFINE WINDOW oWnd MDI TITLE "FWH18.08: DIALOG IN MDICHILD WINDOW"
   DEFINE BUTTONBAR oBar OF oWnd SIZE 100,32 2007
   DEFINE BUTTON OF oBar PROMPT "MDIDLG-OLD" CENTER ACTION DlgInMdiChildOld()
   DEFINE BUTTON OF oBar PROMPT "MDIDLG-NEW" CENTER ACTION CreateDialog( AS_MDICHILD )
   DEFINE BUTTON OF oBar PROMPT "DIALOG"     CENTER ACTION CreateDialog( AS_DIALOG )
   ACTIVATE WINDOW oWnd

return nil

//----------------------------------------------------------------------------//

static function CreateDialog( nAs )

   local oDlg, oCbx, oChk, oFont, oBrush
   local cVar1, cVar2
   local lSwitch1, lSwitch2, lSwitch3
   local cVar     := "Two"
   local aGrad    := {{1, CLR_WHITE, CLR_HBLUE }}

   cVar1 := cVar2 := Space( 50 )
   lSwitch1 := lSwitch2 := lSwitch3 := .f.

   DEFINE BRUSH oBrush GRADIENT aGrad
   DEFINE FONT oFont NAME "Segoe UI" SIZE 0,-14

   DEFINE DIALOG oDlg RESOURCE "MDIDLG" FONT oFont TITLE "MDI-DLG" BRUSH oBrush

   RELEASE FONT oFont
   RELEASE BRUSH oBrush

   REDEFINE CHECKBOX oChk VAR lSwitch1 ID 1001 OF oDlg
   oChk:lTransparent := .t.
   REDEFINE CHECKBOX oChk VAR lSwitch2 ID 1002 OF oDlg
   oChk:lTransparent := .t.
   REDEFINE GET cVar1 ID 1005 OF oDlg
   REDEFINE CHECKBOX oChk VAR lSwitch3 ID 1010 OF oDlg WHEN lSwitch1
   oChk:lTransparent := .t.
   REDEFINE COMBOBOX oCbx VAR cVar ITEMS { "One", "Two", "Three" } ID 1015 OF oDlg WHEN lSwitch2
   REDEFINE GET cVar2 ID 1020 OF oDlg
   REDEFINE SAY ID 1200 OF oDlg TRANSPARENT COLOR CLR_WHITE,CLR_WHITE
   REDEFINE BTNBMP PROMPT "CLOSE" ID 2001 OF oDlg CENTER 2007 ACTION oDlg:End()

   if nAs == AS_MDICHILD

      ACTIVATE DIALOG oDlg AS MDICHILD ;
         ON PAINT oDlg:Box( 8,8, 373, 584, CLR_HRED ) ;
         ON RIGHT CLICK MsgInfo( oDlg:ClassName(), "oDlg:ClassName" )

   elseif nAs == AS_DIALOG

      ACTIVATE DIALOG oDlg CENTERED

   endif

return oDlg

//----------------------------------------------------------------------------//

static function DlgInMdiChildOld()

   local oWnd, oDlg

   oDlg     := CreateDialog()

   DEFINE WINDOW oWnd MDICHILD OF WndMain() TITLE "Dialog"
   ACTIVATE DIALOG oDlg NOWAIT ON INIT ( ChangeParent( oDlg, oWnd ) )
   oDlg:End()
   ACTIVATE WINDOW oWnd

return nil

//----------------------------------------------------------------------------//

static function ChangeParent( oDlg, oWnd )

   local oControl, n
   local aa := Array( Len( oDlg:aControls ), 2 )

   for n := Len( oDlg:aControls ) to 1 step -1
      oControl := oDlg:aControls[ n ]
      SetParent( oControl:hWnd, oWnd:hWnd )
      AAdd( oWnd:aControls, oControl )
      oControl:oWnd  := oWnd
   next

   oWnd:SetSize( oDlg:nWidth, oDlg:nHeight )
   oWnd:SetColor( oDlg:nClrText, oDlg:nClrPane, oDlg:oBrush )

return nil

//----------------------------------------------------------------------------//