mirror of
https://github.com/ToshioCP/Gtk4-tutorial.git
synced 2024-11-16 19:50:35 +01:00
7b14d03a24
Update the distribution package information.
592 lines
55 KiB
HTML
592 lines
55 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="utf-8" />
|
||
<meta name="generator" content="pandoc" />
|
||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-9ndCyUaIbzAi2FUVXJi0CjmCapSmO7SnpJef0486qhLnuZ2cdeRhO02iuK6FUUVM" crossorigin="anonymous">
|
||
<title>GTK 4 tutorial</title>
|
||
<style>
|
||
code{white-space: pre-wrap;}
|
||
span.smallcaps{font-variant: small-caps;}
|
||
span.underline{text-decoration: underline;}
|
||
div.column{display: inline-block; vertical-align: top; width: 50%;}
|
||
div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
|
||
ul.task-list{list-style: none;}
|
||
pre{overflow: visible;}
|
||
pre > code.sourceCode { white-space: pre; position: relative; }
|
||
pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
|
||
pre > code.sourceCode > span:empty { height: 1.2em; }
|
||
code.sourceCode > span { color: inherit; text-decoration: inherit; }
|
||
div.sourceCode { margin: 1em 0; }
|
||
pre.sourceCode { margin: 0; }
|
||
@media screen {
|
||
div.sourceCode { overflow: auto; }
|
||
}
|
||
@media print {
|
||
pre > code.sourceCode { white-space: pre-wrap; }
|
||
pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
|
||
}
|
||
pre.numberSource code
|
||
{ counter-reset: source-line 0; }
|
||
pre.numberSource code > span
|
||
{ position: relative; left: -4em; counter-increment: source-line; }
|
||
pre.numberSource code > span > a:first-child::after
|
||
{ content: counter(source-line);
|
||
position: relative; left: -1em; text-align: right; vertical-align: baseline;
|
||
border: none; display: inline-block;
|
||
-webkit-touch-callout: none; -webkit-user-select: none;
|
||
-khtml-user-select: none; -moz-user-select: none;
|
||
-ms-user-select: none; user-select: none;
|
||
padding: 0 4px; width: 4em;
|
||
color: #aaaaaa;
|
||
}
|
||
pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
|
||
div.sourceCode
|
||
{ }
|
||
@media screen {
|
||
pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
|
||
}
|
||
code span.al { color: #ff0000; font-weight: bold; } /* Alert */
|
||
code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
|
||
code span.at { color: #7d9029; } /* Attribute */
|
||
code span.bn { color: #40a070; } /* BaseN */
|
||
code span.bu { } /* BuiltIn */
|
||
code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
|
||
code span.ch { color: #4070a0; } /* Char */
|
||
code span.cn { color: #880000; } /* Constant */
|
||
code span.co { color: #60a0b0; font-style: italic; } /* Comment */
|
||
code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
|
||
code span.do { color: #ba2121; font-style: italic; } /* Documentation */
|
||
code span.dt { color: #902000; } /* DataType */
|
||
code span.dv { color: #40a070; } /* DecVal */
|
||
code span.er { color: #ff0000; font-weight: bold; } /* Error */
|
||
code span.ex { } /* Extension */
|
||
code span.fl { color: #40a070; } /* Float */
|
||
code span.fu { color: #06287e; } /* Function */
|
||
code span.im { } /* Import */
|
||
code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
|
||
code span.kw { color: #007020; font-weight: bold; } /* Keyword */
|
||
code span.op { color: #666666; } /* Operator */
|
||
code span.ot { color: #007020; } /* Other */
|
||
code span.pp { color: #bc7a00; } /* Preprocessor */
|
||
code span.sc { color: #4070a0; } /* SpecialChar */
|
||
code span.ss { color: #bb6688; } /* SpecialString */
|
||
code span.st { color: #4070a0; } /* String */
|
||
code span.va { color: #19177c; } /* Variable */
|
||
code span.vs { color: #4070a0; } /* VerbatimString */
|
||
code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
|
||
div.sourceCode { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
|
||
pre:not(.sourceCode) { margin: 10px; padding: 16px 10px 8px 10px; border: 2px solid silver; background-color: ghostwhite; overflow-x:scroll}
|
||
table {margin-left: auto; margin-right: auto; border-collapse: collapse; border: 1px solid;}
|
||
th {padding: 2px 6px; border: 1px solid; background-color: ghostwhite;}
|
||
td {padding: 2px 6px; border: 1px solid;}
|
||
img {display: block; margin-left: auto; margin-right: auto;}
|
||
figcaption {text-align: center;}
|
||
</style>
|
||
</head>
|
||
<body style="padding-top: 70px;">
|
||
<div class="container">
|
||
<nav class="navbar fixed-top navbar-expand-lg navbar-dark bg-primary">
|
||
<div class="container-fluid">
|
||
<span class="navbar-brand">Gtk4 tutorial</span>
|
||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
|
||
<span class="navbar-toggler-icon"></span>
|
||
</button>
|
||
<div class="collapse navbar-collapse" id="navbarSupportedContent">
|
||
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="index.html">Home</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec8.html">Prev: section8</a>
|
||
</li>
|
||
|
||
<li class="nav-item">
|
||
<a class="nav-link" href="sec10.html">Next: section10</a>
|
||
</li>
|
||
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</nav>
|
||
<div class="row justify-content-center">
|
||
<div class="col-xl-10 col-xxl-9">
|
||
<h1 id="gtkbuilder-and-ui-file">GtkBuilder and UI file</h1>
|
||
<h2 id="new-open-and-save-button">New, Open and Save button</h2>
|
||
<p>We made very simple editor in the previous section. It reads files at
|
||
the start and writes them out at the end of the program. It works, but
|
||
is not so good. It would be better if we had “New”, “Open”, “Save” and
|
||
“Close” buttons. This section describes how to put those buttons into
|
||
the window.</p>
|
||
<figure>
|
||
<img src="image/screenshot_tfe2.png"
|
||
alt="Screenshot of the file editor" />
|
||
<figcaption aria-hidden="true">Screenshot of the file
|
||
editor</figcaption>
|
||
</figure>
|
||
<p>The screenshot above shows the layout. The function
|
||
<code>app_open</code> in the source code <code>tfe2.c</code> is as
|
||
follows.</p>
|
||
<div class="sourceCode" id="cb1"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb1-2"><a href="#cb1-2"></a>app_open <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> GFile <span class="op">**</span> files<span class="op">,</span> gint n_files<span class="op">,</span> gchar <span class="op">*</span>hint<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb1-3"><a href="#cb1-3"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||
<span id="cb1-4"><a href="#cb1-4"></a> GtkWidget <span class="op">*</span>nb<span class="op">;</span></span>
|
||
<span id="cb1-5"><a href="#cb1-5"></a> GtkWidget <span class="op">*</span>lab<span class="op">;</span></span>
|
||
<span id="cb1-6"><a href="#cb1-6"></a> GtkNotebookPage <span class="op">*</span>nbp<span class="op">;</span></span>
|
||
<span id="cb1-7"><a href="#cb1-7"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span>
|
||
<span id="cb1-8"><a href="#cb1-8"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
|
||
<span id="cb1-9"><a href="#cb1-9"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span>
|
||
<span id="cb1-10"><a href="#cb1-10"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||
<span id="cb1-11"><a href="#cb1-11"></a> gsize length<span class="op">;</span></span>
|
||
<span id="cb1-12"><a href="#cb1-12"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span>
|
||
<span id="cb1-13"><a href="#cb1-13"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb1-14"><a href="#cb1-14"></a> GError <span class="op">*</span>err <span class="op">=</span> NULL<span class="op">;</span></span>
|
||
<span id="cb1-15"><a href="#cb1-15"></a></span>
|
||
<span id="cb1-16"><a href="#cb1-16"></a> GtkWidget <span class="op">*</span>boxv<span class="op">;</span></span>
|
||
<span id="cb1-17"><a href="#cb1-17"></a> GtkWidget <span class="op">*</span>boxh<span class="op">;</span></span>
|
||
<span id="cb1-18"><a href="#cb1-18"></a> GtkWidget <span class="op">*</span>dmy1<span class="op">;</span></span>
|
||
<span id="cb1-19"><a href="#cb1-19"></a> GtkWidget <span class="op">*</span>dmy2<span class="op">;</span></span>
|
||
<span id="cb1-20"><a href="#cb1-20"></a> GtkWidget <span class="op">*</span>dmy3<span class="op">;</span></span>
|
||
<span id="cb1-21"><a href="#cb1-21"></a> GtkWidget <span class="op">*</span>btnn<span class="op">;</span> <span class="co">/* button for new */</span></span>
|
||
<span id="cb1-22"><a href="#cb1-22"></a> GtkWidget <span class="op">*</span>btno<span class="op">;</span> <span class="co">/* button for open */</span></span>
|
||
<span id="cb1-23"><a href="#cb1-23"></a> GtkWidget <span class="op">*</span>btns<span class="op">;</span> <span class="co">/* button for save */</span></span>
|
||
<span id="cb1-24"><a href="#cb1-24"></a> GtkWidget <span class="op">*</span>btnc<span class="op">;</span> <span class="co">/* button for close */</span></span>
|
||
<span id="cb1-25"><a href="#cb1-25"></a></span>
|
||
<span id="cb1-26"><a href="#cb1-26"></a> win <span class="op">=</span> gtk_application_window_new <span class="op">(</span>GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
|
||
<span id="cb1-27"><a href="#cb1-27"></a> gtk_window_set_title <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="st">"file editor"</span><span class="op">);</span></span>
|
||
<span id="cb1-28"><a href="#cb1-28"></a> gtk_window_set_default_size <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> <span class="dv">600</span><span class="op">,</span> <span class="dv">400</span><span class="op">);</span></span>
|
||
<span id="cb1-29"><a href="#cb1-29"></a></span>
|
||
<span id="cb1-30"><a href="#cb1-30"></a> boxv <span class="op">=</span> gtk_box_new <span class="op">(</span>GTK_ORIENTATION_VERTICAL<span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||
<span id="cb1-31"><a href="#cb1-31"></a> gtk_window_set_child <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> boxv<span class="op">);</span></span>
|
||
<span id="cb1-32"><a href="#cb1-32"></a></span>
|
||
<span id="cb1-33"><a href="#cb1-33"></a> boxh <span class="op">=</span> gtk_box_new <span class="op">(</span>GTK_ORIENTATION_HORIZONTAL<span class="op">,</span> <span class="dv">0</span><span class="op">);</span></span>
|
||
<span id="cb1-34"><a href="#cb1-34"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxv<span class="op">),</span> boxh<span class="op">);</span></span>
|
||
<span id="cb1-35"><a href="#cb1-35"></a></span>
|
||
<span id="cb1-36"><a href="#cb1-36"></a> dmy1 <span class="op">=</span> gtk_label_new<span class="op">(</span>NULL<span class="op">);</span> <span class="co">/* dummy label for left space */</span></span>
|
||
<span id="cb1-37"><a href="#cb1-37"></a> gtk_label_set_width_chars <span class="op">(</span>GTK_LABEL <span class="op">(</span>dmy1<span class="op">),</span> <span class="dv">10</span><span class="op">);</span></span>
|
||
<span id="cb1-38"><a href="#cb1-38"></a> dmy2 <span class="op">=</span> gtk_label_new<span class="op">(</span>NULL<span class="op">);</span> <span class="co">/* dummy label for center space */</span></span>
|
||
<span id="cb1-39"><a href="#cb1-39"></a> gtk_widget_set_hexpand <span class="op">(</span>dmy2<span class="op">,</span> TRUE<span class="op">);</span></span>
|
||
<span id="cb1-40"><a href="#cb1-40"></a> dmy3 <span class="op">=</span> gtk_label_new<span class="op">(</span>NULL<span class="op">);</span> <span class="co">/* dummy label for right space */</span></span>
|
||
<span id="cb1-41"><a href="#cb1-41"></a> gtk_label_set_width_chars <span class="op">(</span>GTK_LABEL <span class="op">(</span>dmy3<span class="op">),</span> <span class="dv">10</span><span class="op">);</span></span>
|
||
<span id="cb1-42"><a href="#cb1-42"></a> btnn <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">"New"</span><span class="op">);</span></span>
|
||
<span id="cb1-43"><a href="#cb1-43"></a> btno <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">"Open"</span><span class="op">);</span></span>
|
||
<span id="cb1-44"><a href="#cb1-44"></a> btns <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">"Save"</span><span class="op">);</span></span>
|
||
<span id="cb1-45"><a href="#cb1-45"></a> btnc <span class="op">=</span> gtk_button_new_with_label <span class="op">(</span><span class="st">"Close"</span><span class="op">);</span></span>
|
||
<span id="cb1-46"><a href="#cb1-46"></a></span>
|
||
<span id="cb1-47"><a href="#cb1-47"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> dmy1<span class="op">);</span></span>
|
||
<span id="cb1-48"><a href="#cb1-48"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> btnn<span class="op">);</span></span>
|
||
<span id="cb1-49"><a href="#cb1-49"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> btno<span class="op">);</span></span>
|
||
<span id="cb1-50"><a href="#cb1-50"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> dmy2<span class="op">);</span></span>
|
||
<span id="cb1-51"><a href="#cb1-51"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> btns<span class="op">);</span></span>
|
||
<span id="cb1-52"><a href="#cb1-52"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> btnc<span class="op">);</span></span>
|
||
<span id="cb1-53"><a href="#cb1-53"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxh<span class="op">),</span> dmy3<span class="op">);</span></span>
|
||
<span id="cb1-54"><a href="#cb1-54"></a></span>
|
||
<span id="cb1-55"><a href="#cb1-55"></a> nb <span class="op">=</span> gtk_notebook_new <span class="op">();</span></span>
|
||
<span id="cb1-56"><a href="#cb1-56"></a> gtk_widget_set_hexpand <span class="op">(</span>nb<span class="op">,</span> TRUE<span class="op">);</span></span>
|
||
<span id="cb1-57"><a href="#cb1-57"></a> gtk_widget_set_vexpand <span class="op">(</span>nb<span class="op">,</span> TRUE<span class="op">);</span></span>
|
||
<span id="cb1-58"><a href="#cb1-58"></a> gtk_box_append <span class="op">(</span>GTK_BOX <span class="op">(</span>boxv<span class="op">),</span> nb<span class="op">);</span></span>
|
||
<span id="cb1-59"><a href="#cb1-59"></a></span>
|
||
<span id="cb1-60"><a href="#cb1-60"></a> <span class="cf">for</span> <span class="op">(</span>i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> n_files<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
||
<span id="cb1-61"><a href="#cb1-61"></a> <span class="cf">if</span> <span class="op">(</span>g_file_load_contents <span class="op">(</span>files<span class="op">[</span>i<span class="op">],</span> NULL<span class="op">,</span> <span class="op">&</span>contents<span class="op">,</span> <span class="op">&</span>length<span class="op">,</span> NULL<span class="op">,</span> <span class="op">&</span>err<span class="op">))</span> <span class="op">{</span></span>
|
||
<span id="cb1-62"><a href="#cb1-62"></a> scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
|
||
<span id="cb1-63"><a href="#cb1-63"></a> tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span>
|
||
<span id="cb1-64"><a href="#cb1-64"></a> tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||
<span id="cb1-65"><a href="#cb1-65"></a> gtk_text_view_set_wrap_mode <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WRAP_WORD_CHAR<span class="op">);</span></span>
|
||
<span id="cb1-66"><a href="#cb1-66"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> tv<span class="op">);</span></span>
|
||
<span id="cb1-67"><a href="#cb1-67"></a></span>
|
||
<span id="cb1-68"><a href="#cb1-68"></a> tfe_text_view_set_file <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> g_file_dup <span class="op">(</span>files<span class="op">[</span>i<span class="op">]));</span></span>
|
||
<span id="cb1-69"><a href="#cb1-69"></a> gtk_text_buffer_set_text <span class="op">(</span>tb<span class="op">,</span> contents<span class="op">,</span> length<span class="op">);</span></span>
|
||
<span id="cb1-70"><a href="#cb1-70"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||
<span id="cb1-71"><a href="#cb1-71"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>files<span class="op">[</span>i<span class="op">]);</span></span>
|
||
<span id="cb1-72"><a href="#cb1-72"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span>
|
||
<span id="cb1-73"><a href="#cb1-73"></a> gtk_notebook_append_page <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> lab<span class="op">);</span></span>
|
||
<span id="cb1-74"><a href="#cb1-74"></a> nbp <span class="op">=</span> gtk_notebook_get_page <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">);</span></span>
|
||
<span id="cb1-75"><a href="#cb1-75"></a> g_object_set <span class="op">(</span>nbp<span class="op">,</span> <span class="st">"tab-expand"</span><span class="op">,</span> TRUE<span class="op">,</span> NULL<span class="op">);</span></span>
|
||
<span id="cb1-76"><a href="#cb1-76"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span>
|
||
<span id="cb1-77"><a href="#cb1-77"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb1-78"><a href="#cb1-78"></a> g_printerr <span class="op">(</span><span class="st">"%s.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> err<span class="op">-></span>message<span class="op">);</span></span>
|
||
<span id="cb1-79"><a href="#cb1-79"></a> g_clear_error <span class="op">(&</span>err<span class="op">);</span></span>
|
||
<span id="cb1-80"><a href="#cb1-80"></a> <span class="op">}</span></span>
|
||
<span id="cb1-81"><a href="#cb1-81"></a> <span class="op">}</span></span>
|
||
<span id="cb1-82"><a href="#cb1-82"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb1-83"><a href="#cb1-83"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb1-84"><a href="#cb1-84"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb1-85"><a href="#cb1-85"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb1-86"><a href="#cb1-86"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The function <code>app_open</code> builds the widgets in the main
|
||
application window.</p>
|
||
<ul>
|
||
<li>26-28: Creates a GtkApplicationWindow instance and sets the title
|
||
and default size.</li>
|
||
<li>30-31: Creates a GtkBox instance <code>boxv</code>. It is a vertical
|
||
box and a child of GtkApplicationWindow. It has two children. The first
|
||
child is a horizontal box. The second child is a GtkNotebook.</li>
|
||
<li>33-34: Creates a GtkBox instance <code>boxh</code> and appends it to
|
||
<code>boxv</code> as the first child.</li>
|
||
<li>36-41: Creates three dummy labels. The labels <code>dmy1</code> and
|
||
<code>dmy3</code> has a character width of ten. The other label
|
||
<code>dmy2</code> has hexpand property which is set to be TRUE. This
|
||
makes the label expands horizontally as long as possible.</li>
|
||
<li>42-45: Creates four buttons.</li>
|
||
<li>47-53: Appends these GtkLabel and GtkButton to
|
||
<code>boxh</code>.</li>
|
||
<li>55-58: Creates a GtkNotebook instance and sets hexpand and vexpand
|
||
properties to be TRUE. This makes it expand horizontally and vertically
|
||
as big as possible. It is appended to <code>boxv</code> as the second
|
||
child.</li>
|
||
</ul>
|
||
<p>The number of widget-build lines is 33(=58-26+1). We also needed many
|
||
variables (<code>boxv</code>, <code>boxh</code>, <code>dmy1</code>, …)
|
||
and most of them used only for building the widgets. Are there any good
|
||
solution to reduce these works?</p>
|
||
<p>Gtk provides GtkBuilder. It reads user interface (UI) data and builds
|
||
a window. It reduces this cumbersome work.</p>
|
||
<h2 id="the-ui-file">The UI File</h2>
|
||
<p>Look at the UI file <code>tfe3.ui</code> that defines widget
|
||
structure.</p>
|
||
<div class="sourceCode" id="cb2"><pre
|
||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb2-1"><a href="#cb2-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span>
|
||
<span id="cb2-2"><a href="#cb2-2"></a><<span class="kw">interface</span>></span>
|
||
<span id="cb2-3"><a href="#cb2-3"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkApplicationWindow"</span><span class="ot"> id=</span><span class="st">"win"</span>></span>
|
||
<span id="cb2-4"><a href="#cb2-4"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"title"</span>>file editor</<span class="kw">property</span>></span>
|
||
<span id="cb2-5"><a href="#cb2-5"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-width"</span>>600</<span class="kw">property</span>></span>
|
||
<span id="cb2-6"><a href="#cb2-6"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"default-height"</span>>400</<span class="kw">property</span>></span>
|
||
<span id="cb2-7"><a href="#cb2-7"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-8"><a href="#cb2-8"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span>></span>
|
||
<span id="cb2-9"><a href="#cb2-9"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_VERTICAL</<span class="kw">property</span>></span>
|
||
<span id="cb2-10"><a href="#cb2-10"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-11"><a href="#cb2-11"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkBox"</span>></span>
|
||
<span id="cb2-12"><a href="#cb2-12"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"orientation"</span>>GTK_ORIENTATION_HORIZONTAL</<span class="kw">property</span>></span>
|
||
<span id="cb2-13"><a href="#cb2-13"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-14"><a href="#cb2-14"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||
<span id="cb2-15"><a href="#cb2-15"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"width-chars"</span>>10</<span class="kw">property</span>></span>
|
||
<span id="cb2-16"><a href="#cb2-16"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-17"><a href="#cb2-17"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-18"><a href="#cb2-18"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-19"><a href="#cb2-19"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span>
|
||
<span id="cb2-20"><a href="#cb2-20"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>New</<span class="kw">property</span>></span>
|
||
<span id="cb2-21"><a href="#cb2-21"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-22"><a href="#cb2-22"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-23"><a href="#cb2-23"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-24"><a href="#cb2-24"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span>
|
||
<span id="cb2-25"><a href="#cb2-25"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Open</<span class="kw">property</span>></span>
|
||
<span id="cb2-26"><a href="#cb2-26"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-27"><a href="#cb2-27"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-28"><a href="#cb2-28"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-29"><a href="#cb2-29"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||
<span id="cb2-30"><a href="#cb2-30"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||
<span id="cb2-31"><a href="#cb2-31"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-32"><a href="#cb2-32"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-33"><a href="#cb2-33"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-34"><a href="#cb2-34"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span>
|
||
<span id="cb2-35"><a href="#cb2-35"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Save</<span class="kw">property</span>></span>
|
||
<span id="cb2-36"><a href="#cb2-36"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-37"><a href="#cb2-37"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-38"><a href="#cb2-38"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-39"><a href="#cb2-39"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkButton"</span>></span>
|
||
<span id="cb2-40"><a href="#cb2-40"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"label"</span>>Close</<span class="kw">property</span>></span>
|
||
<span id="cb2-41"><a href="#cb2-41"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-42"><a href="#cb2-42"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-43"><a href="#cb2-43"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-44"><a href="#cb2-44"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkLabel"</span>></span>
|
||
<span id="cb2-45"><a href="#cb2-45"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"width-chars"</span>>10</<span class="kw">property</span>></span>
|
||
<span id="cb2-46"><a href="#cb2-46"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-47"><a href="#cb2-47"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-48"><a href="#cb2-48"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-49"><a href="#cb2-49"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-50"><a href="#cb2-50"></a> <<span class="kw">child</span>></span>
|
||
<span id="cb2-51"><a href="#cb2-51"></a> <<span class="kw">object</span><span class="ot"> class=</span><span class="st">"GtkNotebook"</span><span class="ot"> id=</span><span class="st">"nb"</span>></span>
|
||
<span id="cb2-52"><a href="#cb2-52"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"hexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||
<span id="cb2-53"><a href="#cb2-53"></a> <<span class="kw">property</span><span class="ot"> name=</span><span class="st">"vexpand"</span>>TRUE</<span class="kw">property</span>></span>
|
||
<span id="cb2-54"><a href="#cb2-54"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-55"><a href="#cb2-55"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-56"><a href="#cb2-56"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-57"><a href="#cb2-57"></a> </<span class="kw">child</span>></span>
|
||
<span id="cb2-58"><a href="#cb2-58"></a> </<span class="kw">object</span>></span>
|
||
<span id="cb2-59"><a href="#cb2-59"></a></<span class="kw">interface</span>></span></code></pre></div>
|
||
<p>The is a XML file. Tags begin with <code><</code> and end with
|
||
<code>></code>. There are two types of tags, the start tag and the
|
||
end tag. For example, <code><interface></code> is a start tag and
|
||
<code></interface></code> is an end tag. The UI file begins and
|
||
ends with interface tags. Some tags, for example object tags, can have a
|
||
class and id attributes in their start tag.</p>
|
||
<ul>
|
||
<li>1: XML declaration. It specifies that the XML version is 1.0 and the
|
||
encoding is UTF-8.</li>
|
||
<li>3-6: An object tag with <code>GtkApplicationWindow</code> class and
|
||
<code>win</code> id. This is the top level window. And the three
|
||
properties of the window are defined. The <code>title</code> property is
|
||
“file editor”, <code>default-width</code> property is 600 and
|
||
<code>default-height</code> property is 400.</li>
|
||
<li>7: Child tag means a child widget. For example, line 7 tells us that
|
||
GtkBox object is a child widget of <code>win</code>.</li>
|
||
</ul>
|
||
<p>Compare this ui file and the lines 26-58 in the <code>app_open</code>
|
||
function of <code>tfe2.c</code>. Both builds the same window with its
|
||
descendant widgets.</p>
|
||
<p>You can check the ui file with <code>gtk4-builder-tool</code>.</p>
|
||
<ul>
|
||
<li><code>gtk4-builder-tool validate <ui file name></code>
|
||
validates the ui file. If the ui file includes some syntactical error,
|
||
<code>gtk4-builder-tool</code> prints the error.</li>
|
||
<li><code>gtk4-builder-tool simplify <ui file name></code>
|
||
simplifies the ui file and prints the result. If <code>--replace</code>
|
||
option is given, it replaces the ui file with the simplified one. If the
|
||
ui file specifies a value of property but it is default, then it will be
|
||
removed. For example, the default orientation is horizontal so the
|
||
simplification removes line 12. And some values are simplified. For
|
||
example, “TRUE”and “FALSE” becomes “1” and “0” respectively. However,
|
||
“TRUE” or “FALSE” is better for maintenance.</li>
|
||
</ul>
|
||
<p>It is a good idea to check your ui file before compiling.</p>
|
||
<h2 id="gtkbuilder">GtkBuilder</h2>
|
||
<p>GtkBuilder builds widgets based on a ui file.</p>
|
||
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||
<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>build <span class="op">=</span> gtk_builder_new_from_file <span class="op">(</span><span class="st">"tfe3.ui"</span><span class="op">);</span></span>
|
||
<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||
<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
|
||
<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>nb <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"nb"</span><span class="op">));</span></span>
|
||
<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>g_object_unref<span class="op">(</span>build<span class="op">);</span></span></code></pre></div>
|
||
<p>The function <code>gtk_builder_new_from_file</code> reads the file
|
||
<code>tfe3.ui</code>. Then, it builds the widgets and creates GtkBuilder
|
||
object. All the widgets are connected based on the parent-children
|
||
relationship described in the ui file. We can retrieve objects from the
|
||
builder object with <code>gtk_builder_get_object</code> function. The
|
||
top level window, its id is “win” in the ui file, is taken and assigned
|
||
to the variable <code>win</code>, the application property of which is
|
||
set to <code>app</code> with the <code>gtk_window_set_application</code>
|
||
function. GtkNotebook with the id “nb” in the ui file is also taken and
|
||
assigned to the variable <code>nb</code>. After the window and
|
||
application are connected, GtkBuilder instance is useless. It is
|
||
released with <code>g_object_unref</code> function.</p>
|
||
<p>The ui file reduces lines in the C source file.</p>
|
||
<pre><code>$ cd tfe; diff tfe2.c tfe3.c
|
||
59a60
|
||
> GtkBuilder *build;
|
||
61,104c62,66
|
||
< GtkWidget *boxv;
|
||
< GtkWidget *boxh;
|
||
< GtkWidget *dmy1;
|
||
< GtkWidget *dmy2;
|
||
< GtkWidget *dmy3;
|
||
< GtkWidget *btnn; /* button for new */
|
||
< GtkWidget *btno; /* button for open */
|
||
< GtkWidget *btns; /* button for save */
|
||
< GtkWidget *btnc; /* button for close */
|
||
<
|
||
< win = gtk_application_window_new (GTK_APPLICATION (app));
|
||
< gtk_window_set_title (GTK_WINDOW (win), "file editor");
|
||
< gtk_window_set_default_size (GTK_WINDOW (win), 600, 400);
|
||
<
|
||
< boxv = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
|
||
< gtk_window_set_child (GTK_WINDOW (win), boxv);
|
||
<
|
||
< boxh = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
|
||
< gtk_box_append (GTK_BOX (boxv), boxh);
|
||
<
|
||
< dmy1 = gtk_label_new(NULL); /* dummy label for left space */
|
||
< gtk_label_set_width_chars (GTK_LABEL (dmy1), 10);
|
||
< dmy2 = gtk_label_new(NULL); /* dummy label for center space */
|
||
< gtk_widget_set_hexpand (dmy2, TRUE);
|
||
< dmy3 = gtk_label_new(NULL); /* dummy label for right space */
|
||
< gtk_label_set_width_chars (GTK_LABEL (dmy3), 10);
|
||
< btnn = gtk_button_new_with_label ("New");
|
||
< btno = gtk_button_new_with_label ("Open");
|
||
< btns = gtk_button_new_with_label ("Save");
|
||
< btnc = gtk_button_new_with_label ("Close");
|
||
<
|
||
< gtk_box_append (GTK_BOX (boxh), dmy1);
|
||
< gtk_box_append (GTK_BOX (boxh), btnn);
|
||
< gtk_box_append (GTK_BOX (boxh), btno);
|
||
< gtk_box_append (GTK_BOX (boxh), dmy2);
|
||
< gtk_box_append (GTK_BOX (boxh), btns);
|
||
< gtk_box_append (GTK_BOX (boxh), btnc);
|
||
< gtk_box_append (GTK_BOX (boxh), dmy3);
|
||
<
|
||
< nb = gtk_notebook_new ();
|
||
< gtk_widget_set_hexpand (nb, TRUE);
|
||
< gtk_widget_set_vexpand (nb, TRUE);
|
||
< gtk_box_append (GTK_BOX (boxv), nb);
|
||
<
|
||
---
|
||
> build = gtk_builder_new_from_file ("tfe3.ui");
|
||
> win = GTK_WIDGET (gtk_builder_get_object (build, "win"));
|
||
> gtk_window_set_application (GTK_WINDOW (win), GTK_APPLICATION (app));
|
||
> nb = GTK_WIDGET (gtk_builder_get_object (build, "nb"));
|
||
> g_object_unref(build);
|
||
138c100
|
||
< app = gtk_application_new ("com.github.ToshioCP.tfe2", G_APPLICATION_HANDLES_OPEN);
|
||
---
|
||
> app = gtk_application_new ("com.github.ToshioCP.tfe3", G_APPLICATION_HANDLES_OPEN);
|
||
144a107
|
||
> </code></pre>
|
||
<p><code>61,104c62,66</code> means that 44 (=104-61+1) lines are changed
|
||
to 5 (=66-62+1) lines. Therefore, 39 lines are reduced. Using ui file
|
||
not only shortens C source files, but also makes the widgets structure
|
||
clear.</p>
|
||
<p>Now I’ll show you <code>app_open</code> function in the C file
|
||
<code>tfe3.c</code>.</p>
|
||
<div class="sourceCode" id="cb5"><pre
|
||
class="sourceCode numberSource C numberLines"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a><span class="dt">static</span> <span class="dt">void</span></span>
|
||
<span id="cb5-2"><a href="#cb5-2"></a>app_open <span class="op">(</span>GApplication <span class="op">*</span>app<span class="op">,</span> GFile <span class="op">**</span> files<span class="op">,</span> gint n_files<span class="op">,</span> gchar <span class="op">*</span>hint<span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb5-3"><a href="#cb5-3"></a> GtkWidget <span class="op">*</span>win<span class="op">;</span></span>
|
||
<span id="cb5-4"><a href="#cb5-4"></a> GtkWidget <span class="op">*</span>nb<span class="op">;</span></span>
|
||
<span id="cb5-5"><a href="#cb5-5"></a> GtkWidget <span class="op">*</span>lab<span class="op">;</span></span>
|
||
<span id="cb5-6"><a href="#cb5-6"></a> GtkNotebookPage <span class="op">*</span>nbp<span class="op">;</span></span>
|
||
<span id="cb5-7"><a href="#cb5-7"></a> GtkWidget <span class="op">*</span>scr<span class="op">;</span></span>
|
||
<span id="cb5-8"><a href="#cb5-8"></a> GtkWidget <span class="op">*</span>tv<span class="op">;</span></span>
|
||
<span id="cb5-9"><a href="#cb5-9"></a> GtkTextBuffer <span class="op">*</span>tb<span class="op">;</span></span>
|
||
<span id="cb5-10"><a href="#cb5-10"></a> <span class="dt">char</span> <span class="op">*</span>contents<span class="op">;</span></span>
|
||
<span id="cb5-11"><a href="#cb5-11"></a> gsize length<span class="op">;</span></span>
|
||
<span id="cb5-12"><a href="#cb5-12"></a> <span class="dt">char</span> <span class="op">*</span>filename<span class="op">;</span></span>
|
||
<span id="cb5-13"><a href="#cb5-13"></a> <span class="dt">int</span> i<span class="op">;</span></span>
|
||
<span id="cb5-14"><a href="#cb5-14"></a> GError <span class="op">*</span>err <span class="op">=</span> NULL<span class="op">;</span></span>
|
||
<span id="cb5-15"><a href="#cb5-15"></a> GtkBuilder <span class="op">*</span>build<span class="op">;</span></span>
|
||
<span id="cb5-16"><a href="#cb5-16"></a></span>
|
||
<span id="cb5-17"><a href="#cb5-17"></a> build <span class="op">=</span> gtk_builder_new_from_file <span class="op">(</span><span class="st">"tfe3.ui"</span><span class="op">);</span></span>
|
||
<span id="cb5-18"><a href="#cb5-18"></a> win <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"win"</span><span class="op">));</span></span>
|
||
<span id="cb5-19"><a href="#cb5-19"></a> gtk_window_set_application <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">),</span> GTK_APPLICATION <span class="op">(</span>app<span class="op">));</span></span>
|
||
<span id="cb5-20"><a href="#cb5-20"></a> nb <span class="op">=</span> GTK_WIDGET <span class="op">(</span>gtk_builder_get_object <span class="op">(</span>build<span class="op">,</span> <span class="st">"nb"</span><span class="op">));</span></span>
|
||
<span id="cb5-21"><a href="#cb5-21"></a> g_object_unref<span class="op">(</span>build<span class="op">);</span></span>
|
||
<span id="cb5-22"><a href="#cb5-22"></a> <span class="cf">for</span> <span class="op">(</span>i <span class="op">=</span> <span class="dv">0</span><span class="op">;</span> i <span class="op"><</span> n_files<span class="op">;</span> i<span class="op">++)</span> <span class="op">{</span></span>
|
||
<span id="cb5-23"><a href="#cb5-23"></a> <span class="cf">if</span> <span class="op">(</span>g_file_load_contents <span class="op">(</span>files<span class="op">[</span>i<span class="op">],</span> NULL<span class="op">,</span> <span class="op">&</span>contents<span class="op">,</span> <span class="op">&</span>length<span class="op">,</span> NULL<span class="op">,</span> <span class="op">&</span>err<span class="op">))</span> <span class="op">{</span></span>
|
||
<span id="cb5-24"><a href="#cb5-24"></a> scr <span class="op">=</span> gtk_scrolled_window_new <span class="op">();</span></span>
|
||
<span id="cb5-25"><a href="#cb5-25"></a> tv <span class="op">=</span> tfe_text_view_new <span class="op">();</span></span>
|
||
<span id="cb5-26"><a href="#cb5-26"></a> tb <span class="op">=</span> gtk_text_view_get_buffer <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">));</span></span>
|
||
<span id="cb5-27"><a href="#cb5-27"></a> gtk_text_view_set_wrap_mode <span class="op">(</span>GTK_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> GTK_WRAP_WORD_CHAR<span class="op">);</span></span>
|
||
<span id="cb5-28"><a href="#cb5-28"></a> gtk_scrolled_window_set_child <span class="op">(</span>GTK_SCROLLED_WINDOW <span class="op">(</span>scr<span class="op">),</span> tv<span class="op">);</span></span>
|
||
<span id="cb5-29"><a href="#cb5-29"></a></span>
|
||
<span id="cb5-30"><a href="#cb5-30"></a> tfe_text_view_set_file <span class="op">(</span>TFE_TEXT_VIEW <span class="op">(</span>tv<span class="op">),</span> g_file_dup <span class="op">(</span>files<span class="op">[</span>i<span class="op">]));</span></span>
|
||
<span id="cb5-31"><a href="#cb5-31"></a> gtk_text_buffer_set_text <span class="op">(</span>tb<span class="op">,</span> contents<span class="op">,</span> length<span class="op">);</span></span>
|
||
<span id="cb5-32"><a href="#cb5-32"></a> g_free <span class="op">(</span>contents<span class="op">);</span></span>
|
||
<span id="cb5-33"><a href="#cb5-33"></a> filename <span class="op">=</span> g_file_get_basename <span class="op">(</span>files<span class="op">[</span>i<span class="op">]);</span></span>
|
||
<span id="cb5-34"><a href="#cb5-34"></a> lab <span class="op">=</span> gtk_label_new <span class="op">(</span>filename<span class="op">);</span></span>
|
||
<span id="cb5-35"><a href="#cb5-35"></a> gtk_notebook_append_page <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">,</span> lab<span class="op">);</span></span>
|
||
<span id="cb5-36"><a href="#cb5-36"></a> nbp <span class="op">=</span> gtk_notebook_get_page <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">),</span> scr<span class="op">);</span></span>
|
||
<span id="cb5-37"><a href="#cb5-37"></a> g_object_set <span class="op">(</span>nbp<span class="op">,</span> <span class="st">"tab-expand"</span><span class="op">,</span> TRUE<span class="op">,</span> NULL<span class="op">);</span></span>
|
||
<span id="cb5-38"><a href="#cb5-38"></a> g_free <span class="op">(</span>filename<span class="op">);</span></span>
|
||
<span id="cb5-39"><a href="#cb5-39"></a> <span class="op">}</span> <span class="cf">else</span> <span class="op">{</span></span>
|
||
<span id="cb5-40"><a href="#cb5-40"></a> g_printerr <span class="op">(</span><span class="st">"%s.</span><span class="sc">\n</span><span class="st">"</span><span class="op">,</span> err<span class="op">-></span>message<span class="op">);</span></span>
|
||
<span id="cb5-41"><a href="#cb5-41"></a> g_clear_error <span class="op">(&</span>err<span class="op">);</span></span>
|
||
<span id="cb5-42"><a href="#cb5-42"></a> <span class="op">}</span></span>
|
||
<span id="cb5-43"><a href="#cb5-43"></a> <span class="op">}</span></span>
|
||
<span id="cb5-44"><a href="#cb5-44"></a> <span class="cf">if</span> <span class="op">(</span>gtk_notebook_get_n_pages <span class="op">(</span>GTK_NOTEBOOK <span class="op">(</span>nb<span class="op">))</span> <span class="op">></span> <span class="dv">0</span><span class="op">)</span> <span class="op">{</span></span>
|
||
<span id="cb5-45"><a href="#cb5-45"></a> gtk_window_present <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb5-46"><a href="#cb5-46"></a> <span class="op">}</span> <span class="cf">else</span></span>
|
||
<span id="cb5-47"><a href="#cb5-47"></a> gtk_window_destroy <span class="op">(</span>GTK_WINDOW <span class="op">(</span>win<span class="op">));</span></span>
|
||
<span id="cb5-48"><a href="#cb5-48"></a><span class="op">}</span></span></code></pre></div>
|
||
<p>The whole source code of <code>tfe3.c</code> is stored in the src/tfe
|
||
directory.</p>
|
||
<h3 id="using-ui-string">Using ui string</h3>
|
||
<p>GtkBuilder can build widgets with string. Use
|
||
<code>gtk_builder_new_from_string</code> instead of
|
||
<code>gtk_builder_new_from_file</code>.</p>
|
||
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="dt">char</span> <span class="op">*</span>uistring<span class="op">;</span></span>
|
||
<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>uistring <span class="op">=</span></span>
|
||
<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a><span class="st">"<interface>"</span></span>
|
||
<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> <span class="st">"<object class="</span>GtkApplicationWindow<span class="st">" id="</span>win<span class="st">">"</span></span>
|
||
<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="st">"<property name=</span><span class="sc">\"</span><span class="st">title</span><span class="sc">\"</span><span class="st">>file editor</property>"</span></span>
|
||
<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> <span class="st">"<property name=</span><span class="sc">\"</span><span class="st">default-width</span><span class="sc">\"</span><span class="st">>600</property>"</span></span>
|
||
<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> <span class="st">"<property name=</span><span class="sc">\"</span><span class="st">default-height</span><span class="sc">\"</span><span class="st">>400</property>"</span></span>
|
||
<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a> <span class="st">"<child>"</span></span>
|
||
<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> <span class="st">"<object class=</span><span class="sc">\"</span><span class="st">GtkBox</span><span class="sc">\"</span><span class="st">>"</span></span>
|
||
<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a> <span class="st">"<property name="</span>orientation<span class="st">">GTK_ORIENTATION_VERTICAL</property>"</span></span>
|
||
<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a><span class="st">"</interface>"</span><span class="op">;</span></span>
|
||
<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a></span>
|
||
<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>build <span class="op">=</span> gtk_builder_new_from_string <span class="op">(</span>uistring<span class="op">,</span> <span class="op">-</span><span class="dv">1</span><span class="op">);</span></span></code></pre></div>
|
||
<p>This method has an advantage and disadvantage. The advantage is that
|
||
the ui string is written in the source code. So, no ui file is needed on
|
||
runtime. The disadvantage is that writing C string is a bit bothersome
|
||
because of the double quotes. If you want to use this method, you should
|
||
write a script that transforms ui file into C-string.</p>
|
||
<ul>
|
||
<li>Add backslash before each double quote.</li>
|
||
<li>Add double quotes at the left and right of the string in each
|
||
line.</li>
|
||
</ul>
|
||
<h3 id="gresource">Gresource</h3>
|
||
<p>Gresource is similar to string. But Gresource is compressed binary
|
||
data, not text data. And there’s a compiler that compiles ui file into
|
||
Gresource. It can compile not only text files but also binary files such
|
||
as images, sounds and so on. And after compilation, it bundles them up
|
||
into one Gresource object.</p>
|
||
<p>An xml file is necessary for the resource compiler
|
||
<code>glib-compile-resources</code>. It describes resource files.</p>
|
||
<div class="sourceCode" id="cb7"><pre
|
||
class="sourceCode numberSource xml numberLines"><code class="sourceCode xml"><span id="cb7-1"><a href="#cb7-1"></a><span class="fu"><?xml</span><span class="ot"> version=</span><span class="st">"1.0"</span><span class="ot"> encoding=</span><span class="st">"UTF-8"</span><span class="fu">?></span></span>
|
||
<span id="cb7-2"><a href="#cb7-2"></a><<span class="kw">gresources</span>></span>
|
||
<span id="cb7-3"><a href="#cb7-3"></a> <<span class="kw">gresource</span><span class="ot"> prefix=</span><span class="st">"/com/github/ToshioCP/tfe3"</span>></span>
|
||
<span id="cb7-4"><a href="#cb7-4"></a> <<span class="kw">file</span>>tfe3.ui</<span class="kw">file</span>></span>
|
||
<span id="cb7-5"><a href="#cb7-5"></a> </<span class="kw">gresource</span>></span>
|
||
<span id="cb7-6"><a href="#cb7-6"></a></<span class="kw">gresources</span>></span></code></pre></div>
|
||
<ul>
|
||
<li>2: <code>gresources</code> tag can include multiple gresources
|
||
(gresource tags). However, this xml has only one gresource.</li>
|
||
<li>3: The gresource has a prefix
|
||
<code>/com/github/ToshioCP/tfe3</code>.</li>
|
||
<li>4: The name of the gresource is <code>tfe3.ui</code>. The resource
|
||
will be pointed with <code>/com/github/ToshioCP/tfe3/tfe3.ui</code> by
|
||
GtkBuilder. The pattern is “prefix” + “name”. If you want to add more
|
||
files, insert them between line 4 and 5.</li>
|
||
</ul>
|
||
<p>Save this xml text to <code>tfe3.gresource.xml</code>. The gresource
|
||
compiler <code>glib-compile-resources</code> shows its usage with the
|
||
argument <code>--help</code>.</p>
|
||
<pre><code>$ glib-compile-resources --help
|
||
Usage:
|
||
glib-compile-resources [OPTION..] FILE
|
||
|
||
Compile a resource specification into a resource file.
|
||
Resource specification files have the extension .gresource.xml,
|
||
and the resource file have the extension called .gresource.
|
||
|
||
Help Options:
|
||
-h, --help Show help options
|
||
|
||
Application Options:
|
||
--version Show program version and exit
|
||
--target=FILE Name of the output file
|
||
--sourcedir=DIRECTORY The directories to load files referenced in FILE from (default: current directory)
|
||
--generate Generate output in the format selected for by the target filename extension
|
||
--generate-header Generate source header
|
||
--generate-source Generate source code used to link in the resource file into your code
|
||
--generate-dependencies Generate dependency list
|
||
--dependency-file=FILE Name of the dependency file to generate
|
||
--generate-phony-targets Include phony targets in the generated dependency file
|
||
--manual-register Don't automatically create and register resource
|
||
--internal Don't export functions; declare them G_GNUC_INTERNAL
|
||
--external-data Don't embed resource data in the C file; assume it's linked externally instead
|
||
--c-name C identifier name used for the generated source code
|
||
-C, --compiler The target C compiler (default: the CC environment variable)</code></pre>
|
||
<p>Now run the compiler.</p>
|
||
<pre><code>$ glib-compile-resources tfe3.gresource.xml --target=resources.c --generate-source</code></pre>
|
||
<p>Then a C source file <code>resources.c</code> is generated. Modify
|
||
<code>tfe3.c</code> and save it as <code>tfe3_r.c</code>.</p>
|
||
<div class="sourceCode" id="cb10"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="pp">#include </span><span class="im">"resources.c"</span></span>
|
||
<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a>build <span class="op">=</span> gtk_builder_new_from_resource <span class="op">(</span><span class="st">"/com/github/ToshioCP/tfe3/tfe3.ui"</span><span class="op">);</span></span>
|
||
<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span>
|
||
<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a><span class="op">...</span> <span class="op">...</span> <span class="op">...</span></span></code></pre></div>
|
||
<p>The function <code>gtk_builder_new_from_resource</code> builds
|
||
widgets from a resource.</p>
|
||
<p>Then, compile and run it.</p>
|
||
<pre><code>$ comp tfe3_r
|
||
$ ./a.out tfe2.c</code></pre>
|
||
<p>A window appears and it is the same as the screenshot at the
|
||
beginning of this page.</p>
|
||
<p>Generally, resource is the best way for C language. If you use other
|
||
languages like Ruby, string is better than resource.</p>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
|
||
</body>
|
||
</html>
|