如何在任意位置单击 Gtk.Box 时打开网页,尽管其中有 Gtk.LinkButton 链接?

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

实用上,我喜欢Gtk.LinkButton的风格,想在我的程序中用它做一个广告banner。下面的标签将是 link 目的地的单段描述。但是在横幅上的任何地方都应该单击鼠标打开 link.

这是我试过的。当我单击 Gtk.LinkButton 时,两个 URI 都会打开。当我单击 window 上的其他地方时,什么也没做。

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>

截图:

目前,我正在研究和尝试here描述的一些技术,但我希望有人能早点更快地帮助我。

一个简单的解决方案是将盒子容器包裹在 Gtk.EventBox 中。这可以在 Glade 中轻松完成,方法是右键单击盒子容器并选择 Add Parent,然后选择 Event Box,如下图所示 (注意:widget树已经添加了事件框,应该是添加事件框的结果):

然后,例如,在代码中,box 应该是接收按钮释放事件信号的事件框,处理程序可以从 user_data 接收 LinkBut​​ton 并发出点击信号以模拟单击按钮。

调整代码:

# 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):
    user_data.clicked()
    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()

, 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).

Windows (10) 上的 Adwaita window 装饰也存在一些问题。当可点击框是 window 中的第一个或唯一子项时,单击死区然后移动 window 会触发打开网页。我通过在 Gtk.AspectFrame.

中插入 Gtk.Box 解决了这个问题

最终示例

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>