Skip to content

Commit 4a33f86

Browse files
pvcravenPaul V Cravenclaude
authored
Add a Windows and Views page to the programming guide (#2973)
Explains the window, when to use views, what show_view does, why on_show_view runs every time a view is shown, how events reach a view and then the window, resizing while hidden, per-view background colors, and UIView. Fixes Window.show_view's docstring, which said the new view is shown in the next frame; it calls on_hide_view and on_show_view before returning. on_show_view's docstring said it's called once. Co-authored-by: Paul V Craven <paul.craven@optimizley.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
1 parent a392f25 commit 4a33f86

3 files changed

Lines changed: 226 additions & 6 deletions

File tree

‎arcade/application.py‎

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1186,11 +1186,13 @@ def show_view(self, new_view: View) -> None:
11861186
"""
11871187
Set the currently active view.
11881188
1189-
This will hide the current view
1190-
and show the new view in the next frame.
1189+
Before returning, this calls :py:meth:`~arcade.View.on_hide_view`
1190+
on the view that was showing, if any, then
1191+
:py:meth:`~arcade.View.on_show_view` on the new view. From then on,
1192+
the new view gets the window's events, and the next frame is
1193+
drawn by it.
11911194
1192-
This is not a blocking call. It will simply point to the new view
1193-
and return immediately.
1195+
See :ref:`windows_and_views` to learn more.
11941196
11951197
Calling this function is the same as setting the
11961198
:py:attr:`arcade.Window.current_view` attribute.
@@ -1536,14 +1538,23 @@ def on_draw(self) -> bool | None:
15361538
pass
15371539

15381540
def on_show_view(self) -> None:
1539-
"""Called once when the view is shown.
1541+
"""Called each time the view is shown by :py:meth:`arcade.Window.show_view`.
1542+
1543+
A view can be shown more than once, so put one-time setup in
1544+
``__init__``, and things that should happen each time the view
1545+
appears here, such as starting music.
15401546
15411547
.. seealso:: :py:meth:`~arcade.View.on_hide_view`
15421548
"""
15431549
pass
15441550

15451551
def on_hide_view(self) -> None:
1546-
"""Called once when this view is hidden."""
1552+
"""Called each time the view stops being shown.
1553+
1554+
This happens when the window shows another view, or
1555+
:py:meth:`arcade.Window.hide_view` is called. Use it to undo what
1556+
:py:meth:`on_show_view` did, such as stopping music.
1557+
"""
15471558
pass
15481559

15491560
def on_mouse_motion(self, x: int, y: int, dx: int, dy: int) -> bool | None:

‎doc/index.rst‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ help improve Arcade.
105105
programming_guide/sound
106106
programming_guide/textures
107107
programming_guide/text
108+
programming_guide/windows_and_views
108109
programming_guide/event_loop
109110
programming_guide/camera
110111
programming_guide/sections
Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
.. _windows_and_views:
2+
3+
Windows and Views
4+
=================
5+
6+
Every Arcade game has one :py:class:`arcade.Window`. It's the window on
7+
your screen, and it receives events such as key presses, mouse movement,
8+
and the regular calls to update and draw.
9+
10+
A :py:class:`arcade.View` is one screen of your game, such as a menu,
11+
the game itself, a pause screen or a game over screen. The window shows
12+
one view at a time and passes its events to that view.
13+
14+
The Window
15+
----------
16+
17+
Create one window when your program starts:
18+
19+
.. code-block:: python
20+
21+
window = arcade.Window(1280, 720, "My Game")
22+
23+
Some useful arguments and methods:
24+
25+
* ``fullscreen=True`` opens the window full screen.
26+
:py:meth:`~arcade.Window.set_fullscreen` switches while the game runs.
27+
See the :ref:`full_screen_example` example.
28+
* ``resizable=True`` lets the player resize the window.
29+
See the :ref:`resizable_window` example.
30+
* ``update_rate`` and ``draw_rate`` set how often ``on_update`` and
31+
``on_draw`` are called, 60 times a second by default.
32+
:py:meth:`~arcade.Window.set_update_rate` and
33+
:py:meth:`~arcade.Window.set_draw_rate` change them later.
34+
* :py:attr:`~arcade.Window.background_color` is the color
35+
:py:meth:`~arcade.Window.clear` fills the window with.
36+
37+
For how often each event is called and how time is measured, see
38+
:doc:`event_loop`.
39+
40+
You can put a whole game in a :py:class:`~arcade.Window` subclass by
41+
overriding its ``on_draw``, ``on_update`` and input methods. That's fine
42+
for a small program with one screen.
43+
44+
Why Use Views?
45+
--------------
46+
47+
With several screens in one window, ``on_draw`` and every input method
48+
need to check which screen is showing:
49+
50+
.. code-block:: python
51+
52+
def on_draw(self):
53+
self.clear()
54+
if self.state == "menu":
55+
...
56+
elif self.state == "playing":
57+
...
58+
elif self.state == "game_over":
59+
...
60+
61+
A view keeps each screen in its own class instead. A view has the same
62+
event methods as a window, such as ``on_draw``, ``on_update``,
63+
``on_key_press`` and ``on_mouse_press``, and only the view being shown
64+
gets them:
65+
66+
.. code-block:: python
67+
68+
class MenuView(arcade.View):
69+
def on_draw(self):
70+
self.clear()
71+
arcade.draw_text("Press any key to start", 100, 100)
72+
73+
def on_key_press(self, symbol, modifiers):
74+
self.window.show_view(GameView())
75+
76+
77+
class GameView(arcade.View):
78+
def on_draw(self):
79+
self.clear()
80+
... # Draw the game
81+
82+
83+
window = arcade.Window(1280, 720, "My Game")
84+
window.show_view(MenuView())
85+
arcade.run()
86+
87+
Inside a view, ``self.window`` is the window showing it.
88+
89+
Showing Views
90+
-------------
91+
92+
:py:meth:`window.show_view(view) <arcade.Window.show_view>` switches to
93+
a view. Before it returns, it:
94+
95+
#. Calls :py:meth:`~arcade.View.on_hide_view` on the view that was
96+
showing, if there was one, and stops sending it events.
97+
#. Calls :py:meth:`~arcade.View.on_show_view` on the new view, and starts
98+
sending it events.
99+
100+
The next frame is drawn by the new view.
101+
:py:attr:`window.current_view <arcade.Window.current_view>` is the view
102+
being shown, and :py:meth:`~arcade.Window.hide_view` hides it without
103+
showing another.
104+
105+
A view can be shown, hidden, and shown again. ``__init__`` runs once,
106+
when you create the view, but ``on_show_view`` runs **every time** it's
107+
shown. So:
108+
109+
* Put things that should happen once in ``__init__``, such as loading
110+
sprites and sounds.
111+
* Put things that should happen each time the player arrives in
112+
``on_show_view``, such as starting music, or resetting a menu's
113+
selection.
114+
* Undo them in ``on_hide_view``, such as stopping music.
115+
116+
For example, a pause screen can keep the game view and show it again, so
117+
the game continues where it left off:
118+
119+
.. code-block:: python
120+
121+
class PauseView(arcade.View):
122+
def __init__(self, game_view):
123+
super().__init__()
124+
self.game_view = game_view
125+
126+
def on_key_press(self, symbol, modifiers):
127+
if symbol == arcade.key.ESCAPE:
128+
# The same GameView object, so nothing is reset
129+
self.window.show_view(self.game_view)
130+
131+
To start a level over instead, show a new view: ``GameView()``.
132+
133+
How Events Reach a View
134+
-----------------------
135+
136+
When the window gets an event, it calls the view's method first, then the
137+
window's own method with the same name.
138+
139+
If you subclass :py:class:`~arcade.Window` and also use views, the
140+
window's methods still run while a view is showing. For example, a
141+
window ``on_draw`` that draws a score draws it on top of every view.
142+
To stop the window's method from running for one event, return ``True``
143+
from the view's method:
144+
145+
.. code-block:: python
146+
147+
class GameView(arcade.View):
148+
def on_key_press(self, symbol, modifiers):
149+
if symbol == arcade.key.SPACE:
150+
self.player.jump()
151+
return True # The window doesn't get this key press
152+
153+
Most games that use views use :py:class:`~arcade.Window` itself, without
154+
subclassing it, so this doesn't come up.
155+
156+
Resizing
157+
--------
158+
159+
Only the view being shown gets ``on_resize``. If the window is resized
160+
while a view is hidden, the view isn't told. Cameras that match the
161+
window size should be updated when the view is shown again:
162+
163+
.. code-block:: python
164+
165+
def on_show_view(self):
166+
self.camera.match_window()
167+
168+
def on_resize(self, width, height):
169+
self.camera.match_window()
170+
171+
See :doc:`camera` for more on cameras.
172+
173+
Background Color
174+
----------------
175+
176+
Each view can have its own background color.
177+
:py:meth:`View.clear() <arcade.View.clear>` uses the view's
178+
:py:attr:`~arcade.View.background_color` if it has one, and the window's
179+
otherwise:
180+
181+
.. code-block:: python
182+
183+
class MenuView(arcade.View):
184+
def __init__(self):
185+
super().__init__(background_color=arcade.color.DARK_BLUE)
186+
187+
def on_draw(self):
188+
self.clear() # Fills with dark blue
189+
190+
GUI Views
191+
---------
192+
193+
:py:class:`arcade.gui.UIView` is a view with a
194+
:py:class:`~arcade.gui.UIManager` in ``self.ui``. It turns the GUI on in
195+
``on_show_view`` and off in ``on_hide_view``, so buttons only respond
196+
while the view is showing. If you override either method, call
197+
``super().on_show_view()`` or ``super().on_hide_view()`` so this still
198+
happens. See :ref:`gui` to learn more.
199+
200+
Learn More
201+
----------
202+
203+
* :ref:`view-tutorial`: a tutorial adding instruction and game over
204+
screens to a game
205+
* :ref:`view_screens_minimal`, :ref:`view_pause_screen` and
206+
:ref:`view_instructions_and_game_over`: examples
207+
* :ref:`sections`: splitting one view into areas that each get their own
208+
events

0 commit comments

Comments
 (0)