Window in a Module?

Just starting out? Need help? Post your questions and find answers here.
Ramses800
User
User
Posts: 27
Joined: Wed Nov 05, 2014 3:12 pm
Location: Sweden

Window in a Module?

Post by Ramses800 »

Having a program with a main window open, is it possible to use a OpenWindow in a Module and get the events for that seconday windows gadgets to work?
I am trying to write a selfcontained module(with its own window) for general things to be reused in different project.
Another benefit would be to be able to use variable names in the module without conflicting with the main window, like for instance for common gadget names like btnClose etc.
Former VB6 developer adventuring in a brave, new Purebasic world!
User avatar
Bisonte
Addict
Addict
Posts: 1320
Joined: Tue Oct 09, 2007 2:15 am

Re: Window in a Module?

Post by Bisonte »

Code: Select all

; Make sure, that a module named common hold your extra mega super global definitions
; and declare it as the first module of your project.

DeclareModule common
  
  ; Enumeration of a Window 
  Enumeration enumWindows 1
    #Window_Main ; = 1
  EndEnumeration
  
EndDeclareModule
Module common
EndModule

; here your super feature module with an extra window...
DeclareModule Blabla1
  
  ; Here use the common module with your globals
  UseModule common
  
  ; and go on to enumerate your windows
  Enumeration enumWindows
    #Window_BlaBla1 ; = 2
  EndEnumeration
  
EndDeclareModule
Module Blabla1
EndModule

; and now use your globals in the main program
UseModule common

; and more enumerations....
Enumeration enumWindows
  #myWindow ; = 3
EndEnumeration

Debug #myWindow ; 3
Debug #Window_Main ; 1

Debug Blabla1::#Window_BlaBla1 ; 2
PureBasic 6.21 (Windows x64) | Windows 11 Pro | AsRock B850 Steel Legend Wifi | R7 9800x3D | 64GB RAM | RTX 5080 | ThermaltakeView 270 TG ARGB | build by vannicom​​
English is not my native language... (I often use DeepL.)
User avatar
TI-994A
Addict
Addict
Posts: 2754
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Window in a Module?

Post by TI-994A »

Ramses800 wrote:...is it possible to use a OpenWindow in a Module and get the events for that seconday windows gadgets to work?
...selfcontained module(with its own window)...
...to use variable names in the module without conflicting with the main window...
That's exactly what modules are for. :wink:

This example implements two modules, both with exactly the same gadget variables, used side by side without any naming conflicts. It utilises the UseModule/UnuseModule function to isolate their respective namespaces:

Code: Select all

DeclareModule Win1
  Define.i window, text, string, button
  Declare Init()
EndDeclareModule

DeclareModule Win2
  Define.i window, text, string, button
  Global.s forWin2_andBeyond
  Declare Init()
EndDeclareModule

Module Win1
  ;this GLOBAL variable IS NOT DECLARED in the module declaration
  ;so it is only available within the Win1 module (Private)
  Global.s forWin1_Only = "Win1 String (Private)"
  
  Procedure Init()
    Shared window, string, button
    window = OpenWindow(#PB_Any, 100, 200, 300, 200, "Win1 Window", #PB_Window_SystemMenu)
    text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window ends the app...")
    string = StringGadget(#PB_Any, 50, 80, 200, 30, forWin1_Only)
    button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "Win1 Button")
  EndProcedure
EndModule

Module Win2
  ;this GLOBAL variable IS DECLARED in the module declaration
  ;so it is available within & without the Win2 module (Public)
  forWin2_andBeyond = "Win2 String (Public)"
  
  Procedure Init()  
    Shared window, string, button
    window = OpenWindow(#PB_Any, 440, 200, 300, 200, "Win2 Window", #PB_Window_SystemMenu)
    text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window does not end the app...")
    string = StringGadget(#PB_Any, 50, 80, 200, 30, forWin2_andBeyond)
    button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "Press to see Win2 variable...")
  EndProcedure
EndModule

Win1::Init()
Win2::Init()
  
Repeat
  event = WaitWindowEvent()
  
  Select EventWindow()
      
    Case Win1::window      
      UseModule Win1
      Select event
        Case #PB_Event_CloseWindow
          appQuit = 1
        Case #PB_Event_Gadget
          Select EventGadget()
            Case string
              Select EventType()
                Case #PB_EventType_Change
                  SetGadgetText(button, "Typing...")
              EndSelect
            Case button
              SetGadgetText(string, "You pressed Win1::button!")
          EndSelect
        UnuseModule Win1  
      EndSelect
      
    Case Win2::window      
      UseModule Win2
      Select event
        Case #PB_Event_CloseWindow
          CloseWindow(window)
        Case #PB_Event_Gadget
          Select EventGadget()
            Case string
              Select EventType()
                Case #PB_EventType_Change
                  SetGadgetText(button, "Typing...")
              EndSelect
            Case button
              If Not seenOnce
                MessageRequester("Win2::Module", forWin2_andBeyond)
                SetGadgetText(button, "Win2 Button")
                seenOnce = #True
              Else
                SetGadgetText(string, "You pressed Win2::button!")
              EndIf 
          EndSelect
      EndSelect
      UnuseModule Win2
      
  EndSelect
Until appQuit = 1
This next example adds another window in the global scope, also using the same gadget variables. However, in such instances, the UseModule/UnuseModule function would cause name conflicts, so the module elements are referenced directly with the module separators (::) instead:

Code: Select all

DeclareModule Win1
  Define.i window, text, string, button
  Declare Init()
EndDeclareModule

DeclareModule Win2
  Define.i window, text, string, button
  Global.s forWin2_andBeyond
  Declare Init()
EndDeclareModule

Module Win1
  ;this GLOBAL variable IS NOT DECLARED in the module declaration
  ;so it is only available within the Win1 module (Private)
  Global.s forWin1_Only = "Win1 String (Private)"
  
  Procedure Init()
    Shared window, string, button
    window = OpenWindow(#PB_Any, 100, 460, 300, 200, "Win1 Window", #PB_Window_SystemMenu)
    text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window ends the app...")
    string = StringGadget(#PB_Any, 50, 80, 200, 30, forWin1_Only)
    button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "Win1 Button")
  EndProcedure
EndModule

Module Win2
  ;this GLOBAL variable IS DECLARED in the module declaration
  ;so it is available within & without the Win2 module (Public)
  forWin2_andBeyond = "Win2 String (Public)"
  
  Procedure Init()  
    Shared window, string, button      
    window = OpenWindow(#PB_Any, 440, 460, 300, 200, "Win2 Window", #PB_Window_SystemMenu)
    text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window does not end the app...")
    string = StringGadget(#PB_Any, 50, 80, 200, 30, forWin2_andBeyond)
    button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "Press to see Win2 variable...")
  EndProcedure
EndModule

Win1::Init()
Win2::Init()

Define.s forMainWindowOnly = "MainWindow String"
Define.i window = OpenWindow(#PB_Any, 250, 200, 300, 200, "MainWindow", #PB_Window_SystemMenu)
Define.i text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window ends the app...")
Define.i string = StringGadget(#PB_Any, 50, 80, 200, 30, forMainWindowOnly)
Define.i button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "MainWindow Button")
  
Repeat
  event = WaitWindowEvent()
  
  Select EventWindow()
      
    Case window      
      Select event
        Case #PB_Event_CloseWindow
          appQuit = 1
        Case #PB_Event_Gadget
          Select EventGadget()
            Case string
              Select EventType()
                Case #PB_EventType_Change
                  SetGadgetText(button, "Typing...")
              EndSelect
            Case button
              SetGadgetText(string, "You pressed MainWindow button!")
          EndSelect
      EndSelect      
      
    Case Win1::window      
      Select event
        Case #PB_Event_CloseWindow
          appQuit = 1
        Case #PB_Event_Gadget
          Select EventGadget()
            Case Win1::string
              Select EventType()
                Case #PB_EventType_Change
                  SetGadgetText(Win1::button, "Typing...")
              EndSelect
            Case Win1::button
              SetGadgetText(Win1::string, "You pressed Win1::button!")
          EndSelect
      EndSelect
      
    Case Win2::window      
      Select event
        Case #PB_Event_CloseWindow
          CloseWindow(Win2::window)
        Case #PB_Event_Gadget
          Select EventGadget()
            Case Win2::string
              Select EventType()
                Case #PB_EventType_Change
                  SetGadgetText(Win2::button, "Typing...")
              EndSelect
            Case Win2::button
              If Not seenOnce
                MessageRequester("Win2::Module", Win2::forWin2_andBeyond)
                SetGadgetText(Win2::button, "Win2 Button")
                seenOnce = #True
              Else
                SetGadgetText(Win2::string, "You pressed Win2::button!")
              EndIf 
          EndSelect
      EndSelect
      
  EndSelect
Until appQuit = 1
I threw in the forWin1_Only and forWin2_andBeyond variables simply to illustrate module scopes.

Hope it helps. :D
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Window in a Module?

Post by Danilo »

@TI-994A:
You can also do the event management within the modules, so the global event loop is not required.
Quickly modified your example:

Code: Select all

DeclareModule MainWindow
  Declare Init()
  Declare.i getWindow()
EndDeclareModule

DeclareModule ToolWindow
  Global.s forToolWindow_andBeyond
  Declare Init()
  Declare.i getWindow()
EndDeclareModule

Module MainWindow
  Global.i window, text, string, button
  ;this GLOBAL variable IS NOT DECLARED in the module declaration
  ;so it is only available within the Win1 module (Private)
  Global.s forWin1_Only = "Win1 String (Private)"
  
  ; Private
  Procedure OnCloseWindow()   : End                                                      : EndProcedure
  Procedure OnInputChange()   : SetGadgetText(button, "Typing...")                       : EndProcedure
  Procedure OnButtonClicked() : SetGadgetText(string, "You pressed MainWindow::button!") : EndProcedure
  
  ; Public
  Procedure Init()
    window = OpenWindow(#PB_Any, 100, 200, 300, 200, "MainWindow", #PB_Window_SystemMenu)
    text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window ends the app...")
    string = StringGadget(#PB_Any, 50, 80, 200, 30, forWin1_Only)
    button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "MainWindow Button")
    
    BindEvent(#PB_Event_CloseWindow,@OnCloseWindow(),window)
    BindGadgetEvent(string,@OnInputChange(),#PB_EventType_Change)
    BindGadgetEvent(button,@OnButtonClicked())
  EndProcedure
  
  Procedure.i getWindow()
      ProcedureReturn window
  EndProcedure
EndModule

Module ToolWindow
  Global.i window, text, string, button
  ;this GLOBAL variable IS DECLARED in the module declaration
  ;so it is available within & without the ToolWindow module (Public)
  forToolWindow_andBeyond = "ToolWindow String (Public)"
  
  ; Private
  Procedure OnCloseWindow() : CloseWindow(window)                : EndProcedure
  Procedure OnInputChange() : SetGadgetText(button, "Typing...") : EndProcedure
  Procedure OnButtonClicked()
    Static seenOnce
    If Not seenOnce
      MessageRequester("ToolWindow::Module", forToolWindow_andBeyond)
      SetGadgetText(button, "ToolWindow Button")
      seenOnce = #True
    Else
      SetGadgetText(string, "You pressed ToolWindow::button!")
    EndIf
  EndProcedure
  
  ; Public
  Procedure Init()
    window = OpenWindow(#PB_Any, 440, 200, 300, 200, "ToolWindow", #PB_Window_SystemMenu)
    text = TextGadget(#PB_Any, 50, 30, 250, 30, "Closing this window does not end the app...")
    string = StringGadget(#PB_Any, 50, 80, 200, 30, forToolWindow_andBeyond)
    button = ButtonGadget(#PB_Any, 50, 130, 200, 30, "Press to see ToolWindow variable...")

    BindEvent(#PB_Event_CloseWindow,@OnCloseWindow(),window)
    BindGadgetEvent(string,@OnInputChange(),#PB_EventType_Change)
    BindGadgetEvent(button,@OnButtonClicked())
  EndProcedure
  
  Procedure.i getWindow()
      ProcedureReturn window
  EndProcedure
EndModule

MainWindow::Init()
ToolWindow::Init()

Repeat : WaitWindowEvent() : ForEver
Using getWindow() only you can send messages/events to the other window via PostEvent().
User avatar
TI-994A
Addict
Addict
Posts: 2754
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Window in a Module?

Post by TI-994A »

Danilo wrote:You can also do the event management within the modules, so the global event loop is not required.
Nice, neat, and truly modular.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
davido
Addict
Addict
Posts: 1890
Joined: Fri Nov 09, 2012 11:04 pm
Location: Uttoxeter, UK

Re: Window in a Module?

Post by davido »

@TI-994A,
@Danilo,
Excellent demo.
Couldn't have done that myself: Always nice to learn something new.

Thank you, both. :D
DE AA EB
Ramses800
User
User
Posts: 27
Joined: Wed Nov 05, 2014 3:12 pm
Location: Sweden

Re: Window in a Module?

Post by Ramses800 »

Thanks for all the great advice! Off to coding it all up now....
Former VB6 developer adventuring in a brave, new Purebasic world!
Ramses800
User
User
Posts: 27
Joined: Wed Nov 05, 2014 3:12 pm
Location: Sweden

Re: Window in a Module?

Post by Ramses800 »

A followup question about BindGadgetEvent,
Is it possible to supply the Callback with a parameter? I'm thinking of keeping track of multiple windows opened from the module. Something like this(raises a syntax error)

Code: Select all

BindGadgetEvent(iThisCloseButton,@btnClose_Click(iThisWindow),#PB_EventType_LeftClick) 
Former VB6 developer adventuring in a brave, new Purebasic world!
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Window in a Module?

Post by Danilo »

No, but you can use EventWindow(), EventType(), etc. within your event procedure.

Code: Select all

Procedure btnClose_Click()
    IThisWindow = EventWindow() 
Ramses800
User
User
Posts: 27
Joined: Wed Nov 05, 2014 3:12 pm
Location: Sweden

Re: Window in a Module?

Post by Ramses800 »

@Danilo: Great tip, just what I was looking for!
Former VB6 developer adventuring in a brave, new Purebasic world!
User avatar
Blue
Addict
Addict
Posts: 972
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Window in a Module?

Post by Blue »

A question for Danilo :

In your demo,
Danilo wrote:

Code: Select all

DeclareModule MainWindow
  ...
  Declare.i getWindow()
EndDeclareModule

DeclareModule ToolWindow
  ...
  Declare.i getWindow()
EndDeclareModule

why go through the procedure getWindow() to reference the value of the window variable, instead of declaring the variable itself as public ?

There has to be a compelling reason, but it escapes me so far... :?
Last edited by Blue on Thu Mar 10, 2016 6:42 pm, edited 1 time in total.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
TI-994A
Addict
Addict
Posts: 2754
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Window in a Module?

Post by TI-994A »

Blue wrote:...why go through the procedure getWindow() to reference the value of the window variable, instead of declaring the variable itself as public ?

There has to be a compelling reason, but it escapes me so far... :?
No compelling reason. As you've pointed out, while the value could just as easily be referenced via a public variable, he has simply implemented a convenience getter function, presumably to demonstrate the private scope of global variables within a module.
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
User avatar
Blue
Addict
Addict
Posts: 972
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Window in a Module?

Post by Blue »

Thank you TI-994A for clarifying that.
That's a relief; I was so sure that I was missing something important here. :oops:
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
Danilo
Addict
Addict
Posts: 3036
Joined: Sat Apr 26, 2003 8:26 am
Location: Planet Earth

Re: Window in a Module?

Post by Danilo »

Blue wrote:A question for Danilo :

why go through the procedure getWindow() to reference the value of the window variable, instead of declaring the variable itself as public ?

There has to be a compelling reason, but it escapes me so far... :?
Well, if you declare the variable as public, it is also write-able from outside.

There is no read-only access-specifier in PB, so everybody could just overwrite it from the outside.
The Window is handled by the module internally, and to make the Window handle read-only
from the outside, I used the getter-function. Getter without Setter means read-only and
ensures encapsulation. ;)
User avatar
Blue
Addict
Addict
Posts: 972
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Window in a Module?

Post by Blue »

Danilo wrote:[...]
There is no read-only access-specifier in PB, so everybody could just overwrite it from the outside.
The Window is handled by the module internally, and to make the Window handle read-only
from the outside, I used the getter-function.
[...]
Ah, there's the compelling reason :shock:
I had a strong intuition that I was missing an important point here.
Thanks for clarifying that, Danilo.
As usual, clear, concise and informative.

As for me, as always, I greatly appreciate the learning opportunity.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
Post Reply