Create Modal Window

Just starting out? Need help? Post your questions and find answers here.
WilliamL
Addict
Addict
Posts: 1255
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Create Modal Window

Post by WilliamL »

I've been using 'requesters' as modal windows but I'd like to have more options in the window so I'm looking into modal windows.

I googled and came up with this (see below-this is googles code). It all look pretty straightforward but I'm confused as to whether there needs to be a separate event loop in the modal procedure? The comments below the code were also interesting.

I think a few years ago I made a 'modal window' that used the main event loop but I didn't like how it was coded. Having the event loop in the modal window is much simpler but I was told that you should only have one event loop,

Code: Select all

; Main Window
Enumeration
  #MainWindow
  #OpenModalButton
EndEnumeration

If OpenWindow(#MainWindow, 100, 100, 400, 300, "Main Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ButtonGadget(#OpenModalButton, 100, 100, 200, 30, "Open Modal Window")

  Repeat
    Event = WaitWindowEvent()

    Select Event
      Case #PB_Event_Gadget
        If EventGadget() = #OpenModalButton
          ; Open the modal window
          ModalWindow()
        EndIf

      Case #PB_Event_CloseWindow
        If EventWindow() = #MainWindow
          End
        EndIf
    EndSelect
  Forever
EndIf

Procedure ModalWindow()
  ; Modal Window
  Enumeration
    #ModalWindow
    #CloseModalButton
  EndEnumeration

  If OpenWindow(#ModalWindow, 200, 200, 300, 150, "Modal Dialog", #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Dialog)
    ButtonGadget(#CloseModalButton, 100, 80, 100, 30, "Close")

    ; Disable the main window while the modal is open
    DisableWindow(#MainWindow, #True)

    Repeat
      Event = WaitWindowEvent()

      Select Event
        Case #PB_Event_Gadget
          If EventGadget() = #CloseModalButton
            Break ; Exit the modal loop
          EndIf

        Case #PB_Event_CloseWindow
          If EventWindow() = #ModalWindow
            Break ; Exit the modal loop
          EndIf
      EndSelect
    ForEver

    CloseWindow(#ModalWindow)
    ; Re-enable the main window
    DisableWindow(#MainWindow, #False)
  EndIf
EndProcedure
Explanation:
Main Window: An initial window is created with a button to trigger the modal.
ModalWindow() Procedure:
A new window (#ModalWindow) is opened. The #PB_Window_Dialog flag is important here as it gives the window a typical dialog appearance.
DisableWindow(#MainWindow, #True) is used to prevent interaction with the main window while the modal is active, enforcing its "modality."
A Repeat...Forever loop handles events specifically for the modal window. The loop continues until the close button is clicked or the window is closed.
CloseWindow(#ModalWindow) closes the modal window.
DisableWindow(#MainWindow, #False) re-enables the main window, allowing user interaction again.
This approach ensures that the user must interact with and close the modal window before they can return to the main application window.
MacBook Pro-M1 (2021), Tahoe 26.1, PB 6.31b2
User avatar
jacdelad
Addict
Addict
Posts: 2041
Joined: Wed Feb 03, 2021 12:46 pm
Location: Riesa

Re: Create Modal Window

Post by jacdelad »

Where did you find the code? Did you run it even once? I didn't, but on sure it won't run: the procedure has to be placed before calling it or you need to add a Declare.

Regarding your question: You usually should only write one event loop, but in this case the main window is disabled while the subwindow is open, so it cannot receive anything. The second event loop especially processes the subwindow. This seems ok to me. If the main window would still be active, you should process the subwindow within the main loop (which should be your only loop).

Update: This code is nonsense, the second enumeration gives the modal window the same value as the main window, so the main windows won't be accessible again. Or do I misunderstand the purpose of the code (alternating windows, in this case one event loop would make more sense and you wouldn't need to deactivate the main window)?
Good morning, that's a nice tnetennba!

PureBasic 6.21/Windows 11 x64/Ryzen 7900X/32GB RAM/3TB SSD
Synology DS1821+/DX517, 130.9TB+50.8TB+2TB SSD
User_Russian
Addict
Addict
Posts: 1601
Joined: Wed Nov 12, 2008 5:01 pm
Location: Russia

Re: Create Modal Window

Post by User_Russian »

Code: Select all

; Main Window
Enumeration Window
  #MainWindow
EndEnumeration

Enumeration Gadget
  #OpenModalButton
EndEnumeration

Declare ModalWindow()

If OpenWindow(#MainWindow, 100, 100, 400, 300, "Main Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ButtonGadget(#OpenModalButton, 100, 100, 200, 30, "Open Modal Window")

  Repeat
    Event = WaitWindowEvent()

    Select Event
      Case #PB_Event_Gadget
        If EventGadget() = #OpenModalButton
          ; Open the modal window
          ModalWindow()
        EndIf

      Case #PB_Event_CloseWindow
        If EventWindow() = #MainWindow
          End
        EndIf
    EndSelect
  ForEver
EndIf


; Modal Window
Enumeration Window
  #ModalWindow
EndEnumeration

Enumeration Gadget
  #CloseModalButton
EndEnumeration

Procedure ModalWindow_Event()
  Event = Event()
  
  Select Event
    Case #PB_Event_Gadget
      If EventGadget() = #CloseModalButton
        PostEvent(#PB_Event_CloseWindow, EventWindow(), EventWindow())
      EndIf
    Case #PB_Event_CloseWindow
      UnbindEvent(#PB_Event_Gadget, @ModalWindow_Event(), #ModalWindow)
      UnbindEvent(#PB_Event_CloseWindow, @ModalWindow_Event(), #ModalWindow)
      CloseWindow(#ModalWindow)
      ; Re-enable the main window
      DisableWindow(#MainWindow, #False)
  EndSelect
  
EndProcedure

Procedure ModalWindow()

  If OpenWindow(#ModalWindow, 200, 200, 300, 150, "Modal Dialog", #PB_Window_SystemMenu | #PB_Window_ScreenCentered, WindowID(#MainWindow))
    ButtonGadget(#CloseModalButton, 100, 80, 100, 30, "Close")
    ; Disable the main window while the modal is open
    DisableWindow(#MainWindow, #True)
    BindEvent(#PB_Event_Gadget, @ModalWindow_Event(), #ModalWindow)
    BindEvent(#PB_Event_CloseWindow, @ModalWindow_Event(), #ModalWindow)
  EndIf
EndProcedure
infratec
Always Here
Always Here
Posts: 7681
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Create Modal Window

Post by infratec »

Code: Select all

EnableExplicit

Enumeration Windows
  #MainWindow
EndEnumeration

Enumeration Gadgets
  #OpenModalButton
EndEnumeration


Structure ModalWindowData_Structure
  WindowToDisable.i
  CloseButton.i
EndStructure


Procedure ModalWindow_CloseWindow()
  
  Protected.i Window
  Protected *ModalWindowData.ModalWindowData_Structure
  
  Window = EventWindow()
  *ModalWindowData = GetWindowData(Window)
  
  UnbindGadgetEvent(*ModalWindowData\CloseButton, @ModalWindow_CloseWindow())
  UnbindEvent(#PB_Event_CloseWindow, @ModalWindow_CloseWindow(), Window)
  
  CloseWindow(Window)
  
  DisableWindow(*ModalWindowData\WindowToDisable, #False)
  SetActiveWindow(*ModalWindowData\WindowToDisable)
  
  FreeStructure(*ModalWindowData)
  
EndProcedure


Procedure ModalWindow(WindowToDisable.i)
  
  Protected.i Window
  Protected *ModalWindowData.ModalWindowData_Structure
  
  Window = OpenWindow(#PB_Any, 200, 200, 300, 150, "Modal Dialog", #PB_Window_SystemMenu | #PB_Window_WindowCentered, WindowID(WindowToDisable))
  If Window
    *ModalWindowData = AllocateStructure(ModalWindowData_Structure)
    
    SetWindowData(Window, *ModalWindowData)
    
    *ModalWindowData\WindowToDisable = WindowToDisable
    
    *ModalWindowData\CloseButton = ButtonGadget(#PB_Any, 100, 80, 100, 30, "Close")
    
    ; Disable the main window while the modal is open
    DisableWindow(WindowToDisable, #True)
    
    BindEvent(#PB_Event_CloseWindow, @ModalWindow_CloseWindow(), Window)
    BindGadgetEvent(*ModalWindowData\CloseButton, @ModalWindow_CloseWindow())
  EndIf
  
EndProcedure


Define.i Event


If OpenWindow(#MainWindow, 100, 100, 400, 300, "Main Window", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  ButtonGadget(#OpenModalButton, 100, 100, 200, 30, "Open Modal Window")
  
  Repeat
    Event = WaitWindowEvent()
    If EventWindow() = #MainWindow
      Select Event
        Case #PB_Event_Gadget
          If EventGadget() = #OpenModalButton
            ModalWindow(#MainWindow)
          EndIf
          
        Case #PB_Event_CloseWindow
          Break
          
      EndSelect
    EndIf
  ForEver
EndIf
Last edited by infratec on Fri Nov 21, 2025 10:53 pm, edited 2 times in total.
WilliamL
Addict
Addict
Posts: 1255
Joined: Mon Aug 04, 2008 10:56 pm
Location: Seattle, USA

Re: Create Modal Window

Post by WilliamL »

No, I didn't even look carefully at the google code no less run it. :shock: I just wanted to ask about having 2 event loops.

I never thought about using bindevents and that eliminates the need for two event loops. I looked at both examples (thanks User_Russian and infratec) and they work fine. I'm going to have to look into 'bind events'. I don't think there were bindevents back when I first tried making a modal window.

Thanks for your help.
MacBook Pro-M1 (2021), Tahoe 26.1, PB 6.31b2
infratec
Always Here
Always Here
Posts: 7681
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Create Modal Window

Post by infratec »

I extended my example, so that you can see, how it is possible to store more than one value of the modal window if needed.
Also I center the modal window in the calling window and not in the screen.
You don't need any fixed value and so you can put your modal window in a module and use it for many cases.
The modal window is independent from the main program.
You can add also add x, y, title and flags to the ModalWindow() procedure.
Post Reply