Search code examples
python-2.7hyperlinkadsgtk3msys2

How to open a web page when a Gtk.Box is clicked anywhere, in spite of the Gtk.LinkButton links inside it?


Practically, I like the style of Gtk.LinkButton and I want to use it to make an advertisement banner in my program. The label below would be a single-paragraph description of the destination of the link. But anywhere on the banner should a mouse click open the link.

This is what I tried. When I click on the Gtk.LinkButton, both URIs are opened. When I click elsewhere on the window, nothing is done.

example.py:

# coding=utf-8

import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk

b = Gtk.Builder()
b.add_from_file("test.glade")

w = b.get_object("window1")


def box_clicked(widget, event, user_data=None):
    del widget, event, user_data

    Gtk.show_uri_on_window(w, "http://lumea-lui-silviu.blogspot.ro",
                           Gdk.CURRENT_TIME)


linkButton = b.get_object("linkButton")
box = b.get_object("box1")
box.connect("button-release-event", box_clicked)

w.connect("delete-event", Gtk.main_quit)
w.show_all()
Gtk.main()

test.glade:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.20.0 -->
<interface>
  <requires lib="gtk+" version="3.20"/>
  <object class="GtkWindow" id="window1">
    <property name="can_focus">False</property>
    <child>
      <object class="GtkBox" id="box1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <child>
          <object class="GtkLinkButton" id="linkButton">
            <property name="label" translatable="yes">button</property>
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="receives_default">True</property>
            <property name="relief">none</property>
            <property name="uri">http://www.google.com</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">0</property>
          </packing>
        </child>
        <child>
          <object class="GtkLabel" id="multilineLabel">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">this
is
a
multiline
label</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="fill">True</property>
            <property name="position">1</property>
          </packing>
        </child>
      </object>
    </child>
  </object>
</interface>

Screenshot:

Screenshot

Currently, I study and try some tehniques described here, but I wish someone helps me earlier and faster.


Solution

  • With the code modifications by José Fonte (please vote his answer too), when the label is clicked, the web page is opened as expected, but when the user clicks on the Gtk.LinkButton the web page opens twice. I solved this by setting in Glade the above-child property of the Gtk.EventBox to On and by returning True from the signal handler (the behavior is described in the documentation found here).

    There also were some problems with the Adwaita window decorations on Windows (10). When the clickable box is the first or only child in a window, clicking on a dead zone and then moving the window triggers the opening of the web page. I solved this problem by inserting the Gtk.Box inside a Gtk.AspectFrame.

    Final example

    example.py

    # coding=utf-8
    
    import gi
    gi.require_version("Gtk", "3.0")
    from gi.repository import Gtk, Gdk
    
    b = Gtk.Builder()
    b.add_from_file("test.glade")
    
    w = b.get_object("window1")
    
    def box_clicked(widget, event, user_data):
        #del widget, event, user_data
    
        # New tehnique:
        user_data.clicked()
    
        # Old tehnique:
        # Gtk.show_uri_on_window(w, "http://lumea-lui-silviu.blogspot.ro",
        #                        Gdk.CURRENT_TIME)
    
        return True
    
    linkButton = b.get_object("linkButton")
    box = b.get_object("eventbox1")
    box.connect("button-release-event", box_clicked, linkButton)
    
    w.connect("delete-event", Gtk.main_quit)
    w.show_all()
    Gtk.main()
    

    test.glade

    <?xml version="1.0" encoding="UTF-8"?>
    <!-- Generated with glade 3.20.0 -->
    <interface>
      <requires lib="gtk+" version="3.20"/>
      <object class="GtkWindow" id="window1">
        <property name="can_focus">False</property>
        <child>
          <object class="GtkAspectFrame">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label_xalign">0</property>
            <child>
              <object class="GtkEventBox" id="eventbox1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <property name="above_child">True</property>
                <child>
                  <object class="GtkBox" id="box1">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="orientation">vertical</property>
                    <child>
                      <object class="GtkLinkButton" id="linkButton">
                        <property name="label" translatable="yes">button</property>
                        <property name="visible">True</property>
                        <property name="can_focus">True</property>
                        <property name="receives_default">True</property>
                        <property name="relief">none</property>
                        <property name="uri">http://www.google.com</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">0</property>
                      </packing>
                    </child>
                    <child>
                      <object class="GtkLabel" id="multilineLabel">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="label" translatable="yes">this
    is
    a
    multiline
    label</property>
                      </object>
                      <packing>
                        <property name="expand">False</property>
                        <property name="fill">True</property>
                        <property name="position">1</property>
                      </packing>
                    </child>
                  </object>
                </child>
              </object>
            </child>
          </object>
        </child>
      </object>
    </interface>