Repository: MyreMylar/pygame_gui
Pull request #320 (2022-08-15 08:33:37)

Add global default UIManager option
Now the first UIManager created is set as a global default fallback, if a UIManager is not supplied when creating an element this global default is used instead.

Might get confusing in applications with multiple UIManagers but for most uses should be OK.

Allows us to simplify the quick start program to this:

```python
import pygame

from pygame_gui import UIManager, UI_BUTTON_PRESSED
from pygame_gui.elements import UIButton


pygame.init()


pygame.display.set_caption('Quick Start')
window_surface = pygame.display.set_mode((800, 600))
manager = UIManager((800, 600), 'data/themes/quick_theme.json')

background = pygame.Surface((800, 600))
background.fill(manager.ui_theme.get_colour('dark_bg'))


hello_button = UIButton((350, 280), 'Hello')

clock = pygame.time.Clock()
is_running = True

while is_running:
    time_delta = clock.tick(60)/1000.0
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            is_running = False
        if event.type == UI_BUTTON_PRESSED:
            if event.ui_element == hello_button:
                print('Hello World!')
        manager.process_events(event)

    manager.update(time_delta)

    window_surface.blit(background, (0, 0))
    manager.draw_ui(window_surface)

    pygame.display.update()

```


Patch:
diff --git a/pygame_gui/core/ui_element.py b/pygame_gui/core/ui_element.py
index 1497ba9..f8d2f72 100644
--- a/pygame_gui/core/ui_element.py
+++ b/pygame_gui/core/ui_element.py
@@ -2,7 +2,7 @@ from sys import version_info
 
 import warnings
 from collections import namedtuple
-from typing import List, Union, Tuple, Dict, Any, Callable, Set
+from typing import List, Union, Tuple, Dict, Any, Callable, Set, Optional
 from typing import TYPE_CHECKING
 
 import pygame
@@ -12,6 +12,7 @@ from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterf
 from pygame_gui.core.utility import render_white_text_alpha_black_bg
 from pygame_gui.core.utility import basic_blit
 from pygame_gui.core.layered_gui_group import GUISprite
+from pygame_gui.core.utility import get_default_manager
 
 
 if TYPE_CHECKING:
@@ -42,8 +43,8 @@ class UIElement(GUISprite, IUIElementInterface):
                     override this.
     """
     def __init__(self, relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None],
+                 manager: Optional[IUIManagerInterface],
+                 container: Optional[IContainerLikeInterface],
                  *,
                  starting_height: int,
                  layer_thickness: int,
@@ -52,6 +53,10 @@ class UIElement(GUISprite, IUIElementInterface):
 
         self._layer = 0
         self.ui_manager = manager
+        if self.ui_manager is None:
+            self.ui_manager = get_default_manager()
+        if self.ui_manager is None:
+            raise ValueError("Need to create at least one UIManager to create UIElements")
 
         super().__init__(self.ui_manager.get_sprite_group())
         self.relative_rect = relative_rect.copy()
diff --git a/pygame_gui/core/utility.py b/pygame_gui/core/utility.py
index 71bf6f5..310b750 100644
--- a/pygame_gui/core/utility.py
+++ b/pygame_gui/core/utility.py
@@ -22,6 +22,21 @@ import i18n
 import pygame
 import pygame.freetype
 
+from pygame_gui.core.interfaces import IUIManagerInterface
+
+
+__default_manager = None  # type: Optional[IUIManagerInterface]
+
+
+def get_default_manager():
+    global __default_manager
+    return __default_manager
+
+
+def set_default_manager(manager: Optional[IUIManagerInterface] = None):
+    global __default_manager
+    __default_manager = manager
+
 
 if sys.version_info < (3, 9):
     import importlib_resources as resources
diff --git a/pygame_gui/elements/ui_button.py b/pygame_gui/elements/ui_button.py
index c434d74..6e88564 100644
--- a/pygame_gui/elements/ui_button.py
+++ b/pygame_gui/elements/ui_button.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict, Iterable
+from typing import Union, Tuple, Dict, Iterable, Optional
 
 import pygame
 
@@ -21,12 +21,15 @@ class UIButton(UIElement):
     The button element is reused throughout the UI as part of other elements as it happens to be a
     very flexible interactive element.
 
-    :param relative_rect: A rectangle describing the position (relative to its container) and
-                          dimensions.
+    :param relative_rect: Normally a rectangle describing the position (relative to its container) and
+                          dimensions. Also accepts a position Tuple, or Vector2 where the dimensions
+                          will be dynamic depending on the button's contents. Dynamic dimensions can
+                          be requested by setting the required dimension to -1.
     :param text: Text for the button.
-    :param manager: The UIManager that manages this element.
-    :param container: The container that this element is within. If set to None will be the root
-                      window's container.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param tool_tip_text: Optional tool tip text, can be formatted with HTML. If supplied will
                           appear on hover.
     :param starting_height: The height in layers above it's container that this element will be
@@ -40,10 +43,10 @@ class UIButton(UIElement):
                     override this.
     """
 
-    def __init__(self, relative_rect: pygame.Rect,
+    def __init__(self, relative_rect: Union[pygame.Rect, Tuple[float, float], pygame.Vector2],
                  text: str,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
                  tool_tip_text: Union[str, None] = None,
                  starting_height: int = 1,
                  parent_element: UIElement = None,
@@ -54,7 +57,10 @@ class UIButton(UIElement):
                  visible: int = 1
                  ):
 
-        super().__init__(relative_rect, manager, container,
+        rel_rect = (relative_rect if isinstance(relative_rect, pygame.Rect)
+                    else pygame.Rect(relative_rect, (-1, -1)))
+        super().__init__(rel_rect,
+                         manager, container,
                          starting_height=starting_height,
                          layer_thickness=1,
                          anchors=anchors,
@@ -69,7 +75,7 @@ class UIButton(UIElement):
 
         self.dynamic_width = False
         self.dynamic_height = False
-        self.dynamic_dimensions_orig_top_left = relative_rect.topleft
+        self.dynamic_dimensions_orig_top_left = rel_rect.topleft
         # support for an optional 'tool tip' element attached to this button
         self.tool_tip_text = tool_tip_text
         self.tool_tip = None
diff --git a/pygame_gui/elements/ui_drop_down_menu.py b/pygame_gui/elements/ui_drop_down_menu.py
index 36e01cd..3171205 100644
--- a/pygame_gui/elements/ui_drop_down_menu.py
+++ b/pygame_gui/elements/ui_drop_down_menu.py
@@ -1,4 +1,4 @@
-from typing import Union, List, Tuple, Dict
+from typing import Union, List, Tuple, Dict, Optional
 
 import pygame
 
@@ -612,7 +612,8 @@ class UIDropDownMenu(UIContainer):
     :param options_list: The list of of options to choose from. They must be strings.
     :param starting_option: The starting option, selected when the menu is first created.
     :param relative_rect: The size and position of the element when not expanded.
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If set to None will be the root
                       window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
@@ -628,8 +629,8 @@ class UIDropDownMenu(UIContainer):
                  options_list: List[str],
                  starting_option: str,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
                  parent_element: UIElement = None,
                  object_id: Union[ObjectID, str, None] = None,
                  expansion_height_limit: Union[int, None] = None,
diff --git a/pygame_gui/elements/ui_horizontal_scroll_bar.py b/pygame_gui/elements/ui_horizontal_scroll_bar.py
index 4e72fae..857a5c6 100644
--- a/pygame_gui/elements/ui_horizontal_scroll_bar.py
+++ b/pygame_gui/elements/ui_horizontal_scroll_bar.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict
+from typing import Union, Tuple, Dict, Optional
 
 import pygame
 
@@ -18,7 +18,8 @@ class UIHorizontalScrollBar(UIElement):
     :param relative_rect: The size and position of the scroll bar.
     :param visible_percentage: The horizontal percentage of the larger area that is visible,
                                between 0.0 and 1.0.
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If set to None will be the
                       root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
@@ -31,11 +32,11 @@ class UIHorizontalScrollBar(UIElement):
     def __init__(self,
                  relative_rect: pygame.Rect,
                  visible_percentage: float,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         super().__init__(relative_rect, manager, container,
diff --git a/pygame_gui/elements/ui_horizontal_slider.py b/pygame_gui/elements/ui_horizontal_slider.py
index 787b1e7..c8ec817 100644
--- a/pygame_gui/elements/ui_horizontal_slider.py
+++ b/pygame_gui/elements/ui_horizontal_slider.py
@@ -21,7 +21,8 @@ class UIHorizontalSlider(UIElement):
     :param relative_rect: A rectangle describing the position and dimensions of the element.
     :param start_value: The value to start the slider at.
     :param value_range: The full range of values.
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If set to None will be the root
                       window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
@@ -35,11 +36,11 @@ class UIHorizontalSlider(UIElement):
                  relative_rect: pygame.Rect,
                  start_value: Union[float, int],
                  value_range: Tuple[Union[float, int], Union[float, int]],
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1,
                  click_increment: Union[float, int] = 1
                  ):
diff --git a/pygame_gui/elements/ui_image.py b/pygame_gui/elements/ui_image.py
index e069335..aca54bc 100644
--- a/pygame_gui/elements/ui_image.py
+++ b/pygame_gui/elements/ui_image.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict
+from typing import Union, Tuple, Dict, Optional
 
 import pygame
 
@@ -16,9 +16,10 @@ class UIImage(UIElement):
     :param relative_rect: The rectangle that contains, positions and scales the image relative to
                           it's container.
     :param image_surface: A pygame surface to display.
-    :param manager: The UIManager that manages this element.
-    :param container: The container that this element is within. If set to None will be the root
-                      window's container.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -28,12 +29,12 @@ class UIImage(UIElement):
     def __init__(self,
                  relative_rect: pygame.Rect,
                  image_surface: pygame.surface.Surface,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  image_is_alpha_premultiplied: bool = False,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         super().__init__(relative_rect, manager, container,
diff --git a/pygame_gui/elements/ui_label.py b/pygame_gui/elements/ui_label.py
index b837ba0..8fba2ce 100644
--- a/pygame_gui/elements/ui_label.py
+++ b/pygame_gui/elements/ui_label.py
@@ -24,9 +24,10 @@ class UILabel(UIElement, IUITextOwnerInterface):
     :param relative_rect: The rectangle that contains and positions the label relative to it's
                           container.
     :param text: The text to display in the label.
-    :param manager: The UIManager that manages this label.
-    :param container: The container that this element is within. If set to None will be the root
-                      window's container.
+    :param manager: The UIManager that manages this label. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -36,11 +37,11 @@ class UILabel(UIElement, IUITextOwnerInterface):
 
     def __init__(self, relative_rect: pygame.Rect,
                  text: str,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1,
                  **text_kwargs: str):
 
diff --git a/pygame_gui/elements/ui_panel.py b/pygame_gui/elements/ui_panel.py
index b5c6bae..134f63e 100644
--- a/pygame_gui/elements/ui_panel.py
+++ b/pygame_gui/elements/ui_panel.py
@@ -1,4 +1,4 @@
-from typing import Union, Dict, Tuple
+from typing import Union, Dict, Tuple, Optional
 
 import pygame
 
@@ -25,10 +25,11 @@ class UIPanel(UIElement, IContainerLikeInterface):
                           guide for details.
     :param starting_layer_height: How many layers above its container to place this panel on.
     :param manager: The GUI manager that handles drawing and updating the UI and interactions
-                    between elements.
+                    between elements. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param margins: Controls the distance between the edge of the panel and where it's
                     container should begin.
-    :param container: The container this panel is inside of distinct from this panel's own
+    :param container: The container this panel is inside of - distinct from this panel's own
                       container.
     :param parent_element: A hierarchical 'parent' used for signifying belonging and used in
                            theming and events.
@@ -42,14 +43,14 @@ class UIPanel(UIElement, IContainerLikeInterface):
     def __init__(self,
                  relative_rect: pygame.Rect,
                  starting_layer_height: int,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  *,
                  element_id: str = 'panel',
-                 margins: Dict[str, int] = None,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 margins: Optional[Dict[str, int]] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1
                  ):
 
diff --git a/pygame_gui/elements/ui_progress_bar.py b/pygame_gui/elements/ui_progress_bar.py
index a0bf313..c3113f6 100644
--- a/pygame_gui/elements/ui_progress_bar.py
+++ b/pygame_gui/elements/ui_progress_bar.py
@@ -1,4 +1,4 @@
-from typing import Union, Dict
+from typing import Union, Dict, Optional
 
 import pygame
 
@@ -13,9 +13,10 @@ class UIProgressBar(UIStatusBar):
     A UI that will display a progress bar from 0 to 100%
 
     :param relative_rect: The rectangle that defines the size and position of the progress bar.
-    :param manager: The UIManager that manages this element.
-    :param container: The container that this element is within. If set to None will be the root
-                      window's container.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -26,11 +27,11 @@ class UIProgressBar(UIStatusBar):
 
     def __init__(self,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str, ]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         self.current_progress = 0.0
diff --git a/pygame_gui/elements/ui_screen_space_health_bar.py b/pygame_gui/elements/ui_screen_space_health_bar.py
index 17e098a..056e43e 100644
--- a/pygame_gui/elements/ui_screen_space_health_bar.py
+++ b/pygame_gui/elements/ui_screen_space_health_bar.py
@@ -1,6 +1,7 @@
-from typing import Union, Dict
+from typing import Union, Dict, Optional
 
 import pygame
+from pygame.sprite import Sprite
 
 from pygame_gui.core import ObjectID
 from pygame_gui.core.interfaces import IContainerLikeInterface, IUIManagerInterface
@@ -14,7 +15,8 @@ class UIScreenSpaceHealthBar(UIStatusBar):
     That means it won't move with the camera. This is a good choice for a user/player sprite.
 
     :param relative_rect: The rectangle that defines the size and position of the health bar.
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param sprite_to_monitor: The sprite we are displaying the health of.
     :param container: The container that this element is within. If set to None will be the root
                       window's container.
@@ -28,12 +30,12 @@ class UIScreenSpaceHealthBar(UIStatusBar):
 
     def __init__(self,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
-                 sprite_to_monitor: Union[pygame.sprite.Sprite, None] = None,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 sprite_to_monitor: Optional[Sprite] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         # Setting this here because UIProgressBar doesn't accept a percent_method in __init__.
diff --git a/pygame_gui/elements/ui_scrolling_container.py b/pygame_gui/elements/ui_scrolling_container.py
index b368eb5..c2bf93b 100644
--- a/pygame_gui/elements/ui_scrolling_container.py
+++ b/pygame_gui/elements/ui_scrolling_container.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict
+from typing import Union, Tuple, Dict, Optional
 
 import pygame
 
@@ -18,7 +18,8 @@ class UIScrollingContainer(UIElement, IContainerLikeInterface):
 
     :param relative_rect: The size and relative position of the container. This will also be the
                           starting size of the scrolling area.
-    :param manager: The UI manager for this element.
+    :param manager: The UI manager for this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param starting_height: The starting layer height of this container above it's container.
                             Defaults to 1.
     :param container: The container this container is within. Defaults to None (which is the root
@@ -32,13 +33,13 @@ class UIScrollingContainer(UIElement, IContainerLikeInterface):
     """
     def __init__(self,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  *,
                  starting_height: int = 1,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: Union[UIElement, None] = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Union[Dict[str, str], None] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         super().__init__(relative_rect,
diff --git a/pygame_gui/elements/ui_selection_list.py b/pygame_gui/elements/ui_selection_list.py
index 25c3407..5e48d24 100644
--- a/pygame_gui/elements/ui_selection_list.py
+++ b/pygame_gui/elements/ui_selection_list.py
@@ -1,4 +1,4 @@
-from typing import Union, Dict, Tuple, List
+from typing import Union, Dict, Tuple, List, Optional
 
 import pygame
 
@@ -28,7 +28,8 @@ class UISelectionList(UIElement):
                               tuple for single-selection lists or a list of strings or list of
                               (str, str) tuples for multi-selection lists.
     :param manager: The GUI manager that handles drawing and updating the UI and interactions
-                    between elements.
+                    between elements. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param allow_multi_select: True if we are allowed to pick multiple things from the selection
                                list.
     :param allow_double_clicks: True if we can double click on items in the selection list.
@@ -49,21 +50,20 @@ class UISelectionList(UIElement):
     def __init__(self,
                  relative_rect: pygame.Rect,
                  item_list: Union[List[str], List[Tuple[str, str]]],
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  *,
                  allow_multi_select: bool = False,
                  allow_double_clicks: bool = True,
-                 container: Union[IContainerLikeInterface, None] = None,
+                 container: Optional[IContainerLikeInterface] = None,
                  starting_height: int = 1,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1,
-                 default_selection: Union[
-                    str, Tuple[str, str],               # Single-selection lists
-                    List[str], List[Tuple[str, str]],   # Multi-selection lists
-                    None
-                 ] = None,
+                 default_selection: Optional[Union[
+                    str, Tuple[str, str],             # Single-selection lists
+                    List[str], List[Tuple[str, str]]  # Multi-selection lists
+                    ]] = None,
                  ):
 
         super().__init__(relative_rect,
diff --git a/pygame_gui/elements/ui_status_bar.py b/pygame_gui/elements/ui_status_bar.py
index 5b79abe..33a662b 100644
--- a/pygame_gui/elements/ui_status_bar.py
+++ b/pygame_gui/elements/ui_status_bar.py
@@ -1,4 +1,4 @@
-from typing import Union, Dict, Callable
+from typing import Union, Dict, Callable, Optional
 
 import pygame
 
@@ -28,7 +28,8 @@ class UIStatusBar(UIElement):
     :param follow_sprite: If there's a sprite, this indicates whether the bar should be drawn at the sprite's location.
     :param percent_method: Optional method signature to call to get the percent complete. (To provide a method signature,
                            simply reference the method without parenthesis, such as self.health_percent.)
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param container: The container that this element is within. If set to None will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
@@ -42,7 +43,7 @@ class UIStatusBar(UIElement):
 
     def __init__(self,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  sprite: Union[pygame.sprite.Sprite, None] = None,
                  follow_sprite: bool = True,
                  percent_method: Union[Callable[[], float], None] = None,
diff --git a/pygame_gui/elements/ui_text_box.py b/pygame_gui/elements/ui_text_box.py
index dbf0df4..b6773b2 100644
--- a/pygame_gui/elements/ui_text_box.py
+++ b/pygame_gui/elements/ui_text_box.py
@@ -54,13 +54,14 @@ class UITextBox(UIElement, IUITextOwnerInterface):
 
     :param html_text: The HTML formatted text to display in this text box.
     :param relative_rect: The 'visible area' rectangle, positioned relative to it's container.
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param wrap_to_height: False by default, if set to True the box will increase in height to
                            match the text within.
     :param layer_starting_height: Sets the height, above it's container, to start placing the text
                                   box at.
-    :param container: The container that this element is within. If set to None will be the root
-                      window's container.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -71,13 +72,13 @@ class UITextBox(UIElement, IUITextOwnerInterface):
     def __init__(self,
                  html_text: str,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  wrap_to_height: bool = False,
                  layer_starting_height: int = 1,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1,
                  *,
                  pre_parsing_enabled: bool = True):
diff --git a/pygame_gui/elements/ui_text_entry_line.py b/pygame_gui/elements/ui_text_entry_line.py
index 0cc8d9a..3759838 100644
--- a/pygame_gui/elements/ui_text_entry_line.py
+++ b/pygame_gui/elements/ui_text_entry_line.py
@@ -29,9 +29,10 @@ class UITextEntryLine(UIElement):
     the standard method for UIElements of just using the height of the input rectangle.
 
     :param relative_rect: A rectangle describing the position and width of the text entry element.
-    :param manager: The UIManager that manages this element.
-    :param container: The container that this element is within. If set to None will be the
-                      root window's container.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -67,11 +68,11 @@ class UITextEntryLine(UIElement):
 
     def __init__(self,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1,
                  *,
                  initial_text: Optional[str] = None,
diff --git a/pygame_gui/elements/ui_tool_tip.py b/pygame_gui/elements/ui_tool_tip.py
index f72d645..133a4c1 100644
--- a/pygame_gui/elements/ui_tool_tip.py
+++ b/pygame_gui/elements/ui_tool_tip.py
@@ -25,7 +25,8 @@ class UITooltip(UIElement, IUITooltipInterface):
 
     :param html_text: Text styled with HTML, to be displayed on the tooltip.
     :param hover_distance: Distance in pixels between the tooltip and the thing being hovered.
-    :param manager: The UIManager that manages this element.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -34,10 +35,10 @@ class UITooltip(UIElement, IUITooltipInterface):
     def __init__(self,
                  html_text: str,
                  hover_distance: Tuple[int, int],
-                 manager: IUIManagerInterface,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None):
+                 manager: Optional[IUIManagerInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None):
 
         super().__init__(relative_rect=pygame.Rect((0, 0), (-1, -1)),
                          manager=manager,
diff --git a/pygame_gui/elements/ui_vertical_scroll_bar.py b/pygame_gui/elements/ui_vertical_scroll_bar.py
index f132229..94417db 100644
--- a/pygame_gui/elements/ui_vertical_scroll_bar.py
+++ b/pygame_gui/elements/ui_vertical_scroll_bar.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple, Dict
+from typing import Union, Tuple, Dict, Optional
 
 import pygame
 
@@ -18,9 +18,10 @@ class UIVerticalScrollBar(UIElement):
     :param relative_rect: The size and position of the scroll bar.
     :param visible_percentage: The vertical percentage of the larger area that is visible,
                                between 0.0 and 1.0.
-    :param manager: The UIManager that manages this element.
-    :param container: The container that this element is within. If set to None will be the
-                      root window's container.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to
+                      None will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -31,11 +32,11 @@ class UIVerticalScrollBar(UIElement):
     def __init__(self,
                  relative_rect: pygame.Rect,
                  visible_percentage: float,
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         super().__init__(relative_rect, manager, container,
diff --git a/pygame_gui/elements/ui_window.py b/pygame_gui/elements/ui_window.py
index bf9f8ca..a9dbb9a 100644
--- a/pygame_gui/elements/ui_window.py
+++ b/pygame_gui/elements/ui_window.py
@@ -1,4 +1,4 @@
-from typing import Union, Tuple
+from typing import Union, Tuple, Optional
 
 import pygame
 
@@ -20,7 +20,8 @@ class UIWindow(UIElement, IContainerLikeInterface, IWindowInterface):
 
     :param rect: A rectangle, representing size and position of the window (including title bar,
                  shadow and borders).
-    :param manager: The UIManager that manages this UIWindow.
+    :param manager: The UIManager that manages this UIWindow. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param window_display_title: A string that will appear in the windows title bar if it has one.
     :param element_id: An element ID for this window, if one is not supplied it defaults to
                        'window'.
@@ -33,15 +34,15 @@ class UIWindow(UIElement, IContainerLikeInterface, IWindowInterface):
 
     def __init__(self,
                  rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  window_display_title: str = "",
-                 element_id: Union[str, None] = None,
-                 object_id: Union[ObjectID, str, None] = None,
+                 element_id: Optional[str] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
                  resizable: bool = False,
                  visible: int = 1):
 
         self.window_display_title = window_display_title
-        self._window_root_container = None  # type: Union[UIContainer, None]
+        self._window_root_container = None  # type: Optional[UIContainer]
         self.resizable = resizable
         self.minimum_dimensions = (100, 100)
         self.edge_hovering = [False, False, False, False]
@@ -66,7 +67,7 @@ class UIWindow(UIElement, IContainerLikeInterface, IWindowInterface):
 
         self.resizing_mode_active = False
         self.start_resize_point = (0, 0)
-        self.start_resize_rect = None  # type: Union[pygame.Rect, None]
+        self.start_resize_rect = None  # type: Optional[pygame.Rect]
 
         self.grabbed_window = False
         self.starting_grab_difference = (0, 0)
@@ -80,9 +81,9 @@ class UIWindow(UIElement, IContainerLikeInterface, IWindowInterface):
         self.title_bar_close_button_width = self.title_bar_height
 
         # UI elements
-        self.window_element_container = None  # type: Union[UIContainer, None]
-        self.title_bar = None  # type: Union[UIButton, None]
-        self.close_window_button = None  # type: Union[UIButton, None]
+        self.window_element_container = None  # type: Optional[UIContainer]
+        self.title_bar = None  # type: Optional[UIButton]
+        self.close_window_button = None  # type: Optional[UIButton]
 
         self.rebuild_from_changed_theme_data()
 
diff --git a/pygame_gui/elements/ui_world_space_health_bar.py b/pygame_gui/elements/ui_world_space_health_bar.py
index b11e510..9baeb51 100644
--- a/pygame_gui/elements/ui_world_space_health_bar.py
+++ b/pygame_gui/elements/ui_world_space_health_bar.py
@@ -1,4 +1,4 @@
-from typing import Union, Dict
+from typing import Union, Dict, Optional
 
 import pygame
 
@@ -18,9 +18,10 @@ class UIWorldSpaceHealthBar(UIStatusBar):
 
     :param relative_rect: The rectangle that defines the size of the health bar.
     :param sprite_to_monitor: The sprite we are displaying the health of.
-    :param manager: The UIManager that manages this element.
-    :param container: The container that this element is within. If set to None will be the root
-                      window's container.
+    :param manager: The UIManager that manages this element. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
+    :param container: The container that this element is within. If not provided or set to None
+                      will be the root window's container.
     :param parent_element: The element this element 'belongs to' in the theming hierarchy.
     :param object_id: A custom defined ID for fine tuning of theming.
     :param anchors: A dictionary describing what this element's relative_rect is relative to.
@@ -46,11 +47,11 @@ class UIWorldSpaceHealthBar(UIStatusBar):
     def __init__(self,
                  relative_rect: pygame.Rect,
                  sprite_to_monitor: Union[pygame.sprite.Sprite, ExampleHealthSprite],
-                 manager: IUIManagerInterface,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, Union[str, UIElement]] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors: Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         if sprite_to_monitor is not None:
diff --git a/pygame_gui/ui_manager.py b/pygame_gui/ui_manager.py
index 7843c38..68a6d46 100644
--- a/pygame_gui/ui_manager.py
+++ b/pygame_gui/ui_manager.py
@@ -1,5 +1,5 @@
 import os
-from typing import Tuple, List, Dict, Union, Set
+from typing import Tuple, List, Dict, Union, Set, Optional
 
 import pygame
 import i18n
@@ -14,7 +14,7 @@ from pygame_gui.core.ui_appearance_theme import UIAppearanceTheme
 from pygame_gui.core.ui_window_stack import UIWindowStack
 from pygame_gui.core.ui_container import UIContainer
 from pygame_gui.core.resource_loaders import IResourceLoader, BlockingThreadedResourceLoader
-from pygame_gui.core.utility import PackageResource
+from pygame_gui.core.utility import PackageResource, get_default_manager, set_default_manager
 from pygame_gui.core.layered_gui_group import LayeredGUIGroup
 
 from pygame_gui.elements import UITooltip
@@ -34,12 +34,14 @@ class UIManager(IUIManagerInterface):
 
     def __init__(self,
                  window_resolution: Tuple[int, int],
-                 theme_path: Union[str, PackageResource] = None,
+                 theme_path: Optional[Union[str, PackageResource]] = None,
                  enable_live_theme_updates: bool = True,
-                 resource_loader: IResourceLoader = None,
+                 resource_loader: Optional[IResourceLoader] = None,
                  starting_language: str = 'en',
-                 translation_directory_paths: List[str] = None):
+                 translation_directory_paths: Optional[List[str]] = None):
 
+        if get_default_manager() is None:
+            set_default_manager(self)
         # Translation stuff
         self._locale = starting_language
         root_path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
diff --git a/pygame_gui/windows/ui_colour_picker_dialog.py b/pygame_gui/windows/ui_colour_picker_dialog.py
index dfeb504..a79a09f 100644
--- a/pygame_gui/windows/ui_colour_picker_dialog.py
+++ b/pygame_gui/windows/ui_colour_picker_dialog.py
@@ -1,5 +1,5 @@
 import warnings
-from typing import Union, Tuple, Dict
+from typing import Union, Tuple, Dict, Optional
 
 import pygame
 
@@ -23,13 +23,14 @@ class UIColourChannelEditor(UIElement):
 
     :param relative_rect: The relative rectangle for sizing and positioning the element, relative
                           to the anchors.
-    :param manager: The UI manager for the UI system.
     :param name: Name for this colour channel, (e.g 'R:' or 'B:'). Used for the label.
     :param channel_index: Index for the colour channel (e.g. red is 0, blue is 1, hue is also 0,
                           saturation is 1)
     :param value_range: Range of values for this channel (0 to 255 for R,G,B - 0 to 360 for hue, 0
                         to 100 for the rest)
     :param initial_value: Starting value for this colour channel.
+    :param manager: The UI manager for the UI system. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param container: UI container for this element.
     :param parent_element: An element to parent this element, used for theming hierarchies and
                            events.
@@ -41,15 +42,15 @@ class UIColourChannelEditor(UIElement):
     """
     def __init__(self,
                  relative_rect: pygame.Rect,
-                 manager: IUIManagerInterface,
                  name: str,
                  channel_index: int,
                  value_range: Tuple[int, int],
                  initial_value: int,
-                 container: Union[IContainerLikeInterface, None] = None,
-                 parent_element: UIElement = None,
-                 object_id: Union[ObjectID, str, None] = None,
-                 anchors: Dict[str, str] = None,
+                 manager: Optional[IUIManagerInterface] = None,
+                 container: Optional[IContainerLikeInterface] = None,
+                 parent_element: Optional[UIElement] = None,
+                 object_id: Optional[Union[ObjectID, str]] = None,
+                 anchors:  Optional[Dict[str, Union[str, UIElement]]] = None,
                  visible: int = 1):
 
         super().__init__(relative_rect,
@@ -298,7 +299,8 @@ class UIColourPickerDialog(UIWindow):
 
     :param rect: The size and position of the colour picker window. Includes the size of shadow,
                  border and title bar.
-    :param manager: The manager for the whole of the UI.
+    :param manager: The manager for the whole of the UI. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param initial_colour: The starting colour for the colour picker, defaults to black.
     :param window_title: The title for the window, defaults to 'Colour Picker'
     :param object_id: The object ID for the window, used for theming - defaults to
@@ -306,7 +308,7 @@ class UIColourPickerDialog(UIWindow):
     :param visible: Whether the element is visible by default.
     """
     def __init__(self, rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  *,
                  initial_colour: pygame.Color = pygame.Color(0, 0, 0, 255),
                  window_title: str = "pygame-gui.colour_picker_title_bar",
diff --git a/pygame_gui/windows/ui_confirmation_dialog.py b/pygame_gui/windows/ui_confirmation_dialog.py
index 182fae1..67c2edd 100644
--- a/pygame_gui/windows/ui_confirmation_dialog.py
+++ b/pygame_gui/windows/ui_confirmation_dialog.py
@@ -1,5 +1,5 @@
 import warnings
-from typing import Union
+from typing import Union, Optional
 
 import pygame
 
@@ -17,9 +17,10 @@ class UIConfirmationDialog(UIWindow):
     or, 'Rename' for a file rename operation.
 
     :param rect: The size and position of the window, includes the menu bar across the top.
-    :param manager: The UIManager that manages this UIElement.
     :param action_long_desc: Long-ish description of action. Can make use of HTML to
                              style the text.
+    :param manager: The UIManager that manages this UIElement. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param window_title: The title of the  window.
     :param action_short_name: Short, one or two word description of action for button.
     :param blocking: Whether this window should block all other mouse interactions with the GUI
@@ -30,8 +31,8 @@ class UIConfirmationDialog(UIWindow):
     """
 
     def __init__(self, rect: pygame.Rect,
-                 manager: IUIManagerInterface,
                  action_long_desc: str,
+                 manager: Optional[IUIManagerInterface] = None,
                  *,
                  window_title: str = 'pygame-gui.Confirm',
                  action_short_name: str = 'pygame-gui.OK',
diff --git a/pygame_gui/windows/ui_console_window.py b/pygame_gui/windows/ui_console_window.py
index e761532..cd84db2 100644
--- a/pygame_gui/windows/ui_console_window.py
+++ b/pygame_gui/windows/ui_console_window.py
@@ -1,5 +1,5 @@
 import html
-from typing import Union
+from typing import Union, Optional
 
 import pygame
 
@@ -21,7 +21,8 @@ class UIConsoleWindow(UIWindow):
     Python Interactive Shell.
 
     :param rect: A rect determining the size and position of the console window.
-    :param manager: The UI manager.
+    :param manager: The UI manager. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param window_title: The title displayed in the windows title bar.
     :param object_id: The object ID for the window, used for theming - defaults to
                       '#console_window'
@@ -29,7 +30,7 @@ class UIConsoleWindow(UIWindow):
     """
     def __init__(self,
                  rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  window_title: str = 'pygame-gui.console_title_bar',
                  object_id: Union[ObjectID, str] = ObjectID('#console_window', None),
                  visible: int = 1,
diff --git a/pygame_gui/windows/ui_file_dialog.py b/pygame_gui/windows/ui_file_dialog.py
index 4247b65..7e83b78 100644
--- a/pygame_gui/windows/ui_file_dialog.py
+++ b/pygame_gui/windows/ui_file_dialog.py
@@ -1,6 +1,6 @@
 import warnings
 
-from typing import Union, List
+from typing import Union, List, Optional
 from pathlib import Path
 
 import pygame
@@ -26,7 +26,8 @@ class UIFileDialog(UIWindow):
 
     :param rect: The size and position of the file dialog window. Includes the size of shadow,
                  border and title bar.
-    :param manager: The manager for the whole of the UI.
+    :param manager: The manager for the whole of the UI. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param window_title: The title for the window, defaults to 'File Dialog'
     :param initial_file_path: The initial path to open the file dialog at.
     :param object_id: The object ID for the window, used for theming - defaults to '#file_dialog'
@@ -35,9 +36,9 @@ class UIFileDialog(UIWindow):
 
     def __init__(self,
                  rect: pygame.Rect,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface],
                  window_title: str = 'pygame-gui.file_dialog_title_bar',
-                 initial_file_path: Union[str, None] = None,
+                 initial_file_path: Optional[str] = None,
                  object_id: Union[ObjectID, str] = ObjectID('#file_dialog', None),
                  allow_existing_files_only: bool = False,
                  allow_picking_directories: bool = False,
@@ -440,8 +441,8 @@ class UIFileDialog(UIWindow):
                                   file_name=str(selected_file_name))
             self.delete_confirmation_dialog = UIConfirmationDialog(
                 rect=confirmation_rect,
-                manager=self.ui_manager,
                 action_long_desc=long_desc,
+                manager=self.ui_manager,
                 action_short_name='pygame-gui.Delete',
                 window_title='pygame-gui.Delete')
         if event.type == UI_BUTTON_PRESSED and event.ui_element == self.parent_directory_button:
diff --git a/pygame_gui/windows/ui_message_window.py b/pygame_gui/windows/ui_message_window.py
index c1eb776..5895e0b 100644
--- a/pygame_gui/windows/ui_message_window.py
+++ b/pygame_gui/windows/ui_message_window.py
@@ -1,5 +1,5 @@
 import warnings
-from typing import Union
+from typing import Union, Optional
 
 import pygame
 
@@ -15,14 +15,15 @@ class UIMessageWindow(UIWindow):
 
     :param rect: The size and position of the window, includes the menu bar across the top.
     :param html_message: The message itself. Can make use of HTML (a subset of) to style the text.
-    :param manager: The UIManager that manages this UIElement.
+    :param manager: The UIManager that manages this UIElement. If not provided or set to None,
+                    it will try to use the first UIManager that was created by your application.
     :param window_title: The title of the  window.
     :param object_id: A custom defined ID for fine tuning of theming. Defaults to '#message_window'.
     :param visible: Whether the element is visible by default.
     """
     def __init__(self, rect: pygame.Rect,
                  html_message: str,
-                 manager: IUIManagerInterface,
+                 manager: Optional[IUIManagerInterface] = None,
                  *,
                  window_title: str = 'pygame-gui.message_window_title_bar',
                  object_id: Union[ObjectID, str] = ObjectID('#message_window', None),


Test patch:
diff --git a/tests/test_core/test_ui_element.py b/tests/test_core/test_ui_element.py
index 36c017f..3b6e592 100644
--- a/tests/test_core/test_ui_element.py
+++ b/tests/test_core/test_ui_element.py
@@ -5,6 +5,7 @@ from pygame_gui.core.ui_element import UIElement
 from pygame_gui.core.ui_container import UIContainer
 from pygame_gui.core.drawable_shapes import RectDrawableShape
 from pygame_gui.core.interfaces import IUIManagerInterface
+from pygame_gui.core.utility import set_default_manager
 
 
 class TestUIElement:
@@ -15,6 +16,21 @@ class TestUIElement:
                   starting_height=0,
                   layer_thickness=1)
 
+        UIElement(relative_rect=pygame.Rect(0, 0, 50, 50),
+                  manager=None,
+                  container=None,
+                  starting_height=0,
+                  layer_thickness=1)
+
+        set_default_manager(None)
+
+        with pytest.raises(ValueError, match="Need to create at least one UIManager to create UIElements"):
+            UIElement(relative_rect=pygame.Rect(0, 0, 50, 50),
+                      manager=None,
+                      container=None,
+                      starting_height=0,
+                      layer_thickness=1)
+
     def test_create_valid_id(self, _init_pygame, default_ui_manager):
         element = UIElement(relative_rect=pygame.Rect(0, 0, 50, 50),
                             manager=default_ui_manager,
diff --git a/tests/test_elements/test_ui_button.py b/tests/test_elements/test_ui_button.py
index 4a097d6..6afab1b 100644
--- a/tests/test_elements/test_ui_button.py
+++ b/tests/test_elements/test_ui_button.py
@@ -18,8 +18,7 @@ class TestUIButton:
                       _display_surface_return_none):
         button = UIButton(relative_rect=pygame.Rect(100, 100, 150, 30),
                           text="Test Button",
-                          tool_tip_text="This is a test of the button's tool tip functionality.",
-                          manager=default_ui_manager)
+                          tool_tip_text="This is a test of the button's tool tip functionality.")
         assert button.image is not None
 
     @pytest.mark.filterwarnings("ignore:DeprecationWarning")
diff --git a/tests/test_windows/test_ui_confirmation_dialog.py b/tests/test_windows/test_ui_confirmation_dialog.py
index 514a28b..045953b 100644
--- a/tests/test_windows/test_ui_confirmation_dialog.py
+++ b/tests/test_windows/test_ui_confirmation_dialog.py
@@ -15,9 +15,9 @@ class TestUIConfirmationDialog:
                       _display_surface_return_none):
         default_ui_manager.preload_fonts([{'name': 'fira_code', 'point_size': 14, 'style': 'bold'}])
         UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                             manager=default_ui_manager,
                              action_long_desc="Confirm a <b>bold</b> test of the confirmation "
                                               "dialog.",
+                             manager=default_ui_manager,
                              window_title="Confirm",
                              action_short_name="Confirm")
 
@@ -27,18 +27,18 @@ class TestUIConfirmationDialog:
 
         with pytest.warns(UserWarning, match="Initial size"):
             UIConfirmationDialog(rect=pygame.Rect(100, 100, 50, 50),
-                                 manager=default_ui_manager,
                                  action_long_desc="Confirm a <b>bold</b> test of the confirmation "
                                                   "dialog.",
+                                 manager=default_ui_manager,
                                  window_title="Confirm",
                                  action_short_name="Confirm")
 
     def test_press_close_window_button(self, _init_pygame, default_ui_manager,
                                        _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the confirmation "
                                                                "dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -68,9 +68,9 @@ class TestUIConfirmationDialog:
     def test_press_cancel_button(self, _init_pygame, default_ui_manager,
                                  _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the confirmation "
                                                                "dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -90,9 +90,9 @@ class TestUIConfirmationDialog:
     def test_press_confirm_button(self, _init_pygame, default_ui_manager,
                                   _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -122,9 +122,9 @@ class TestUIConfirmationDialog:
     def test_update_menu_bar_grab(self, _init_pygame, default_ui_manager,
                                   _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a "
                                                                "test of the confirmation dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -138,9 +138,9 @@ class TestUIConfirmationDialog:
     def test_rebuild(self, _init_pygame, default_ui_manager,
                      _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -151,9 +151,9 @@ class TestUIConfirmationDialog:
     def test_rebuild_rounded_rectangle(self, _init_pygame, default_ui_manager,
                                        _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the confirmation "
                                                                "dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -168,9 +168,9 @@ class TestUIConfirmationDialog:
         manager = UIManager((800, 600), os.path.join("tests", "data", "themes",
                                                      "ui_confirmation_dialog_non_default.json"))
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -183,9 +183,9 @@ class TestUIConfirmationDialog:
                                                      "themes",
                                                      "ui_confirmation_dialog_bad_values.json"))
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm")
 
@@ -193,9 +193,9 @@ class TestUIConfirmationDialog:
 
     def test_show(self, _init_pygame, default_ui_manager, _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm",
                                               visible=0)
@@ -214,9 +214,9 @@ class TestUIConfirmationDialog:
 
     def test_hide(self, _init_pygame, default_ui_manager, _display_surface_return_none):
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=default_ui_manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=default_ui_manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm",
                                               visible=1)
@@ -241,9 +241,9 @@ class TestUIConfirmationDialog:
         surface = empty_surface.copy()
         manager = pygame_gui.UIManager(resolution)
         confirm_dialog = UIConfirmationDialog(rect=pygame.Rect(100, 100, 400, 300),
-                                              manager=manager,
                                               action_long_desc="Confirm a test of the "
                                                                "confirmation dialog.",
+                                              manager=manager,
                                               window_title="Confirm",
                                               action_short_name="Confirm",
                                               visible=0)