FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin for Harbour/xHarbour MDI Questions
Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
MDI Questions
Posted: Wed Feb 11, 2026 12:56 AM

I have avoided MDI for all these years because my clients would forget to close windows and thus mess up their data. However, now that they are handling multiple open applications, I am converting my program to MDI. This thread may include more questions but here is the first.

I have a primary window ( actually a bar ) when I open the application and it puts an icon on the task bar. If I open a section ( ie. inventory ), to work it starts as a new MDI window ... and I can move it anywhere. However, if I open a second without moving it, it covers over it. Often they might want multiple sections open ( inventory, clients, invoicing, accounting ), and may not have all the windows visible. Unfortunately on the task bar there is only the original icon for the main program. How can they move between windows ? When opening a window, can we highlight the button on the button bar, and click it to go back to that window ? Can we add an icon to the task bar ? Can I add a scrolling control on the main button bar ?

I probably should have known this years ago ( and maybe I did ) but it's not there right now.

Thanks

Tim

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: MDI Questions
Posted: Wed Feb 11, 2026 10:00 AM

Dear Tim,

Based on the FiveWin framework code, here are solutions to your MDI window management questions:

1. Moving Between Windows - Standard Window Menu

The easiest way is to use the built-in MDI menu functionality. Call oMenu:AddMdi() after defining your menu, which automatically creates a "Window" submenu with standard operations (Cascade, Tile, etc.) and automatically lists all open child windows at the bottom of the menu. 0-cite-0

When you have more than 9 open windows, the framework automatically adds a "More Windows" option that opens a dialog to select from all windows: 0-cite-1

The menu also includes keyboard shortcuts - Ctrl+F6 to switch to the next window and Ctrl+F4 to close the active window: 0-cite-2

2. Using Button Bar to Switch Windows

Yes, you can create buttons on your button bar where each button calls oChild:SetFocus() to activate a specific MDI child window. Here's an example from the codebase: 0-cite-3

The SetFocus() method internally calls the MDI client's ChildActivate() to properly activate the window: 0-cite-4 0-cite-5

You could maintain references to your child windows and create/update button bar buttons dynamically as windows are opened/closed, changing their state or appearance based on which window is active.

3. Adding Icons to the Taskbar

This is not standard MDI behavior. In Windows MDI applications, only the parent TMdiFrame window appears on the taskbar - not the individual child windows. This is by design in the Windows MDI specification. The MDI children exist within the parent frame's client area and don't get their own taskbar entries. 0-cite-6

If you absolutely need separate taskbar icons, you would need to use separate top-level windows instead of MDI child windows, but that would defeat the purpose of using MDI.

4. Additional Window Management Options

The framework provides several window arrangement methods that can be called from your menu or button bar:

  • oWnd:Cascade() - Overlapping windows
  • oWnd:Tile() / oWnd:Tile(.t.) - Vertical/Horizontal tiling
  • oWnd:ArrangeIcons() - Organize minimized windows
  • oWnd:IconizeAll() - Minimize all windows
  • oWnd:NextWindow() / oWnd:PrevWindow() - Cycle through windows 0-cite-7

Notes:

  • For scrolling button bars, the standard TButtonBar class doesn't have built-in scrolling. You would need to implement custom scrolling logic or use a different control approach (like a listbox or browse to show open windows).
  • The DlgSelectChild() dialog that appears when you have more than 9 windows provides an XBrowse-based selection interface, which is essentially what you'd need for a scrolling window list.
  • Consider using the Window menu approach (oMenu:AddMdi()) as it's the standard way users expect to manage MDI windows and requires no additional code to maintain.
  • You can check Len(oWnd:oWndClient:aWnd) at any time to see how many child windows are open, which is useful for enabling/disabling buttons or menu items.

Citations

File: source/classes/menu.prg (L2055-2128)

Code (text): Select all Collapse
METHOD AddMdi( aColors, cFile, cRes ) CLASS TMenu

   local oItem

   if !Empty( aColors )
      ::SetColors( aColors )
   endif

   if Empty( cFile ) .and. Empty( cRes )
      MENUITEM oItem PROMPT FWString( "&Window" )
   else
      if !Empty( cFile )
         MENUITEM oItem PROMPT FWString( "&Window" ) FILE cFile
      else
         if !Empty( cRes )
            MENUITEM oItem PROMPT FWString( "&Window" ) RESOURCE cRes
         endif
      endif
   endif
   if ::lColors
      MENU ::oMenuChild ;
        COLORMENU      ::nClrMenu, ::nClrText ;
        COLORBMP       ::nClrToBa, ::nClrBkBa ; //::nClrToBa, ::nClrBkBa
        COLORRIGHT     ::nClrToBr, ::nClrBkBr ;
        COLORSELECT    ::nClrHiLi, ::nClrHiLf, ::nClrHiTx;
        COLORSEPARATOR ::nClrHiBr ;
        COLORS ;
        FONT ::oFont
   else
      MENU ::oMenuChild
   endif
      ::oMenuChild:l2007    := ::l2007
      ::oMenuChild:l2010    := ::l2010
      ::oMenuChild:l2013    := ::l2013
      ::oMenuChild:l2015    := ::l2015
      ::oMenuChild:lColors  := ::lColors
      ::oMenuChild:lLinVert := IF( ::l2013, .T., ::lLinVert )
      ::oMenuChild:lBorder  := ::lBorder

      MENUITEM FWString( "&Tile Vertical" ) ACTION ( oMenuItem, ::oWnd:Tile() ) ;
         MESSAGE FWString( "Vertical arranges the windows as nonoverlapping tiles" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 0, .T. ) ) //HSYSBITMAP IF( ::oMenuChild:lColors, 32745, 10 )

      MENUITEM FWString( "&Tile Horizontal" ) ACTION ( oMenuItem, ::oWnd:Tile( .t. ) ) ;
         MESSAGE FWString( "Horizontal arranges the windows as nonoverlapping tiles" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 0, .T. ) ) //HSYSBITMAP 32748

      MENUITEM FWString( "&Cascade" )        ACTION ( oMenuItem, ::oWnd:Cascade() ) ;  //E158
         MESSAGE FWString( "Arranges the windows so they overlap" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 0, .T. ) ) //HSYSBITMAP IF( ::oMenuChild:lColors, 32744, 9 )

      MENUITEM FWString( "&Next Window" ) + Chr( 9 ) + "Ctrl+F6" ;
         ACTION ( oMenuItem, ::oWnd:NextWindow() ) MESSAGE FWString( "Selects the next window" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 1, .T. ) ) //HSYSBITMAP IF( ::oMenuChild:lColors, 32739, 32739 )

      SEPARATOR

      MENUITEM FWString( "&Arrange Icons" )  ACTION ( oMenuItem, ::oWnd:ArrangeIcons() ) ;  //E154
         MESSAGE FWString( "Arrange icons at the bottom of the window" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 0, .T. ) ) // HSYSBITMAP 32738

      MENUITEM FWString( "&Iconize All" )    ACTION ( oMenuItem, ::oWnd:IconizeAll() ) ;
         MESSAGE FWString( "Iconize all open windows" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 0, .T. ) ) // HSYSBITMAP IF( ::oMenuChild:lColors, 32749, 11 )

      MENUITEM FWString( "C&lose All" )      ACTION ( oMenuItem, ::oWnd:CloseAll() ) ;
         MESSAGE FWString( "Close all open windows" ) ;
         WHEN ( oMenuItem, IF( !Empty( ::oWnd ), Len( ::oWnd:oWndClient:aWnd ) > 0, .T. ) ) //HSYSBITMAP IF( ::oMenuChild:lColors, 32758, 5 )
   ENDMENU
   if !Empty( aColors )
      ::SetColors( ::aColorsBak )
   endif

return oItem

File: source/classes/mdiframe.prg (L34-108)

Code (text): Select all Collapse
CLASS TMdiFrame FROM TWindow

   DATA   oWndActive
   DATA   oWndClient
   DATA   oMenuStart
   DATA   nMenuInfo
   DATA   bOnOpen
   DATA   lChildAutoSize AS LOGICAL INIT .f.
   DATA   bDlgSelectChild

   CLASSDATA lRegistered AS LOGICAL

   METHOD New( nTop, nLeft, nBottom, nRight, cTitle, nStyle, oMenu, oBrush,;
               oIcon, nClrFore, nClrBack, lVScroll, lHScroll, nMenuInfo,;
               cBorder, oWnd, lPixel, cVarName, nHelpID, lUnicode, nWidth, nHeight ) CONSTRUCTOR

   METHOD ChildNew( nTop, nLeft, nBottom, nRight, cTitle, nStyle ) INLINE ;
          ::oWndClient:ChildNew( nTop, nLeft, nBottom, nRight, cTitle, nStyle )

   METHOD Cascade()      INLINE ::oWndClient:Cascade()
   METHOD CloseAll()     INLINE ::oWndClient:lCloseAll()

   METHOD IconizeAll()   INLINE ::oWndClient:IconizeAll()

   METHOD Tile( lHor )   INLINE ::oWndClient:Tile( lHor )
   METHOD ArrangeIcons() INLINE ::oWndClient:ArrangeIcons()

   METHOD Zoom()         INLINE ::oWndClient:Zoom()

   METHOD CloseActive()  INLINE ::oWndClient:CloseActive()

   METHOD NextWindow() INLINE ::oWndClient:NextWindow()
   METHOD PrevWindow() INLINE ::oWndClient:PrevWindow()

   METHOD ReSize( nSizeType, nWidth, nHeight )

   METHOD Command( nWParam, nLParam )

   METHOD Copy() INLINE If( ::oWndActive != nil, ::oWndActive:Copy(),)
   METHOD Cut()  INLINE If( ::oWndActive != nil, ::oWndActive:Cut(),)

   METHOD Delete()  INLINE If( ::oWndActive != nil, ::oWndActive:Delete(),)
   METHOD FindNext()  INLINE If( ::oWndActive != nil, ::oWndActive:FindNext(),)

   METHOD Open() INLINE If( ::bOnOpen != nil, Eval( ::bOnOpen, Self ),)

   METHOD Paste( cText ) INLINE ;
          If( ::oWndActive != nil, ::oWndActive:Paste( cText ),)

   METHOD Print() INLINE ;
          If( ::oWndActive != nil, ::oWndActive:Print(),)

   METHOD ReDo()  INLINE If( ::oWndActive != nil, ::oWndActive:ReDo(),)
   METHOD UnDo()  INLINE If( ::oWndActive != nil, ::oWndActive:UnDo(),)

   METHOD Find( cText ) INLINE ;
          If( ::oWndActive != nil, ::oWndActive:Find( cText ),)

   METHOD End()

   METHOD Properties()  INLINE If( ::oWndActive != nil, ::oWndActive:Properties(),)

   METHOD Replace()  INLINE If( ::oWndActive != nil, ::oWndActive:Replace(),)

   METHOD Select( nWindow ) INLINE ::oWndClient:Select( nWindow )

   METHOD SelectAll()  INLINE If( ::oWndActive != nil, ::oWndActive:SelectAll(),)

   METHOD SetMenu( oMenu, nMenuInfo )

   METHOD GotFocus()

   METHOD DlgSelectChild()

ENDCLASS

File: source/classes/mdiframe.prg (L340-401)

Code (text): Select all Collapse
METHOD DlgSelectChild() CLASS TMdiFrame

   local nWnd    := 0
   local aWnds   := {}
   local oDlg
   local oLbx
   local cTitle  := "Select Child Window"
   local nTopBtn
   local nBtnW   := 48
   local nBtnH   := 14
   local nDlgW   := 450 + 100            // nDlgW := 450
   local nDlgH   := 300
   local nTopLbx := 2 //33
   local nLbxW   := 220 + 50
   local nLbxH
   local nLeftR
   local oFont
   nTopBtn       := Int( nDlgH / 2 ) - nBtnH - 2    // 6
   nLbxH         := nTopBtn - nTopLbx - 2

   AEval( ::oWndClient:aWnd, { | a | AAdd( aWnds, a:cCaption ) } )

   //XBROWSER aWnds SELECT ( nWnd := oBrw:nArrayAt ) SHOW RECID
   DEFINE FONT oFont NAME "Segoe UI" SIZE 0, -16
   DEFINE DIALOG oDlg SIZE nDlgW, nDlgH TITLE cTitle
      oDlg:lTruePixel   := .f.
      oDlg:lHelpIcon    := .f.

      @ nTopLbx, 2 XBROWSE oLbx DATASOURCE aWnds OF oDlg ;
         COLUMNS 1 HEADERS "Caption Child Window" ;
         SIZE nLbxW, nLbxH - 2 PIXEL STYLE FLAT NOBORDER FONT oFont
      WITH OBJECT oLbx
         :l2007           := .F.
         :lHScroll        := .F.
         :lRecordSelector := .F.
         :nRowHeight      := 24
         :nColorPen       := CLR_HGRAY
         :bClrStd         := { || { CLR_BLUE, Rgb( 248, 248, 248 ) } }
         :bClrHeader      := { || { CLR_BLUE, RGB( 222, 222, 222 ), RGB( 222, 222, 222 ) } }
         :lFullGrid       := .T.
         :nMarqueeStyle   := MARQSTYLE_HIGHLROW
         :bLDblClick    := { || nWnd := oLbx:nArrayAt, oDlg:End() }
         :CreateFromCode()
      END
      nLeftR := ( ( nDlgW + nBtnW * 2 ) - ( 2 * nBtnW ) ) / ( 2 * 2 )
      @ nTopBtn, nLeftR BUTTON "&Cancel" ;
         OF oDlg ACTION ( oDlg:End() ) ;
         SIZE nBtnW, nBtnH FONT oFont PIXEL

      @ nTopBtn, nLeftR + nBtnW * 1.5 BUTTON "&Select" ;
         OF oDlg ACTION ( nWnd := oLbx:nArrayAt, oDlg:End() ) ;
         SIZE nBtnW, nBtnH PIXEL FONT oFont DEFAULT

   ACTIVATE DIALOG oDlg CENTERED
   RELEASE FONT oFont

   if !Empty( nWnd )
      ::oWndClient:aWnd[ nWnd ]:SetFocus()
   endif

Return nil

File: source/classes/mdichild.prg (L117-117)

Code (text): Select all Collapse
   METHOD SetFocus() INLINE ::oWnd:oWndClient:ChildActivate( Self )

File: source/classes/mdichild.prg (L304-320)

Code (text): Select all Collapse
METHOD KeyDown( nKey, nFlags ) CLASS TMdiChild

   // There is no a standard behavior for WM_KEYDOWN messages so we have
   // to process them !

   if nKey == VK_F4 .and. GetKeyState( VK_CONTROL )
      ::SendMsg( WM_SYSCOMMAND, SC_CLOSE )
      return 0
   endif

   if nKey == VK_F6 .and. GetKeyState( VK_CONTROL )
      ::SendMsg( WM_SYSCOMMAND, SC_NEXT )
      return 0
   endif

return ::Super:KeyDown( nKey, nFlags )

File: samples/test/testmdi6.prg (L29-38)

Code (text): Select all Collapse
   DEFINE BUTTONBAR oBar OF oWnd

   DEFINE BUTTON OF oBar ACTION oChild1:SetFocus()
   DEFINE BUTTON OF oBar ACTION oChild2:SetFocus()
   DEFINE BUTTON OF oBar ACTION oChild3:SetFocus()

   DEFINE BUTTON OF oBar GROUP ACTION NewChild()

   ACTIVATE WINDOW oWnd

File: source/classes/mdiclien.prg (L53-53)

Code (text): Select all Collapse
   METHOD ChildActivate( oWnd ) INLINE ::SendMsg( WM_MDIACTIVATE, oWnd:hWnd )
regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1445
Joined: Mon Oct 10, 2005 02:38 PM
Re: MDI Questions
Posted: Wed Feb 11, 2026 10:57 AM

Tim,

En mi caso uso MDI.

  • * - * - * - * - * - * - * -*

En el menú de la ventana principal tengo 2 botones:
"<<" y ">>"

    MENUITEM "<<" ACTION oWndMDI:PrevWindow()
    MENUITEM ">>" ACTION oWndMDI:NextWindow()
  • * - * - * - * - * - * - * -*

En cada MDIClient tengo:

    oWndMDIClient1:bKeyDown   := {| nKey , nflags | ;
                             KeyInoWnd( AMPAarra, oWndMDI, oWndMDIClient1, "P", ;
                                        {nEditando, oModi, oBusca, oWBrowse, oPrint, oAfegir, oDel, oASFiltre, ;
                                         Nil,       Nil,   Nil,    Nil,      Nil,    Nil,     Nil,  Nil}, ;
                                         nKey, nflags  ) }
  • * - * - * - * - * - * - * -*

FUNCTION KeyInoWnd( AMPAarra, oWndMDI, oWndMDIClient, cTipusWnd, aControles, nKey, nflags )

....

ElseIf nKey = VK_F11
    If GetKeyState( VK_CONTROL )
        /* Cambia de ventana de datos a la ventana siguiente.
           ----------------------------------------------- */
        oWndMDI:NextWindow()
      Else
    /* Cambia de ventana de datos a la ventana anterior.
       ---------------------------------------------- */
        oWndMDI:PrevWindow()
    EndIf

....

Return Nil

  • * - * - * - * - * - * - * -*

Por tanto, pueden pulsar en el menú, o con F11 ó CTRL+F11 podrán cambiar de MDIClient.

Un Saludo

Carlos G.



FiveWin 25.12 + Harbour 3.2.0dev (r2502110321), BCC 7.7 Windows 11 Home

Posts: 8515
Joined: Tue Dec 20, 2005 07:36 PM
Re: MDI Questions
Posted: Wed Feb 11, 2026 03:50 PM

C:\FWH\SAMPLES\EDITOR.prg

   // Inside a menu action
   MENUITEM "&Previous Window" ACTION oWndMDI:oWndClient:PrevWindow()
   / Assuming oWndMDI is your main MDI Window
   // And you want to switch to the previous child

   IF Len( oWndMDI:oWndClient:aWnd ) > 0
      oWndMDI:oWndClient:PrevWindow()
   ENDIF

Regards, saludos.

João Santos - São Paulo - Brasil - Phone: +55(11)95150-7341
Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
Re: MDI Questions
Posted: Wed Feb 11, 2026 06:53 PM

Thanks for the responses. Here is where/why I'm running into problems, and what I'm trying to accomplish.

Currently: I open the .exe to a main window. The button bar on the top offers options for multiple operations: Workorders ( Estimates, invoices, etc ), Clients, Inventory, Accounting, and different utilities. The buttons call dialogs ( modal ) for each area. The problem is that only one operation can be run at a time.

Desire: I want to open these main areas allowing multiple windows to be open at the same time.

First attempt: I changed the main program Window to MDI. Then I tried setting the main dialog for each of the processes to MDICHILD in their .prgs. That didn't work. Only one would open at a time. ( I assumed making it a child of the main window would allow this ... it didn't ).

Second attempt: I left the main window as MDI, and made each of those sections opening to a new MDI Window. I then opened the previous dialog in that window. This worked but if I opened another window, that one disappeared between the MAIN opening window and could not be retrieved unless I closed other windows.

Third attempt: I reduced the main window to only a bar across the top. That way I could see the various windows but still had to move them around to see the others.

I have reviewed the ChatGPT output Antonio posted, and also the responses provided here. Previously I reviewed all of the examples I could find in Samples. Seeing minimal samples just doesn't help understand the use of MDI for a full featured application. I'm a reader, and documentation really helps me understand the principals of how something works, and then apply it. Sadly, we've not had any good documentation for FW for many years. What we do have is decades old.

I'd love to see an example of a fully implemented MDI application like this one that takes into account the need for multiple child windows all performing different major functions as listed at the top of these comments.

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 113
Joined: Wed Feb 08, 2006 10:32 PM
Re: MDI Questions
Posted: Wed Feb 11, 2026 11:38 PM

Hello Tim,

I always use Mdi structure for my apps, but one thing is not clear, is your main window an MdiFrame() window? It should not be a 'standard' window. Anyway let's look at the next step, I also built a container class for the MdiFrame() and the mdiChild(), to store in a dbf some info about the windows. The info I store are the window id, coordinates, colours, buttonbar position, and others so when the user reopen the same window he will find it in he same state and position where he closed it

Hope you will find useful best regards

Roberto Chiaiese
R&C Informatica S.n.c.
https://www.recinformatica.it
info@recinformatica.it

Harbour 3.2 - FW2512

Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
Re: MDI Questions
Posted: Thu Feb 12, 2026 01:53 AM

I have been working with ChatGPT all day ...

On my opening PROCEDURE MAIN, after initializing some variables, I make the following call:

DEFINE WINDOW oWnd TITLE "AppNamet" MDIFRAME

// In here I create a button bar with no buttons, and no calls to anything. They do exist but are blocked out at this point

ACTIVATE WINDOW oWnd MAXIMIZED

On startup, although I have no child windows being called, I get the following message and the app crashes immediately with:

BASE/1004 No exported method: OWNDCLIENT stack shows window.prg => oWndClient() called from mdichild.prg => TMDIChild:New().

I have other issues, but in this case I need to get past the problem with MDIFRAME ... and if I use just MDI I don't have this problem, but I understand it will create other problems unless I use MDIFRAME

Tim

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 44158
Joined: Thu Oct 06, 2005 05:47 PM
Re: MDI Questions
Posted: Thu Feb 12, 2026 05:04 AM

Dear Tim,

This is the right code:

DEFINE WINDOW oWnd TITLE "AppNamet" MDI

ACTIVATE WINDOW oWnd MAXIMIZED

I encourage you to try Google Gemini. You can get a free entreprise Google gemini account this way:
https://youtu.be/n32X6bL-FCg?si=qLD0sDBFtiaEunp9

regards, saludos

Antonio Linares
www.fivetechsoft.com
Posts: 1515
Joined: Thu Oct 30, 2008 02:37 PM
Re: MDI Questions
Posted: Thu Feb 12, 2026 12:54 PM
Antonio Linares wrote:

Dear Tim,

Based on the FiveWin framework code, here are solutions to your MDI window management questions:

Querido Antonio,

Un compañero, Jesús Marín, hizo una clase para MDI, MDIChildFolder, que me pareció que superaba con mucho las posibilidades MDI de Fivewin. Me impresionó la clase. Lástima que no he podido usarla aún y no ha sido por falta de ganas.

https://forums.fivetechsupport.com/viewtopic.php?t=45841
https://github.com/JesusMarinVives/MdiChildFolder

Salu2

Posts: 1445
Joined: Mon Oct 10, 2005 02:38 PM
Re: MDI Questions
Posted: Fri Feb 13, 2026 03:14 PM

Tim,

Esto es de una aplicación que tiene más de 20 años (antes del EURO), que está funcionando y lincada hoy en día con FWH 25.06

// *******************************************************
// ******************************************** en el main() está esto
/* Se define la ventana principal
---------------------------------*/

DEFINE WINDOW JuvaArra[1][1][2][1][1] MDI ;             // Definimos la ventana
    FROM 2,2 TO 30,80;                                  // Coordenadas
    TITLE "Juva32, Control de serveis y facturació."  ; // Título
    MENU MenuMain( JuvaArra )  // Menú

/* Se activa la ventana principal
---------------------------------*/

ACTIVATE WINDOW JuvaArra[1][1][2][1][1] ;
    MAXIMIZED ;
    ON INIT ( AutResiz( JuvaArra[1][1][2][1][1], 2 ), Albara02( JuvaArra ) )  ;
    VALID ( JuvaArra[4][1] := MsgNoYes("Vol sortir del programa?", "Atenció!" ) )

// *******************************************************
// En OTRO PRG
// *******************MDIChild 'SIMPLE' ************************* está esto

DEFINE WINDOW oalbara02 MDICHILD FROM 0,0 TO 520,804 TITLE ;
    "Manteniment Albarans NO facturats COMPLERTS" COLORS J02CLRTEXTO,J02CLRWND OF ;
    JuvaArra[1][1][2][1][1] NOZOOM PIXEL

@ 174,42 LISTBOX oWBrowse FIELDS DtoC( (@oTDbfAlbara:DATAALBA) ), ;
    Padl( "-" + AllTrim(Str((@oTDbfAlbara:NUMEALBA), 9, 0)), 10, "L"), ;
    Padl( "-" + Alltrim(@oTDbfaLBARA:CodiArti), 13, "A"), ;
    padl( "-" + Alltrim(@oTDbfaLBARA:CodiPers), 9, "C"), Str((@oTDbfAlbara:QUANUNIT), ;
    8, 2), Str( nContravalor( JuvaArra, (@oTDbfAlbara:PREUUNIT), ;
    (@oTDbfAlbara:MNDA), JuvaArra[1][2][5][3] ), 10, 2), (@oTDbfAlbara:TipuUnit), ;
    padl("-"+alltrim(Str((@oTDbfAlbara:NUMEFACT), 10, 0)), 10, "F" ), ;
    Padl( "-" + AllTrim(Str((@oTDbfAlbara:CODIDEST), 4, 0)), 6, "D"), ;
    (@oTDbfAlbara:CODIPRES), Str((@oTDbfAlbara:Movivend), 8, 0) ALIAS ;
    oTDbfAlbara:Alias() COLSIZES 75,75,75,85,100,100,50,85,75,100,75 HEADERS ;
    "Dat.Alb.", "Albarà", "Codi Article", "Client", "Quantitat", "Preu", "Unitats", ;
    "Factura", "Destí", "Pressupost", "Moviment" SIZE 707,229 OF oalbara02 FONT J02FONTLB COLORS ;
    J02CLRTEXTO,J02CLRFONDO UPDATE PIXEL

.....

    ACTIVATE WINDOW oAlbara02 ;
        VALID If( JuvaArra[4][1], ;
                   ( lExiste := .F., oFiltre:SetFocus(),  lWndSalta( JuvaArra, Nil ) , ;
                     laTDbfEnd( JuvaArra, { oTDbfAlbara, oTdbfPerson, ;
                                            oTDbfArticu, oTDbfDestin } ) , ;
                     oSWnd := Nil, .T. ), ;
                   ( lWndSalta( JuvaArra, oAlbara02 ), oSWnd:Hide(), .F. ) ;
                 ) ;
      ON INIT AutResiz( oAlbara02, 2 )

// *******************************************************
// En OTRO PRG
// *******************MDIChild con FOLDERS ************************* PRG está esto

DEFINE WINDOW oFactur01 MDICHILD FROM 0,0 TO 535,804 TITLE "Manteniment de Factures" ;
        COLORS J02CLRTEXTO,J02CLRWND OF JuvaArra[1][1][2][1][1] NOZOOM PIXEL //FIVEWIDI

 DEFINE DIALOG oSMdiDlgFo FROM 0,0 TO 485,800 OF oFactur01 STYLE WS_CHILD PIXEL ;
    FONT J02FONTWND //FIVEWIDI

 ACTIVATE DIALOG oSMdiDlgFo NOWAIT ;
        VALID ( If( nEditando == 0, ;
                    ( If( JuvaArra[4][1], ;
                        ( .T.), ;
                        (JuvaArra[1][1][2][1][1]:NextWindow(), oSWnd:Hide(), .F. ) ;
                     ) ) , ;
                    ( Eval( oSGo:bAction ), .F.) ) ;
              ) ;

// Folder 1
@ -2,-1 FOLDER oFdFactur OF oSMdiDlgFo ITEMS "&Capçalera Factura", ;
    "&Detall Factura" PIXEL COLORS J02CLRTEXTO,J02CLRWND OPTION 1 SIZE 797,496 FONT ;
    J02FONTWND //FIVEWIDI

@ 264,14 LISTBOX oWBrowse FIELDS DToC(@oTDbfFactur:DataFact), Padl("-"+ ;
    Alltrim(Str((@oTDbfFactur:NumeFact), 10,0)),10,"F"), cGetNomPers( ;
    (@oTDbfFactur:TipuPers), (@oTDbfFactur:nom),(@oTDbfFactur:cognom1), ;
    (@oTDbfFactur:cognom2)), Str( nContravalor( JuvaArra, (@oTDbfFactur:TotalBru), ;
    (@oTDbfFactur:Mnda), JuvaArra[1][2][5][3] ), 13, 2) ALIAS oTDbfFactur:Alias() ;
    COLSIZES 75,100,300,75 HEADERS "Data Fact.", "Núm. Fact.", "Client", "Import" ;
    SIZE 454,160 OF oFdFactur:adialogs[1] FONT J02FONTLB ;
	COLORS J02CLRTEXTO, J02CLRFONDO ;
	UPDATE PIXEL //FIVEWIDI
....

// Folder 2
@ 154,42 LISTBOX oWBrowse2 FIELDS DtoC( (@oTDbfConFac:DATAALBA) ), Padl("-" + ;
    AllTrim(Str((@oTDbfConFac:NUMEALBA), 9, 0)), 10, "L"), ;
    Padl("-"+alltrim(@oTDbfConFac:CodiArti), 13, "A"), ;
    padl("-"+alltrim(@oTDbfConFac:CodiPers), 9, "C"), Str((@oTDbfConFac:QUANUNIT), ;
    8, 2), Str( nContravalor( JuvaArra, (@oTDbfConFac:PREUUNIT), ;
    (@oTDbfConFac:MNDA), JuvaArra[1][2][5][3] ), 10, 2), (@oTDbfConFac:TipuUnit), ;
    Str((@oTDbfConFac:NUMEFACT), 8, 0), Str((@oTDbfConFac:CODIDEST), 4, 0), ;
    (@oTDbfConFac:CodiPres), Str((@oTDbfConFac:Movivend), 8, 0) ALIAS oTDbfConFac:Alias() COLSIZES 75,75,75, ;
    75,100,100,50,75,50,100,75 HEADERS "Dat.Alb.", "Albarà", "Codi Article", "Client", ;
    "Quantitat", "Preu", "Unitats", "Factura", "Destí", "Pressupost", "Moviment" SIZE 707,229 OF ;
    oFdFactur:adialogs[2] FONT J02FONTLB COLORS J02CLRTEXTO,J02CLRFONDO UPDATE ;
    PIXEL //FIVEWIDI

@ 134,45 SAY "F3-Busca:" OF oFdFactur:adialogs[2] COLORS J02CLRTEXTO,;
    J02CLRFONDO FONT J02FONTSAY PIXEL SIZE 55,16 UPDATE //FIVEWIDI

....

// *******************************************************
// Y para acabar al final del PRG se activa la MDIChild

ACTIVATE WINDOW oFactur01 ;   //    MAXIMIZED ; ON INIT oLBmnda:Set( JuvaArra[1][2][5][3] ) ;
            VALID ( If( nEditando == 0, ;
                        If( JuvaArra[4][1], ;
                            (oPrint:SetFocus(), oSWnd:SetFocus(), oSMdiDlgFo:SetFocus(), SysRefresh(), ; //                             laTDbfEnd( JuvaArra, { oTDbfFactur, oSTdbfFactur, oTDbfFacIva, oTdbfConFac, oTdbfPerson, oTdbfDestin, oTdbfArticu } ), ;                             oSWnd:SetFocus(), ;
                             If( lExiste := !oSMdiDlgFo:End(), ;
                                 Nil, ;
                                 (SysRefresh(), lWndSalta( JuvaArra, Nil), laTDbfEnd( JuvaArra, { oTDbfFactur, oSTdbfFactur, oTDbfFacIva, oTdbfConFac, oTdbfPerson, oTdbfDestin, oTdbfArticu } ), ;
                                  oSMdiDlgFo := oSTdbfFactur := oSWnd := oSToFol1 := oSRecno := oSGo := oSModi := oSPrint := Nil ) ;
                               ), ;
                            !lExiste ), ;
                            (lWndSalta( JuvaArra, oFactur01), oSWnd:Hide(), .F. ) ;
                          ) , ;
                        ( Eval( oSGo:bAction ), .F.) ;
                      ) ;
                  ) ;
          ON INIT AutResiz( oFactur01, 2 )

El usuario en el menu tiene '<<' y '>>' para poder cambiar entre MDICHILD

Nota: Seguro que el código asusta, pero es de hace 20 años... o más.

Un Saludo

Carlos G.



FiveWin 25.12 + Harbour 3.2.0dev (r2502110321), BCC 7.7 Windows 11 Home

Posts: 3022
Joined: Fri Oct 07, 2005 01:45 PM
Re: MDI Questions
Posted: Fri Feb 13, 2026 09:52 PM

Thank you. That will be VERY helpful.

Tim

Tim Stone
http://www.MasterLinkSoftware.com
http://www.autoshopwriter.com
timstone@masterlinksoftware.com
Using: FWH 23.10 with Harbour 3.2.0 / Microsoft Visual Studio Community 2022-24 32/64 bit
Posts: 2706
Joined: Fri Oct 07, 2005 01:50 PM
Re: MDI Questions
Posted: Sat Feb 14, 2026 07:58 PM

Tim .. Been writing MDI code for years ... Wanted to add my sample code to the list

DEFINE ICON oICO RESOURCE "ACUSTOMER"
DEFINE BITMAP oBMAP FILENAME (cDEFA+"\LOGO.BMP")    of oWind        // logo
DEFINE BITMAP oBMP  FILENAME (cDEFA+"\DAYCARE.BMP") of oWind

DEFINE WINDOW oWind                                          ;
   FROM 0,2 to 28,78                                         ;
   TITLE "Daycare Information Systems"                       ;
   MENU _BuildMenu( cDEFA,dEXE,cRDD,nSCR1,nSCR2 )            ;     

   ICON oICO                                                 ;
   MDI

   DEFINE BUTTONBAR oBar OF oWind SIZE 80,64 2010    // 80,58   80,64
  

   oBar:bClrGrad = { || { { 0.10,15724527,7303023 }, ;       // grey
       { 0.10,7303023,15724527 } } }

   DEFINE BUTTON oButt1 of oBar ACTION ( _ParnBrow( oWind )) ;
          RESOURCE "Employee" PROMPT "Parent-Child"+CRLF+"Fees-Receipts"
   oButt1:cToolTip := { " " + CRLF + "Parent Child Information","Fee Info Charges and Receipts", 1, CLR_BLACK, 14089979  }

   DEFINE BUTTON oButt3 of oBar ACTION ( _Rptmenu( oWind )   ) ;
          RESOURCE "report"     PROMPT "Reports"
   oButt3:cToolTip := { " " + CRLF + "Run Reports and Answer Questions", "Report Information", 1, CLR_BLACK, 14089979  }

   DEFINE BUTTON oButt4 of oBar ACTION (nil ) 

   DEFINE BUTTON oButt5 of oBar ACTION ( nil )  // hide this

   DEFINE BUTTON oButt6 of oBar ACTION ( _UTILmenu( oWIND ));
          RESOURCE "controlpanel" PROMPT "Control Panel"
   oButt6:cToolTip := { " " + CRLF + "System Information", "User Defined Tables", 1, CLR_BLACK, 14089979  }

   DEFINE BUTTON oButt7 of oBar ACTION (_WebHelp( dExe )) ;
          RESOURCE "palmetto" PROMPT "Created in South Carolina"
   oButt7:cToolTip := { " " + CRLF + "System Information", "Help and About", 1, CLR_BLACK, 14089979  }

   DEFINE BUTTON oButt8 of oBar ACTION (SHELLEXECUTE(nil,"open", "calc.exe",0,0,1)) ;
          RESOURCE "calculator" PROMPT "Calculator"
   oButt8:cToolTip := { " " + CRLF + "Bring Up the Calculator", "Calculator", 1, CLR_BLACK, 14089979  }

   DEFINE BUTTON oButt9 of oBar ACTION oWind:End();
          RESOURCE "exit" PROMPT "Quit"
   oButt9:cToolTip := { " " + CRLF + "Close this Program", "Quit", 1, CLR_BLACK, 14089979  }


   SET MESSAGE OF oWind        ;
       to xMessage CLOCK 2010

ACTIVATE WINDOW oWind                                         ;
   MAXIMIZED ;
   ON INIT  ( IF( nSCR1 < 1024, _ResMessage(nSCR1, nSCR2), ),_ChkOwner( oWind,cFirst)); // 560,230
   ON PAINT ( IF( xTEXT = "/NL", ,PalBmpDraw( hDC, 0,0, oBmp:hBitmap,  oBmp:hPalette, nSCR1, nSCR2 )),;
                    PalBmpDraw( hDC, _UpDown(), _RightLeft(), oBMAP:hBitmap, oBMAP:hPalette,305,191 ));
   VALID ( IIF( !lExitPgm, _ExitPgm( .T.,@lExitPgm ) , .F. ))

RETURN( NIL )

Continue the discussion