File: sec-buildapp-pref-dialog.html

package info (click to toggle)
gtkmm-documentation 4.12.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 25,772 kB
  • sloc: cpp: 15,541; javascript: 1,208; makefile: 1,080; python: 401; xml: 106; perl: 67; sh: 8
file content (688 lines) | stat: -rw-r--r-- 26,791 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" href="highlight.min.css">
<script src="highlight.min.js"></script><script>
      hljs.configure({languages: ['cpp']});
      hljs.highlightAll();
    </script><title>A preference dialog</title>
<link rel="stylesheet" type="text/css" href="style.css">
<meta name="generator" content="DocBook XSL Stylesheets Vsnapshot">
<link rel="home" href="index.html" title="Programming with gtkmm 4">
<link rel="up" href="chapter-building-applications.html" title="Chapter 31. Building applications">
<link rel="prev" href="sec-buildapp-menu.html" title="A menu">
<link rel="next" href="sec-buildapp-search-bar.html" title="Adding a search bar">
</head>
<body bgcolor="white" text="black" link="#0000FF" vlink="#840084" alink="#0000FF">
<div class="navheader">
<table width="100%" summary="Navigation header">
<tr><th colspan="3" align="center">A preference dialog</th></tr>
<tr>
<td width="20%" align="left">
<a accesskey="p" href="sec-buildapp-menu.html"><img src="icons/prev.png" alt="Prev"></a> </td>
<th width="60%" align="center">Chapter 31. Building applications</th>
<td width="20%" align="right"> <a accesskey="n" href="sec-buildapp-search-bar.html"><img src="icons/next.png" alt="Next"></a>
</td>
</tr>
</table>
<hr>
</div>
<div class="section">
<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="sec-buildapp-pref-dialog"></a>A preference dialog</h2></div></div></div>


<p>
A typical application will have some preferences that should be remembered from one run
to the next. Even for our simple example application, we may want to change the font
that is used for the content.
</p>

<p>
We are going to use <code class="classname">Gio::Settings</code> to store our preferences.
<code class="classname">Gio::Settings</code> requires a schema that describes our settings,
in our case the <code class="filename">org.gtkmm.exampleapp.gschema.xml</code> file.
</p>

<p>
Before we can make use of this schema in our application, we need to compile it into
the binary form that <code class="classname">Gio::Settings</code> expects. GIO provides macros
to do this in autotools-based projects. See the description of
<a class="ulink" href="https://docs.gtk.org/gio/class.Settings.html" target="_top">GSettings</a>.
Meson provides the <code class="function">compile_schemas()</code> function in the
<a class="ulink" href="https://mesonbuild.com/Gnome-module.html" target="_top">GNOME module</a>.
</p>

<p>
Next, we need to connect our settings to the widgets that they are supposed to control.
One convenient way to do this is to use <code class="methodname">Gio::Settings::bind()</code>
to bind settings keys to object properties, as we do for the transition setting in
<code class="classname">ExampleAppWindow</code>'s constructor.
</p>
<pre class="programlisting"><code class="code">m_settings = Gio::Settings::create("org.gtkmm.exampleapp");
m_settings-&gt;bind("transition", m_stack-&gt;property_transition_type());
</code></pre>

<p>
The code to connect the font setting is a little more involved, since it corresponds to
an object property in a <code class="classname">Gtk::TextTag</code> that we must first create.
The code is in <code class="methodname">ExampleAppWindow::open_file_view()</code>.
</p>
<pre class="programlisting"><code class="code">auto tag = buffer-&gt;create_tag();
m_settings-&gt;bind("font", tag-&gt;property_font());
buffer-&gt;apply_tag(tag, buffer-&gt;begin(), buffer-&gt;end());
</code></pre>

<p>
At this point, the application will already react if you change one of the settings,
e.g. using the <span class="command"><strong>gsettings</strong></span> commandline tool. Of course, we expect
the application to provide a preference dialog for these. So lets do that now.
Our preference dialog will be a subclass of <code class="classname">Gtk::Window</code>, and
we'll use the same techniques that we've already seen in <code class="classname">ExampleAppWindow</code>:
a <code class="classname">Gtk::Builder</code> ui file and settings bindings.
In this case the bindings are more involved, though. We use
<code class="classname">Gtk::FontDialogButton</code> and <code class="classname">Gtk::DropDown</code>
in the preference dialog. The types of the properties in these classes can't be
automatically converted to the string type that <code class="classname">Gio::Settings</code> requires.
</p>

<p>
When we've created the <code class="filename">prefs.ui</code> file and the <code class="classname">ExampleAppPrefs</code>
class, we revisit the <code class="methodname">ExampleApplication::on_action_preferences()</code>
method in our application class, and make it open a new preference dialog.
</p>
<pre class="programlisting"><code class="code">auto prefs_dialog = ExampleAppPrefs::create(*get_active_window());
prefs_dialog-&gt;present();
</code></pre>

<p>
After all this work, our application can now show a preference dialog like this:
</p>

<div class="figure">
<a name="figure-buildapp-pref-dialog"></a><p class="title"><b>Figure 31.5. A preference dialog</b></p>
<div class="figure-contents">
  
  <div class="screenshot">
    <div class="mediaobject"><img src="figures/buildapp_pref_dialog.png" alt="A preference dialog"></div>
  </div>
</div>
</div>
<br class="figure-break">

<p><a class="ulink" href="https://gitlab.gnome.org/GNOME/gtkmm-documentation/tree/master/examples/book/buildapp/step5" target="_top">Source Code</a></p>

<p>File: <code class="filename">exampleapplication.h</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "../step4/exampleapplication.h"
// Equal to the corresponding file in step4
</code></pre>
<p>File: <code class="filename">exampleappprefs.h</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#ifndef GTKMM_EXAMPLEAPPPREFS_H_
#define GTKMM_EXAMPLEAPPPREFS_H_

#include &lt;gtkmm.h&gt;

#ifdef GLIBMM_CHECK_VERSION
#define HAS_GIO_SETTINGS_BIND_WITH_MAPPING GLIBMM_CHECK_VERSION(2,75,0)
#else
#define HAS_GIO_SETTINGS_BIND_WITH_MAPPING 0
#endif

class ExampleAppPrefs : public Gtk::Window
{
public:
  ExampleAppPrefs(BaseObjectType* cobject,
    const Glib::RefPtr&lt;Gtk::Builder&gt;&amp; refBuilder);

  static ExampleAppPrefs* create(Gtk::Window&amp; parent);

protected:
#if HAS_GIO_SETTINGS_BIND_WITH_MAPPING
  // Mappings from Gio::Settings to properties
  static std::optional&lt;unsigned int&gt; map_from_ustring_to_int(const Glib::ustring&amp; transition);
  static std::optional&lt;Glib::ustring&gt; map_from_int_to_ustring(const unsigned int&amp; pos);
#else
  // Signal handlers
  void on_font_setting_changed(const Glib::ustring&amp; key);
  void on_font_selection_changed();
  void on_transition_setting_changed(const Glib::ustring&amp; key);
  void on_transition_selection_changed();
#endif
  Glib::RefPtr&lt;Gtk::Builder&gt; m_refBuilder;
  Glib::RefPtr&lt;Gio::Settings&gt; m_settings;
  Gtk::FontDialogButton* m_font {nullptr};
  Gtk::DropDown* m_transition {nullptr};
};

#endif /* GTKMM_EXAMPLEAPPPREFS_H_ */
</code></pre>
<p>File: <code class="filename">exampleappwindow.h</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#ifndef GTKMM_EXAMPLEAPPWINDOW_H_
#define GTKMM_EXAMPLEAPPWINDOW_H_

#include &lt;gtkmm.h&gt;

class ExampleAppWindow : public Gtk::ApplicationWindow
{
public:
  ExampleAppWindow(BaseObjectType* cobject,
    const Glib::RefPtr&lt;Gtk::Builder&gt;&amp; refBuilder);

  static ExampleAppWindow* create();

  void open_file_view(const Glib::RefPtr&lt;Gio::File&gt;&amp; file);

protected:
  Glib::RefPtr&lt;Gtk::Builder&gt; m_refBuilder;
  Glib::RefPtr&lt;Gio::Settings&gt; m_settings;
  Gtk::Stack* m_stack {nullptr};
  Gtk::MenuButton* m_gears {nullptr};
};

#endif /* GTKMM_EXAMPLEAPPWINDOW_H */
</code></pre>
<p>File: <code class="filename">exampleapplication.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "exampleapplication.h"
#include "exampleappwindow.h"
#include "exampleappprefs.h"
#include &lt;iostream&gt;
#include &lt;exception&gt;

ExampleApplication::ExampleApplication()
: Gtk::Application("org.gtkmm.examples.application", Gio::Application::Flags::HANDLES_OPEN)
{
}

Glib::RefPtr&lt;ExampleApplication&gt; ExampleApplication::create()
{
  return Glib::make_refptr_for_instance&lt;ExampleApplication&gt;(new ExampleApplication());
}

ExampleAppWindow* ExampleApplication::create_appwindow()
{
  auto appwindow = ExampleAppWindow::create();

  // Make sure that the application runs for as long this window is still open.
  add_window(*appwindow);

  // A window can be added to an application with Gtk::Application::add_window()
  // or Gtk::Window::set_application(). When all added windows have been hidden
  // or removed, the application stops running (Gtk::Application::run() returns()),
  // unless Gio::Application::hold() has been called.

  // Delete the window when it is hidden.
  appwindow-&gt;signal_hide().connect([appwindow](){ delete appwindow; });

  return appwindow;
}

void ExampleApplication::on_startup()
{
  // Call the base class's implementation.
  Gtk::Application::on_startup();

  // Add actions and keyboard accelerators for the menu.
  add_action("preferences", sigc::mem_fun(*this, &amp;ExampleApplication::on_action_preferences));
  add_action("quit", sigc::mem_fun(*this, &amp;ExampleApplication::on_action_quit));
  set_accel_for_action("app.quit", "&lt;Ctrl&gt;Q");
}

void ExampleApplication::on_activate()
{
  try
  {
    // The application has been started, so let's show a window.
    auto appwindow = create_appwindow();
    appwindow-&gt;present();
  }
  // If create_appwindow() throws an exception (perhaps from Gtk::Builder),
  // no window has been created, no window has been added to the application,
  // and therefore the application will stop running.
  catch (const Glib::Error&amp; ex)
  {
    std::cerr &lt;&lt; "ExampleApplication::on_activate(): " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }
  catch (const std::exception&amp; ex)
  {
    std::cerr &lt;&lt; "ExampleApplication::on_activate(): " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }
}

void ExampleApplication::on_open(const Gio::Application::type_vec_files&amp; files,
  const Glib::ustring&amp; /* hint */)
{
  // The application has been asked to open some files,
  // so let's open a new view for each one.
  ExampleAppWindow* appwindow = nullptr;
  auto windows = get_windows();
  if (windows.size() &gt; 0)
    appwindow = dynamic_cast&lt;ExampleAppWindow*&gt;(windows[0]);

  try
  {
    if (!appwindow)
      appwindow = create_appwindow();

    for (const auto&amp; file : files)
      appwindow-&gt;open_file_view(file);

    appwindow-&gt;present();
  }
  catch (const Glib::Error&amp; ex)
  {
    std::cerr &lt;&lt; "ExampleApplication::on_open(): " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }
  catch (const std::exception&amp; ex)
  {
    std::cerr &lt;&lt; "ExampleApplication::on_open(): " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }
}

void ExampleApplication::on_action_preferences()
{
  try
  {
    auto prefs_dialog = ExampleAppPrefs::create(*get_active_window());
    prefs_dialog-&gt;present();

    // Delete the dialog when it is hidden.
    prefs_dialog-&gt;signal_hide().connect([prefs_dialog](){ delete prefs_dialog; });
  }
  catch (const Glib::Error&amp; ex)
  {
    std::cerr &lt;&lt; "ExampleApplication::on_action_preferences(): " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }
  catch (const std::exception&amp; ex)
  {
    std::cerr &lt;&lt; "ExampleApplication::on_action_preferences(): " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }
}

void ExampleApplication::on_action_quit()
{
  // Gio::Application::quit() will make Gio::Application::run() return,
  // but it's a crude way of ending the program. The window is not removed
  // from the application. Neither the window's nor the application's
  // destructors will be called, because there will be remaining reference
  // counts in both of them. If we want the destructors to be called, we
  // must remove the window from the application. One way of doing this
  // is to hide the window. See comment in create_appwindow().
  auto windows = get_windows();
  for (auto window : windows)
    window-&gt;set_visible(false);

  // Not really necessary, when Gtk::Widget::set_visible(false) is called,
  // unless Gio::Application::hold() has been called without a corresponding
  // call to Gio::Application::release().
  quit();
}
</code></pre>
<p>File: <code class="filename">exampleappprefs.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "exampleappprefs.h"
#include "exampleappwindow.h"
#include &lt;array&gt;
#include &lt;stdexcept&gt;

namespace
{
struct TransitionTypeStruct
{
  Glib::ustring id;   // Value of "transition" key in Gio::Settings
  Glib::ustring text; // Text in the DropDown list
};

const std::array&lt;TransitionTypeStruct, 3&gt; transitionTypes =
{
  TransitionTypeStruct{"none",             "None"},
  TransitionTypeStruct{"crossfade",        "Fade"},
  TransitionTypeStruct{"slide-left-right", "Slide"}
};

} // anonymous namespace

ExampleAppPrefs::ExampleAppPrefs(BaseObjectType* cobject,
  const Glib::RefPtr&lt;Gtk::Builder&gt;&amp; refBuilder)
: Gtk::Window(cobject),
  m_refBuilder(refBuilder)
{
  m_font = m_refBuilder-&gt;get_widget&lt;Gtk::FontDialogButton&gt;("font");
  if (!m_font)
    throw std::runtime_error("No \"font\" object in prefs.ui");

  m_transition = m_refBuilder-&gt;get_widget&lt;Gtk::DropDown&gt;("transition");
  if (!m_transition)
    throw std::runtime_error("No \"transition\" object in prefs.ui");

  // DropDown for transition type.
  auto string_list = Gtk::StringList::create();
  for (const auto&amp; transitionType : transitionTypes)
    string_list-&gt;append(transitionType.text);

  m_transition-&gt;set_model(string_list);

  m_settings = Gio::Settings::create("org.gtkmm.exampleapp");

  // Connect preference properties to the Gio::Settings.
#if HAS_GIO_SETTINGS_BIND_WITH_MAPPING
  m_settings-&gt;bind&lt;Glib::ustring, Pango::FontDescription&gt;("font",
    m_font-&gt;property_font_desc(), Gio::Settings::BindFlags::DEFAULT,
    [](const auto&amp; font) { return Pango::FontDescription(font); },
    [](const auto&amp; fontdesc) { return fontdesc.to_string(); }
  );
  m_settings-&gt;bind&lt;Glib::ustring, unsigned int&gt;("transition",
    m_transition-&gt;property_selected(), Gio::Settings::BindFlags::DEFAULT,
    [](const auto&amp; transition) { return map_from_ustring_to_int(transition); },
    [](const auto&amp; pos) { return map_from_int_to_ustring(pos); }
  );
#else
  // This is easier when g_settings_bind_with_mapping() is
  // wrapped in a Gio::Settings method.
  m_settings-&gt;signal_changed("font").connect(
    sigc::mem_fun(*this, &amp;ExampleAppPrefs::on_font_setting_changed));
  m_font-&gt;property_font_desc().signal_changed().connect(
    sigc::mem_fun(*this, &amp;ExampleAppPrefs::on_font_selection_changed));

  m_settings-&gt;signal_changed("transition").connect(
    sigc::mem_fun(*this, &amp;ExampleAppPrefs::on_transition_setting_changed));
  m_transition-&gt;property_selected().signal_changed().connect(
    sigc::mem_fun(*this, &amp;ExampleAppPrefs::on_transition_selection_changed));

  // Synchronize the preferences dialog with m_settings.
  on_font_setting_changed("font");
  on_transition_setting_changed("transition");
#endif
}

//static
ExampleAppPrefs* ExampleAppPrefs::create(Gtk::Window&amp; parent)
{
  // Load the Builder file and instantiate its widgets.
  auto refBuilder = Gtk::Builder::create_from_resource("/org/gtkmm/exampleapp/prefs.ui");

  auto dialog = Gtk::Builder::get_widget_derived&lt;ExampleAppPrefs&gt;(refBuilder, "prefs_dialog");
  if (!dialog)
    throw std::runtime_error("No \"prefs_dialog\" object in prefs.ui");

  dialog-&gt;set_transient_for(parent);

  return dialog;
}

#if HAS_GIO_SETTINGS_BIND_WITH_MAPPING
std::optional&lt;unsigned int&gt; ExampleAppPrefs::map_from_ustring_to_int(const Glib::ustring&amp; transition)
{
  for (std::size_t i = 0; i &lt; transitionTypes.size(); ++i)
  {
    if (transitionTypes[i].id == transition)
      return i;
  }
  return std::nullopt;
}

std::optional&lt;Glib::ustring&gt; ExampleAppPrefs::map_from_int_to_ustring(const unsigned int&amp; pos)
{
  if (pos &gt;= transitionTypes.size())
    return std::nullopt;
  return transitionTypes[pos].id;
}
#else
void ExampleAppPrefs::on_font_setting_changed(const Glib::ustring&amp; /* key */)
{
  const auto font_setting = m_settings-&gt;get_string("font");
  const auto font_button = m_font-&gt;get_font_desc().to_string();
  if (font_setting != font_button)
    m_font-&gt;set_font_desc(Pango::FontDescription(font_setting));
}

void ExampleAppPrefs::on_font_selection_changed()
{
  const auto font_setting = m_settings-&gt;get_string("font");
  const auto font_button = m_font-&gt;get_font_desc().to_string();
  if (font_setting != font_button)
    m_settings-&gt;set_string("font", font_button);
}

void ExampleAppPrefs::on_transition_setting_changed(const Glib::ustring&amp; /* key */)
{
  const auto transition_setting = m_settings-&gt;get_string("transition");
  const auto transition_button = transitionTypes[m_transition-&gt;get_selected()].id;
  if (transition_setting != transition_button)
  {
    for (std::size_t i = 0; i &lt; transitionTypes.size(); ++i)
    {
      if (transitionTypes[i].id == transition_setting)
      {
        m_transition-&gt;set_selected(i);
        break;
      }
    }
  }
}

void ExampleAppPrefs::on_transition_selection_changed()
{
  const auto pos = m_transition-&gt;get_selected();
  if (pos &gt;= transitionTypes.size())
    return;
  const auto transition_setting = m_settings-&gt;get_string("transition");
  const auto transition_button = transitionTypes[pos].id;
  if (transition_setting != transition_button)
    m_settings-&gt;set_string("transition", transition_button);
}
#endif
</code></pre>
<p>File: <code class="filename">exampleappwindow.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "exampleappwindow.h"
#include &lt;iostream&gt;
#include &lt;stdexcept&gt;

ExampleAppWindow::ExampleAppWindow(BaseObjectType* cobject,
  const Glib::RefPtr&lt;Gtk::Builder&gt;&amp; refBuilder)
: Gtk::ApplicationWindow(cobject),
  m_refBuilder(refBuilder)
{
  // Get widgets from the Gtk::Builder file.
  m_stack = m_refBuilder-&gt;get_widget&lt;Gtk::Stack&gt;("stack");
  if (!m_stack)
    throw std::runtime_error("No \"stack\" object in window.ui");

  m_gears = m_refBuilder-&gt;get_widget&lt;Gtk::MenuButton&gt;("gears");
  if (!m_gears)
    throw std::runtime_error("No \"gears\" object in window.ui");

  // Bind settings.
  m_settings = Gio::Settings::create("org.gtkmm.exampleapp");
  m_settings-&gt;bind("transition", m_stack-&gt;property_transition_type());

  // Connect the menu to the MenuButton m_gears.
  // (The connection between action and menu item is specified in gears_menu.ui.)
  auto menu_builder = Gtk::Builder::create_from_resource("/org/gtkmm/exampleapp/gears_menu.ui");
  auto menu = menu_builder-&gt;get_object&lt;Gio::MenuModel&gt;("menu");
  if (!menu)
    throw std::runtime_error("No \"menu\" object in gears_menu.ui");

  m_gears-&gt;set_menu_model(menu);
}

//static
ExampleAppWindow* ExampleAppWindow::create()
{
  // Load the Builder file and instantiate its widgets.
  auto refBuilder = Gtk::Builder::create_from_resource("/org/gtkmm/exampleapp/window.ui");

  auto window = Gtk::Builder::get_widget_derived&lt;ExampleAppWindow&gt;(refBuilder, "app_window");
  if (!window)
    throw std::runtime_error("No \"app_window\" object in window.ui");

  return window;
}

void ExampleAppWindow::open_file_view(const Glib::RefPtr&lt;Gio::File&gt;&amp; file)
{
  const Glib::ustring basename = file-&gt;get_basename();

  auto scrolled = Gtk::make_managed&lt;Gtk::ScrolledWindow&gt;();
  scrolled-&gt;set_expand(true);
  auto view = Gtk::make_managed&lt;Gtk::TextView&gt;();
  view-&gt;set_editable(false);
  view-&gt;set_cursor_visible(false);
  scrolled-&gt;set_child(*view);
  m_stack-&gt;add(*scrolled, basename, basename);

  auto buffer = view-&gt;get_buffer();
  try
  {
    char* contents = nullptr;
    gsize length = 0;
    
    file-&gt;load_contents(contents, length);
    buffer-&gt;set_text(contents, contents+length);
    g_free(contents);
  }
  catch (const Glib::Error&amp; ex)
  {
    std::cout &lt;&lt; "ExampleAppWindow::open_file_view(\"" &lt;&lt; file-&gt;get_parse_name()
      &lt;&lt; "\"):\n  " &lt;&lt; ex.what() &lt;&lt; std::endl;
  }

  auto tag = buffer-&gt;create_tag();
  m_settings-&gt;bind("font", tag-&gt;property_font());
  buffer-&gt;apply_tag(tag, buffer-&gt;begin(), buffer-&gt;end());
}
</code></pre>
<p>File: <code class="filename">main.cc</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">#include "exampleapplication.h"

int main(int argc, char* argv[])
{
  // Since this example is running uninstalled, we have to help it find its
  // schema. This is *not* necessary in a properly installed application.
  Glib::setenv ("GSETTINGS_SCHEMA_DIR", ".", false);

  auto application = ExampleApplication::create();

  // Start the application, showing the initial window,
  // and opening extra views for any files that it is asked to open,
  // for instance as a command-line parameter.
  // run() will return when the last window has been closed.
  return application-&gt;run(argc, argv);
}
</code></pre>
<p>File: <code class="filename">exampleapp.gresource.xml</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;gresources&gt;
  &lt;gresource prefix="/org/gtkmm/exampleapp"&gt;
    &lt;file preprocess="xml-stripblanks"&gt;window.ui&lt;/file&gt;
    &lt;file preprocess="xml-stripblanks"&gt;gears_menu.ui&lt;/file&gt;
    &lt;file preprocess="xml-stripblanks"&gt;prefs.ui&lt;/file&gt;
  &lt;/gresource&gt;
&lt;/gresources&gt;
</code></pre>
<p>File: <code class="filename">prefs.ui</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;interface&gt;
  &lt;object class="GtkWindow" id="prefs_dialog"&gt;
    &lt;property name="title" translatable="yes"&gt;Preferences&lt;/property&gt;
    &lt;property name="resizable"&gt;False&lt;/property&gt;
    &lt;property name="modal"&gt;True&lt;/property&gt;
    &lt;property name="hide_on_close"&gt;True&lt;/property&gt;
    &lt;child&gt;
      &lt;object class="GtkGrid" id="grid"&gt;
        &lt;property name="margin-start"&gt;12&lt;/property&gt;
        &lt;property name="margin-end"&gt;12&lt;/property&gt;
        &lt;property name="margin-top"&gt;12&lt;/property&gt;
        &lt;property name="margin-bottom"&gt;12&lt;/property&gt;
        &lt;property name="row-spacing"&gt;12&lt;/property&gt;
        &lt;property name="column-spacing"&gt;12&lt;/property&gt;
        &lt;child&gt;
          &lt;object class="GtkLabel" id="fontlabel"&gt;
            &lt;property name="label"&gt;_Font:&lt;/property&gt;
            &lt;property name="use-underline"&gt;True&lt;/property&gt;
            &lt;property name="mnemonic-widget"&gt;font&lt;/property&gt;
            &lt;property name="xalign"&gt;1&lt;/property&gt;
            &lt;layout&gt;
              &lt;property name="column"&gt;0&lt;/property&gt;
              &lt;property name="row"&gt;0&lt;/property&gt;
            &lt;/layout&gt;
          &lt;/object&gt;
        &lt;/child&gt;
        &lt;child&gt;
          &lt;object class="GtkFontDialogButton" id="font"&gt;
            &lt;property name="dialog"&gt;
              &lt;object class="GtkFontDialog"/&gt;
            &lt;/property&gt;
            &lt;layout&gt;
              &lt;property name="column"&gt;1&lt;/property&gt;
              &lt;property name="row"&gt;0&lt;/property&gt;
            &lt;/layout&gt;
          &lt;/object&gt;
        &lt;/child&gt;
        &lt;child&gt;
          &lt;object class="GtkLabel" id="transitionlabel"&gt;
            &lt;property name="label"&gt;_Transition:&lt;/property&gt;
            &lt;property name="use-underline"&gt;True&lt;/property&gt;
            &lt;property name="mnemonic-widget"&gt;transition&lt;/property&gt;
            &lt;property name="xalign"&gt;1&lt;/property&gt;
            &lt;layout&gt;
              &lt;property name="column"&gt;0&lt;/property&gt;
              &lt;property name="row"&gt;1&lt;/property&gt;
            &lt;/layout&gt;
          &lt;/object&gt;
        &lt;/child&gt;
        &lt;child&gt;
          &lt;object class="GtkDropDown" id="transition"&gt;
            &lt;layout&gt;
              &lt;property name="column"&gt;1&lt;/property&gt;
              &lt;property name="row"&gt;1&lt;/property&gt;
            &lt;/layout&gt;
          &lt;/object&gt;
        &lt;/child&gt;
      &lt;/object&gt;
    &lt;/child&gt;
  &lt;/object&gt;
&lt;/interface&gt;
</code></pre>
<p>File: <code class="filename">org.gtkmm.exampleapp.gschema.xml</code> (For use with gtkmm 4)</p>
<pre class="programlisting"><code class="code">&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;schemalist&gt;
  &lt;schema path="/org/gtkmm/exampleapp/" id="org.gtkmm.exampleapp"&gt;
    &lt;key name="font" type="s"&gt;
      &lt;default&gt;'Monospace 12'&lt;/default&gt;
      &lt;summary&gt;Font&lt;/summary&gt;
      &lt;description&gt;The font to be used for content.&lt;/description&gt;
    &lt;/key&gt;
    &lt;key name="transition" type="s"&gt;
      &lt;choices&gt;
        &lt;choice value='none'/&gt;
        &lt;choice value='crossfade'/&gt;
        &lt;choice value='slide-left-right'/&gt;
      &lt;/choices&gt;
      &lt;default&gt;'none'&lt;/default&gt;
      &lt;summary&gt;Transition&lt;/summary&gt;
      &lt;description&gt;The transition to use when switching tabs.&lt;/description&gt;
    &lt;/key&gt;
  &lt;/schema&gt;
&lt;/schemalist&gt;
</code></pre>


</div>
<div class="navfooter">
<hr>
<table width="100%" summary="Navigation footer">
<tr>
<td width="40%" align="left">
<a accesskey="p" href="sec-buildapp-menu.html"><img src="icons/prev.png" alt="Prev"></a> </td>
<td width="20%" align="center"><a accesskey="u" href="chapter-building-applications.html"><img src="icons/up.png" alt="Up"></a></td>
<td width="40%" align="right"> <a accesskey="n" href="sec-buildapp-search-bar.html"><img src="icons/next.png" alt="Next"></a>
</td>
</tr>
<tr>
<td width="40%" align="left" valign="top">A menu </td>
<td width="20%" align="center"><a accesskey="h" href="index.html"><img src="icons/home.png" alt="Home"></a></td>
<td width="40%" align="right" valign="top"> Adding a search bar</td>
</tr>
</table>
</div>
</body>
</html>