Python 3 + GTK 4 – Buttons with pictures and labels look weird

Question:

I develop a simple app for Linux, Kamarada Firstboot (source on GitLab), using Python 3 and GTK, and I’m migrating from GTK 3 to GTK 4. In case you are curious, you can see it in action if you download the Linux Kamarada ISO image and boot it using e.g. VirtualBox. The following screenshots are from the current version (15.3 branch), based on GTK 3.

enter image description here

enter image description here

I ported most of it to GTK 4 already (gtk4 branch). But I’m facing an issue with the GtkButton‘s, as since GTK 4 they don’t have the label and image properties anymore, and to achieve the same appearance I need to use a combination of GtkBox, GtkPicture and GtkLabel.

But although all my GtkButton‘s have similar sources:

      <object class="GtkButton" id="btnPortuguese">
        <property name="child">
          <object class="GtkBox">
            <property name="margin-bottom">10</property>
            <property name="margin-end">10</property>
            <property name="margin-start">10</property>
            <property name="margin-top">10</property>
            <property name="orientation">vertical</property>
            <property name="spacing">10</property>
            <child>
              <object class="GtkPicture" id="imgPortuguese">
                <property name="halign">center</property>
                <property name="valign">start</property>
              </object>  
            </child>
            <child>
              <object class="GtkLabel">
                <property name="label">Português Brasileiro</property>
              </object>
            </child>
          </object>
        </property>
        <layout>
          <property name="column">0</property>
          <property name="row">2</property>
        </layout>
        <signal name="clicked" handler="onBtnPortugueseClicked"/>
      </object>

Each of them look differently:

enter image description here

enter image description here

What am I doing wrong?

I’m new to both Python and GTK, but I have some experience programming.

I believe the most relevant files for this question are: kamarada-firstboot.py and kamarada-firstboot.ui.

Here’s how one can easily get started with the project (supposing Git, Python 3 and GTK 4 are installed already):

$ git clone https://gitlab.com/kamarada/firstboot.git
$ cd firstboot
$ git checkout gtk4
$ cd usr/share/kamarada-firstboot
$ python3 kamarada-firstboot.py

When the program ends, it outputs the user choices to ~/.config/kamarada-firstboot. You may want to delete this file between tests.

Asked By: Antônio Medeiros

||

Answers:

Using the GTK Inspector on some GNOME core apps and studying their source codes, I found a solution.

Each software listed in GNOME Software corresponds to a GsSummaryTile, which inherits from GsAppTile, whose parent is the GtkButton. So, we are seeing buttons here:

enter image description here

The GsSummaryTile uses a GtkGrid (not a GtkBox, as I was trying to do) to pack the GtkImage and the GtkLabel‘s together.

I did that inside the buttons:

          <object class="GtkButton" id="btnPortuguese">
            <property name="child">
              <object class="GtkGrid">
                <property name="halign">center</property>
                <property name="margin-bottom">12</property>
                <property name="margin-top">12</property>
                <property name="row-spacing">12</property>
                <property name="valign">center</property>
                <child>
                  <object class="GtkPicture" id="imgPortuguese">
                    <property name="halign">center</property>
                    <property name="valign">end</property>
                    <layout>
                      <property name="column">0</property>
                      <property name="row">0</property>
                    </layout>
                  </object>  
                </child>
                <child>
                  <object class="GtkLabel">
                    <property name="justify">center</property>
                    <property name="label">Português Brasileiro</property>
                    <property name="valign">start</property>
                    <layout>
                      <property name="column">0</property>
                      <property name="row">1</property>
                    </layout>
                  </object>
                </child>
              </object>
            </property>
            <!-- ... -->
          </object>

enter image description here

And to make the buttons have the same width and height, I put them inside a GtkGrid with column-homogeneous and row-homogeneous set to True:

      <object class="GtkGrid">
        <property name="column-homogeneous">True</property>
        <property name="column-spacing">24</property>
        <property name="row-homogeneous">True</property>
        <child>
          <object class="GtkButton" id="btnPortuguese">
          <!-- ... -->
        </child>
        <child>
          <object class="GtkButton" id="btnEnglish">
          <!-- ... -->
        </child>
      </object>

With the buttons on the second stack, I did a similar solution, but with one detail: I split the button in half and put the icon on the first (upper) half and the label on the second (bottom) half, setting row-homogeneous to True on the inner GtkGrid, valign to end on the GtkPicture and valign to start on the GtkLabel.

enter image description here

          <object class="GtkButton" id="btnInstall">
            <property name="halign">fill</property>
            <property name="valign">fill</property>
            <property name="child">
              <object class="GtkGrid">
                <property name="halign">center</property>
                <property name="margin-bottom">12</property>
                <property name="margin-top">12</property>
                <property name="row-homogeneous">True</property>
                <property name="valign">center</property>
                <child>
                  <object class="GtkPicture" id="imgInstall">
                    <property name="halign">center</property>
                    <property name="valign">end</property>
                    <layout>
                      <property name="column">0</property>
                      <property name="row">0</property>
                    </layout>
                  </object>  
                </child>
                <child>
                  <object class="GtkLabel" id="lbInstallButton">
                    <property name="justify">center</property>
                    <property name="label">Install Linux Kamarada</property>
                    <property name="margin-top">12</property>
                    <property name="valign">start</property>
                    <layout>
                      <property name="column">0</property>
                      <property name="row">1</property>
                    </layout>
                  </object>
                </child>
              </object>
            </property>
            <!-- ... -->
          </object>

I believe I summarized the main ideas of my solution.

You can see the full source here: kamarada-firstboot.ui.

Answered By: Antônio Medeiros
Categories: questions Tags: , , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.