Sign in Join
Wiki copytemporary

macOS NSStatusBar: what changed

Revision 0 to 1. Removed lines have a minus sign; added lines have a plus sign.

Title: macOS NSStatusBar

OldNewLine
1+*(macOS only)*
2+
3+## Overview
4+
5+NSStatusBar is an object that manages a collection of status items that provide interaction with or feedback to the user. A status item can be displayed with text or an icon, can provide a menu or send a target-action message when clicked. Use status items sparingly and only if the alternatives (such as a Dock menu, preference pane, or status window) are not suitable. As there is limited space in which to display status items, status items are not guaranteed to be available at all times. For this reason, Apple recommends that you do not rely on them being available and always provide a user preference for hiding your application’s status items to free up space in the menu bar.
6+
7+![](/wiki-images/3/38/MacOS_Status_Bar.png)
8+
9+Only one status bar, the system status bar, is available in macOS. It resides in the system-wide menu bar as shown above. Status items appear on the right side of the menu bar, just to the left of the menu bar clock and Menu Extras, such as the Displays and Sound menus. The items remain in the menu bar even when your application is not in the foreground.
10+
11+## Creating status items
12+
13+1\. Obtain the system status bar with the **systemStatusBar** class method; you should not allocate an instance of it yourself. ' 2A. If you are displaying an icon, invoke **statusItemWithLength** to create a new status item and allocate space for it in the menu bar. Pass the amount of space in pixels you need to display your status item. You can use the constant **NSSquareStatusItemLength** to make the width the same as the status bar’s thickness.
14+
15+2B. If you are displaying text, invoke **statusItemWithLength** to create a new status item and allocate space for it in the menu bar. Pass the amount of space in pixels you need to display your status item. You can use the constant **NSVariableStatusItemLength** to make the width variable based on the contents of the item.
16+
17+The system status bar is shared by all applications and therefore cannot retain references to each application’s status item objects. Instead, each application is responsible for retaining its own status items. Each status item then communicates with the status bar as its configuration changes. When deallocated, the status item removes itself from the status bar. Following normal Cocoa memory management rules, you **must retain the object** returned by statusItemWithLength to keep it around.
18+
19+Once you have the new status item object, you can assign it a title, a menu, a target-action, a tool tip, and so on.
20+
21+## Example code for a text status item menu
22+
23+![](/wiki-images/b/bc/Ex1_Menu_Bar.png)
24+
25+This example application places a text status item named "Captioner" on the system-wide menu bar. Clicking on the item reveals a menu with three options, two of which change the caption on the application's title bar while the third quits the application. The toggle button allows you to toggle the status item on/off. By calling the ToggleButtonClick handler from the OnCreate event of the Form, the status item appears automagically when the application is launched.
26+
27+``` pascal
28+unit Unit1;
29+
30+{$mode objfpc}{$H+}
31+{$modeswitch objectivec1}
32+
33+interface
34+
35+uses
36+ Forms, Dialogs, StdCtrls,
37+ CocoaAll, Classes;
38+
39+type
40+
41+ { TForm1 }
42+
43+ TForm1 = class(TForm)
44+ ToggleButton: TButton;
45+ procedure ToggleButtonClick(Sender: TObject);
46+ procedure FormCreate(Sender: TObject);
47+ private
48+
49+ public
50+
51+ end;
52+
53+ { TMyDelegate }
54+
55+ TMyAppDelegate = objcclass(NSObject)
56+ private
57+
58+ public
59+ procedure menuItem1;
60+ message 'menuItem1';
61+ procedure menuItem2;
62+ message 'menuItem2';
63+ procedure menuItem3;
64+ message 'menuItem3';
65+ end;
66+var
67+ Form1: TForm1;
68+ myAppDelegate: TMyAppDelegate;
69+ myStatusBarItem: NSStatusItem;
70+ sbi_created: Boolean = False;
71+
72+implementation
73+
74+{$R *.lfm}
75+
76+{ TForm1 }
77+
78+// AppDelegate methods
79+procedure TMyAppDelegate.menuItem1;
80+begin
81+ Form1.Caption := 'Hello menu item 1';
82+end;
83+
84+procedure TMyAppDelegate.menuItem2;
85+begin
86+ Form1.Caption := 'Hello menu item 2';
87+end;
88+
89+procedure TMyAppDelegate.menuItem3;
90+begin
91+ Form1.Close;
92+end;
93+
94+// ToggleButton handler
95+procedure TForm1.ToggleButtonClick(Sender: TObject);
96+var
97+ statusBar: NSStatusBar;
98+ myMenu: NSMenu;
99+ myMenuItem1: NSMenuItem;
100+ myMenuItem2: NSMenuItem;
101+ myMenuItem3: NSMenuItem;
102+ aSEL1: SEL;
103+ aSEL2: SEL;
104+ aSEL3: SEL;
105+begin
106+ // If status bar item exists
107+ if(sbi_created <> False) then
108+ begin
109+ // Remove item
110+ NSStatusBar.systemStatusBar.removeStatusItem(myStatusBarItem);
111+ myStatusBarItem := Nil;
112+ // Allow new one to be created next time
113+ sbi_created := False;
114+ exit;
115+ end
116+ else
117+ sbi_created := True;
118+
119+ // Obtain system-wide status bar instance
120+ statusBar := NSStatusBar.systemStatusBar;
121+
122+ // Setup selectors for menu item actions
123+ aSel1 := ObjCSelector(TMyAppDelegate.menuItem1);
124+ aSel2 := ObjCSelector(TMyAppDelegate.menuItem2);
125+ aSel3 := ObjCSelector(TMyAppDelegate.menuItem3);
126+
127+ // Create menu
128+ myMenu := NSMenu.alloc.init.autorelease;
129+ myMenuItem1 := NSMenuItem.alloc.initWithTitle_action_keyEquivalent(NSStr('Menu item 1'),aSEL1, NSStr('A')).autorelease;
130+ myMenuItem2 := NSMenuItem.alloc.initWithTitle_action_keyEquivalent(NSStr('Menu item 2'),aSEL2, NSStr('B')).autorelease;
131+ myMenuItem3 := NSMenuItem.alloc.initWithTitle_action_keyEquivalent(NSStr('Quit'),aSEL3, NSStr('Q')).autorelease;
132+ myMenu.addItem(myMenuItem1);
133+ myMenu.addItem(myMenuItem2);
134+ myMenu.addItem(myMenuItem3);
135+
136+ // Setup my status bar item
137+ myStatusBarItem := statusBar.statusItemWithLength(NSVariableStatusItemLength);
138+ myStatusBarItem.setTitle(NSStr('Captioner'));
139+ myStatusBarItem.setHighlightMode(True);
140+ myStatusBarItem.setMenu(myMenu);
141+
142+ // Important! You must retain the object or it will disappear when the
143+ // variable goes out of scope
144+ myStatusBarItem.retain;
145+end;
146+
147+// Form creation
148+procedure TForm1.FormCreate(Sender: TObject);
149+begin
150+ // NSApp
151+ // - The global variable for the shared application instance.
152+ // NSApplication.sharedApplication
153+ // - Returns the application instance, creating it if it doesn’t exist yet.
154+ NSApp := NSApplication.sharedApplication;
155+
156+ // Setup my application delegate
157+ NSApp.setDelegate(myAppDelegate);
158+
159+ // Show status bar item
160+ ToggleButtonClick(self);
161+end;
162+
163+Initialization
164+ myAppDelegate := TMyAppDelegate.alloc.init;
165+
166+Finalization
167+ myAppDelegate.Release;
168+end.
169+```
170+
171+Full project source code is available on [SourceForge](https://sourceforge.net/p/lazarus-wiki-projects/code/ci/master/tree/laz_nsstatusbar/).
172+
173+## Example code for an image status item
174+
175+![](/wiki-images/4/44/Ex2_Menu_Bar.png)
176+
177+This example application places a status item image on the system-wide menu bar. Clicking on the item reveals a menu with three options, two of which change the caption on the application's title bar while the third quits the application. The toggle button allows you to toggle the status item on/off. By calling the ToggleButtonClick handler from the OnCreate event of the Form, the status item appears automagically when the application is launched.
178+
179+This code is pretty much identical to the previous code above - the new and changed lines have been highlighted. The image file, `icon.png` is located in the [[Application Bundle|application bundle's]] Resources directory.
180+
181+``` pascal
182+unit Unit1;
183+
184+{$mode objfpc}{$H+}
185+{$modeswitch objectivec1}
186+
187+interface
188+
189+uses
190+ Forms, StdCtrls,
191+ CocoaAll, Classes;
192+
193+type
194+
195+ { TForm1 }
196+
197+ TForm1 = class(TForm)
198+ ToggleButton: TButton;
199+ procedure ToggleButtonClick(Sender: TObject);
200+ procedure FormCreate(Sender: TObject);
201+ private
202+
203+ public
204+
205+ end;
206+
207+ { TMyDelegate }
208+
209+ TMyAppDelegate = objcclass(NSObject)
210+ private
211+
212+ public
213+ procedure menuItem1;
214+ message 'menuItem1';
215+ procedure menuItem2;
216+ message 'menuItem2';
217+ procedure menuItem3;
218+ message 'menuItem3';
219+ end;
220+var
221+ Form1: TForm1;
222+ myAppDelegate: TMyAppDelegate;
223+ myStatusBarItem: NSStatusItem;
224+ sbi_created: Boolean = False;
225+
226+implementation
227+
228+{$R *.lfm}
229+
230+{ TForm1 }
231+
232+// AppDelegate methods
233+procedure TMyAppDelegate.menuItem1;
234+begin
235+ Form1.Caption := 'Hello menu item 1';
236+end;
237+
238+procedure TMyAppDelegate.menuItem2;
239+begin
240+ Form1.Caption := 'Hello menu item 2';
241+end;
242+
243+procedure TMyAppDelegate.menuItem3;
244+begin
245+ Form1.Close;
246+end;
247+
248+// ToggleButton handler
249+procedure TForm1.ToggleButtonClick(Sender: TObject);
250+var
251+ statusBar: NSStatusBar;
252+ myMenu: NSMenu;
253+ myMenuItem1: NSMenuItem;
254+ myMenuItem2: NSMenuItem;
255+ myMenuItem3: NSMenuItem;
256+ aSEL1: SEL;
257+ aSEL2: SEL;
258+ aSEL3: SEL;
259+ myImage: NSImage;
260+begin
261+ // If status bar item exists
262+ if(sbi_created <> False) then
263+ begin
264+ // Remove item
265+ NSStatusBar.systemStatusBar.removeStatusItem(myStatusBarItem);
266+ myStatusBarItem := Nil;
267+ // Allow new one to be created next time
268+ sbi_created := False;
269+ exit;
270+ end
271+ else
272+ sbi_created := True;
273+
274+ // Obtain system-wide status bar instance
275+ statusBar := NSStatusBar.systemStatusBar;
276+
277+ // Setup selectors for menu item actions
278+ aSel1 := ObjCSelector(TMyAppDelegate.menuItem1);
279+ aSel2 := ObjCSelector(TMyAppDelegate.menuItem2);
280+ aSel3 := ObjCSelector(TMyAppDelegate.menuItem3);
281+
282+ // Create menu
283+ myMenu := NSMenu.alloc.init.autorelease;
284+ myMenuItem1 := NSMenuItem.alloc.initWithTitle_action_keyEquivalent(NSStr('Menu item 1'),aSEL1, NSStr('A')).autorelease;
285+ myMenuItem2 := NSMenuItem.alloc.initWithTitle_action_keyEquivalent(NSStr('Menu item 2'),aSEL2, NSStr('B')).autorelease;
286+ myMenuItem3 := NSMenuItem.alloc.initWithTitle_action_keyEquivalent(NSStr('Quit'),aSEL3, NSStr('Q')).autorelease;
287+ myMenu.addItem(myMenuItem1);
288+ myMenu.addItem(myMenuItem2);
289+ myMenu.addItem(myMenuItem3);
290+
291+ // Setup my status bar item
292+ myStatusBarItem := statusBar.statusItemWithLength(NSSquareStatusItemLength);
293+ myImage := NSImage.alloc.initWithContentsOfFile(NSBundle.mainBundle.pathForImageResource(NSStr('icon.png'))).autorelease;
294+ myStatusBarItem.button.setImage(myImage);
295+ myStatusBarItem.setHighlightMode(True);
296+ myStatusBarItem.setMenu(myMenu);
297+
298+ // Important! You must retain the object or it will disappear when the
299+ // variable goes out of scope
300+ myStatusBarItem.retain;
301+end;
302+
303+// Form creation
304+procedure TForm1.FormCreate(Sender: TObject);
305+begin
306+ // NSApp
307+ // - The global variable for the shared application instance.
308+ // NSApplication.sharedApplication
309+ // - Returns the application instance, creating it if it doesn’t exist yet.
310+ NSApp := NSApplication.sharedApplication;
311+
312+ // Setup my application delegate
313+ NSApp.setDelegate(myAppDelegate);
314+
315+ // Show status bar item
316+ ToggleButtonClick(self);
317+end;
318+
319+Initialization
320+ myAppDelegate := TMyAppDelegate.alloc.init;
321+
322+Finalization
323+ myAppDelegate.Release;
324+end.
325+```
326+
327+Full project source code available from [SourceForge](https://sourceforge.net/p/lazarus-wiki-projects/code/ci/master/tree/laz_nsstatusbar2/).
328+
329+## See also
330+
331+- [[macOS Application Dock Menu]]
332+- [[Apple-specific UI elements]]
333+
334+## External links
335+
336+- [Apple: NSStatusBar](https://developer.apple.com/documentation/appkit/nsstatusbar)
337+- [Apple: NSStatusItem](https://developer.apple.com/documentation/appkit/nsstatusitem)
338+- [Apple: NSImage](https://developer.apple.com/documentation/appkit/nsimage)
339+
340+---
341+*From the Free Pascal wiki, page "macOS NSStatusBar", as it stood on 2021-12-15 after a change by Trev, out of the wiki's dump of 2024-05-26. Copyright stays with the author who wrote it, according to the old wiki's [[Licensing]] page. If you have concerns about this material, [message the admin](/wiki-contact).*
342+Category: Code
343+Category: Platform-sensitive development
344+Category: macOS

Back to history