{"id":1148,"date":"2018-11-01T16:46:29","date_gmt":"2018-11-01T15:46:29","guid":{"rendered":"http:\/\/hobbykeller.spdns.de\/?p=1148"},"modified":"2019-01-31T01:30:06","modified_gmt":"2019-01-31T00:30:06","slug":"pygtk-pack_start-parameters","status":"publish","type":"post","link":"https:\/\/hobbykeller.spdns.de\/?p=1148","title":{"rendered":"pyGTK pack_start parameters"},"content":{"rendered":"<p>When I started to work with pyGTK, I had the impression that documentation is not as abundant and detailed as for learning the standard Python language in general. Among the most popular tutorials are an <a href=\"https:\/\/www.tutorialspoint.com\/pygtk\">introduction to pyGTK by tutorialspoint.com<\/a> and (so far my favourite) an <a href=\"https:\/\/python-gtk-3-tutorial.readthedocs.io\/en\/latest\/\">intro by readthedocs.io<\/a>. While these tutorials will explain the technical basics, I would have sometimes preferred a few more graphical illustrations to understand the effects of different commands to arrange graphical elements (&#8216;widgets&#8217;) in a window.<\/p>\n<p><!--more--><\/p>\n<p>A method frequently needed to arrange widgets in so called <code>Box<\/code> containers that pops up in early introductory examples is <code>pack_start<\/code>. I had a particular hard time of imagining what effects each of its parameters would have. So here&#8217;s a graphical illustration.<\/p>\n<h1>The function parameters<\/h1>\n<p>Taking the examples from the pyGTK tutorials and the <a href=\"https:\/\/developer.gnome.org\/gtk3\/stable\/GtkBox.html#gtk-box-pack-start\">official GTK documentation<\/a> (which is not Python specific, but C++), the template for the <code>pack_start<\/code> function is as follows:<\/p>\n<pre class=\"lang:default decode:true\" title=\"pack_start function template\">box.pack_start(childWidget, expand, fill, padding)<\/pre>\n<ul>\n<li style=\"list-style-type: none;\">\n<ul>\n<li>\u00a0Unsurprisingly, <code>box<\/code> is the destination <code>Box<\/code> object into which the <code>childWidget<\/code> is packed.<\/li>\n<li><code>childWidget<\/code>can be almost any widget &#8211; a Label, a CheckButton, a ComboBox, an image etc.<\/li>\n<li><code>expand<\/code>\u00a0is of type boolean. If set to <code>True<\/code>, Gtk will distribute all child objects with equal spaces in between. The name is a quite misleading, because <strong>the effect is not to alter the size of the object<\/strong>. Rather, the parameter influences the <strong>positioning<\/strong> of the object (with respect to the height of the <code>VBox<\/code> or the width of an <code>HBox<\/code>).Those who do PowerPoint will know the horizontally and vertically arrange buttons which have the same effect:\n<ul>\n<li>In case we have a <code>VBox<\/code>, the objects each object will be horizontally stretched to the full width of the VBox, and they will vertically be arranged so that the space before and after each object is identical.<\/li>\n<li>In case we have an <code>HBox<\/code>, each widget will be vertically stretched to the full height of the box. Horizontally, the objects will be arranged so that the space before and after each object has the same width.<\/li>\n<\/ul>\n<\/li>\n<li>Similar ill-labelled is the <code>fill<\/code> parameter. First of all, the parameter is without any effect if <code>expand<\/code> is set to <code>False<\/code>. This parameter actually <strong>stretches<\/strong> each widget arranged along the Box object so that any blank space is filled (evidently, this does only make sense when the objects are aligned with equal spaces along the Box by <code>expand=True<\/code>.<\/li>\n<li>The <code>padding<\/code> parameter has an equally strange defintion. According to the GTK+3 reference (which again isn&#8217;t Python specific) padding is basically the amount of Pixels that a widget is shifted along the orientation of the Box (i.e. horizontally to the right in case of an HBox, vertically to the bottom in case of a VBox) &#8220;over and above the global amount specified by the spacing property&#8221;. The spacing property is by default set to 0 and determines the distance of a widget from its neighbours.<\/li>\n<\/ul>\n<\/li>\n<\/ul>\n<p>A less confusing way to name the function parameters would be something like:<\/p>\n<pre class=\"lang:default decode:true\" title=\"pack_start with better parameter naming\">box.pack_start(widget, arrange, stretch, padding)<\/pre>\n<h1>The Basic Code<\/h1>\n<p>The code I am using produces 4 objects (a Button, a CheckButton, a Label and a ComboBox) and puts them all in a VBox that fills the whole main window. As a consequence, the pack_start function is called 4 times &#8211; once each for placing the 4 objects.<\/p>\n<pre class=\"lang:default decode:true\" title=\"pack_start example code (1)\">import gi\ngi.require_version('Gtk', '3.0')\nfrom gi.repository import Gtk\n\nwin = Gtk.Window(title='Demo')\nwin.set_default_size(200, 300)\nwin.connect('delete-event', Gtk.main_quit)\n\nvbox = Gtk.VBox(spacing=10)\nwin.add(vbox)\nbtn = Gtk.Button(\"Do not click here\")\nchk = Gtk.CheckButton(\"Mit alles...\")\nlbl = Gtk.Label(\"Alles f\u00fcr den Dackel\")\ncmb = Gtk.ComboBox()\n\nvbox.pack_start(chk, False, True, 0)\nvbox.pack_start(btn, False, True, 0)\nvbox.pack_start(lbl, False, True, 0)\nvbox.pack_start(cmb, False, True, 0)\n\nwin.show_all()\n\nGtk.main()<\/pre>\n<h1>Parameter Testing<\/h1>\n<h2><code>arrange = False<\/code><\/h2>\n<p>We start with calling <code>pack_start<\/code> with <code>arrange=False<\/code> as in the above base example:<\/p>\n<pre class=\"lang:default decode:true\">vbox.pack_start(chk, True, False, 0)\nvbox.pack_start(btn, True, False, 0)\nvbox.pack_start(lbl, True, False, 0)\nvbox.pack_start(cmb, True, False, 0)<\/pre>\n<p>Note without any arranging along the orientation of the Box object, the <code>stretch<\/code> parameter is completely without any effect whether it&#8217;s set to <code>True<\/code> or <code>False<\/code>. The left Window in the image below is with <code>padding=0<\/code>, the right image is with <code>padding=20<\/code> for the second <code>pack_start<\/code> command that packs the Button.<\/p>\n<figure id=\"attachment_1154\" aria-describedby=\"caption-attachment-1154\" style=\"width: 416px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-1154\" src=\"http:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_0.png\" alt=\"\" width=\"416\" height=\"337\" srcset=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_0.png 416w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_0-300x243.png 300w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_0-370x300.png 370w\" sizes=\"auto, (max-width: 416px) 100vw, 416px\" \/><figcaption id=\"caption-attachment-1154\" class=\"wp-caption-text\"><code>pack_start<\/code> called with <code>arrange=False<\/code> and <code>padding=0<\/code> for all widgets (left) and with <code>padding=20<\/code> for the first widget (right)<\/figcaption><\/figure>\n<p>As expected, each widget is packed along the vertical orientation of the VBox. Note that <code>pack_start<\/code> by enforces stretching each widget in its width to match the full width of the VBox. In case an HBox, <code>pack_start<\/code> would stuff any widget without any horizontal space from left to right but would stretch any widget vertically to meet the height of the HBox.<\/p>\n<p>We also see, that setting padding to a non-zero value enforces the space to the neighboring items before and after the widget that was packed with that padding value. The (vertical) distance between the preceding CheckBox and the Button has increased as well as the (vertical) distance between the Button and the following Label.<\/p>\n<h2><code>arrange = True, stretch = False<\/code><\/h2>\n<p>When calling <code>pack_start<\/code> with <code>arrange=True<\/code> and <code>stretch=False<\/code>, Gtk spreads the\u00a0 widgets evenly on the vertical axis (in case of a VBox), with equal vertical white space being put before and after each widget.<\/p>\n<figure id=\"attachment_1156\" aria-describedby=\"caption-attachment-1156\" style=\"width: 416px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-1156\" src=\"http:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_1.png\" alt=\"\" width=\"416\" height=\"337\" srcset=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_1.png 416w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_1-300x243.png 300w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/10\/start_pack_1-370x300.png 370w\" sizes=\"auto, (max-width: 416px) 100vw, 416px\" \/><figcaption id=\"caption-attachment-1156\" class=\"wp-caption-text\"><code>pack_start<\/code> function invoked with <code>arrange=True<\/code> and <code>stretch=False<\/code> with <code>padding=0<\/code> (left) and <code>padding=20<\/code> (right) for the CheckBox<\/figcaption><\/figure>\n<p>Again to test for the effect of a non-zero <code>padding<\/code> parameter, we have set <code>padding=20<\/code> (this time for the first element packed which is the CheckBox). This increases the vertical space above and below the CheckBox by 20px while the remaining 3 widgets are equally spaced apart along the remaining vertical space.<\/p>\n<h2><code>arrange = True, stretch = True<\/code><\/h2>\n<p>Setting both <code>arrange<\/code> and <code>stretch<\/code> to <code>True<\/code> will first distribute all widgets evenly spaced along the orientation of the box (i.e. vertically in case of a VBox and horizontally in case of an Hbox) and then stretch any widgets to fill the gaps left arranging the widgets with equal spacing.<\/p>\n<p>Again, in order to observe the effect of the <code>padding<\/code> parameter, <code>padding<\/code> was set to <code>20<\/code> for one single widget (this time the Label widget, i.e. the 3rd element to be placed in the containing VBox) while all the others were set to <code>0<\/code>.<\/p>\n<figure id=\"attachment_1157\" aria-describedby=\"caption-attachment-1157\" style=\"width: 408px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-1157\" src=\"http:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/11\/start_pack_2.png\" alt=\"\" width=\"408\" height=\"338\" srcset=\"https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/11\/start_pack_2.png 408w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/11\/start_pack_2-300x249.png 300w, https:\/\/hobbykeller.spdns.de\/wp-content\/uploads\/2018\/11\/start_pack_2-362x300.png 362w\" sizes=\"auto, (max-width: 408px) 100vw, 408px\" \/><figcaption id=\"caption-attachment-1157\" class=\"wp-caption-text\"><code>pack_start<\/code> function with both <code>arrange<\/code> and <code>expand<\/code> parameter set to <code>True<\/code>, once with <code>padding=0<\/code> for all widgets and once with <code>padding=20<\/code> for the 3rd widget<\/figcaption><\/figure>\n<p>As expected setting <code>padding=20<\/code> for the Label widget with <code>arrange=True<\/code> will first align all widgets with equal vertical free space among them, then <code>stretch=True<\/code> will stretch each widget equally in height (for VBox, width for Hbox) until all empty space between the widgets is consumed. Finally the Label will be extended 20px up and 20px down at the expanse of shrinking all remaining Labels proportionally.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>When I started to work with pyGTK, I had the impression that documentation is not as abundant and detailed as for learning the standard Python language in general. Among the<span class=\"more-button\"><a href=\"https:\/\/hobbykeller.spdns.de\/?p=1148\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\">pyGTK pack_start parameters<\/span><\/a><\/span><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[64],"tags":[251,252,253,250,132],"class_list":["post-1148","post","type-post","status-publish","format-standard","hentry","category-linux","tag-gtk","tag-gui","tag-pack_start","tag-pygtk","tag-python"],"_links":{"self":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts\/1148","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1148"}],"version-history":[{"count":7,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts\/1148\/revisions"}],"predecessor-version":[{"id":1179,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=\/wp\/v2\/posts\/1148\/revisions\/1179"}],"wp:attachment":[{"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1148"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1148"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/hobbykeller.spdns.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1148"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}