PyGobject(三十一)布局容器之EventBox

Gtk.EventBox

Gtk.EventBox有自己的窗口。对于那些没有自己窗口的部件捕捉事件是非常有用的

继承关系

Gtk.EventBox是Gtk.Bin的直接子类
这里写图片描述

Methods

方法修饰词方法名及参数
staticnew ()
get_above_child ()
get_visible_window ()
set_above_child (above_child)
set_visible_window (visible_window)

Virtual Methods

Properties

NameTypeFlagsShort Description
above-childboolr/w/enWhether the event-trapping window of the eventbox is above the window of the child widget as opposed to below it.
visible-windowboolr/w/enWhether the event box is visible, as opposed to invisible and only used to trap events.

Signals

NameShort Description

例子

捕捉鼠标按键事件

这里写图片描述
代码:

#!/usr/bin/env python3
# Created by xiaosanyu at 16/7/12
# section 037
# 
# author: xiaosanyu
# website: yuxiaosan.tk \
#          http://blog.csdn.net/a87b01c14
# created: 16/7/12

TITLE = "EventBox"
DESCRIPTION = """
The Gtk.EventBox widget is a subclass of Gtk.Bin which also has its own window.
It is useful since it allows you to catch events for widgets which do not have their own window.
"""
import gi

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


class EventBoxWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="EventBox Example")
        self.set_size_request(200, 200)
        self.set_border_width(10)

        box = Gtk.VBox()
        label = Gtk.Label("press your mouse.")
        box.add(label)
        label = Gtk.Label()
        box.add(label)
        eventbox = Gtk.EventBox()
        eventbox.connect("button-press-event", self.on_button_press_event, label)
        eventbox.add(box)
        self.add(eventbox)

    @staticmethod
    def on_button_press_event(widget, event, label):
        # Check if right mouse button was preseed
        if event.type == Gdk.EventType.BUTTON_PRESS:
            if event.button == Gdk.BUTTON_PRIMARY:
                label.set_label("you press The left mouse button")
            if event.button == Gdk.BUTTON_MIDDLE:
                label.set_label("you press The middle mouse button")
            if event.button == Gdk.BUTTON_SECONDARY:
                label.set_label("you press The right mouse button")


def main():
    win = EventBoxWindow()
    win.connect("delete-event", Gtk.main_quit)
    win.show_all()
    Gtk.main()


if __name__ == "__main__":
    main()

代码解析:
创建一个Gtk.EventBox

eventbox = Gtk.EventBox()

连接Gtk.Widget::button_press_event(widget, event)信号

eventbox.connect("button-press-event", self.on_button_press_event, label)

在on_button_press_event方法中,先判断事件(Gdk.EventButton)的类别是否为按键,
再判断按下的键是哪一个

这里写图片描述

代码

#!/usr/bin/env python3
# Created by xiaosanyu at 16/7/12
# section 038
# Event Axes

# Demonstrates advanced handling of event information from exotic
# input devices.
#
# On one hand, this snippet demonstrates management of input axes,
# those contain additional information for the pointer other than
# X/Y coordinates.
#
# Input axes are dependent on hardware devices, on linux/unix you
# can see the device axes through xinput list <device>. Each time
# a different hardware device is used to move the pointer, the
# master device will be updated to match the axes it provides,
# these changes can be tracked through GdkDevice::changed, or
# checking gdk_event_get_source_device().
#
# On the other hand, this demo handles basic multitouch events,
# each event coming from an specific touchpoint will contain a
# GdkEventSequence that's unique for its lifetime, so multiple
# touchpoints can be tracked.
# author: xiaosanyu
# website: yuxiaosan.tk \
#          http://blog.csdn.net/a87b01c14
# created: 16/7/12

TITLE = "EventBox(1)"
DESCRIPTION = ""
import gi
import cairo

gi.require_version('Gtk', '3.0')
gi.require_version('PangoCairo', '1.0')
from gi.repository import Gtk, Gdk, GLib, PangoCairo, GObject


class AxesInfo(object):
    def __init__(self, event=None, last_source=None, last_tool=None, axes=None, color=None, x=None, y=None):
        # GObject.GObject.__init__(self)
        self.event = event
        self.last_source = last_source  # Gdk.Device
        self.last_tool = last_tool  # Gdk.DeviceTool
        self.axes = axes  # [Gdk.EventMotion.axes] or [Gdk.EventButton.axes]
        self.color = color  # Gdk.RGBA
        self.x = x  # double
        self.y = y  # double


class EventData(object):
    def __init__(self, pointer_info=None, touch_info=None):
        # GObject.GObject.__init__(self)
        self.pointer_info = pointer_info  # dict {Gdk.Device}
        self.touch_info = touch_info  # dict {Gdk.EventSequence}


colors = ("black", "orchid", "fuchsia", "indigo", "thistle", "sienna",
          "azure", "plum", "lime", "navy", "maroon", "burlywood")

cur_color = 0


class EventBoxWindow(Gtk.Window):
    def __init__(self):
        Gtk.Window.__init__(self, title="Event Axes")
        self.set_default_size(400, 400)

        eventbox = Gtk.EventBox()
        eventbox.set_support_multidevice(True)
        eventbox.add_events(
                Gdk.EventMask.POINTER_MOTION_MASK |
                Gdk.EventMask.BUTTON_PRESS_MASK |
                Gdk.EventMask.BUTTON_RELEASE_MASK |
                Gdk.EventMask.SMOOTH_SCROLL_MASK |
                Gdk.EventMask.ENTER_NOTIFY_MASK |
                Gdk.EventMask.LEAVE_NOTIFY_MASK |
                Gdk.EventMask.TOUCH_MASK)

        event_data = self.event_data_new()

        eventbox.connect("event", self.event_cb, event_data)
        eventbox.connect("draw", self.draw_cb, event_data)
        self.add(eventbox)

    @staticmethod
    def axes_info_new():
        global cur_color
        info = AxesInfo()
        info.color = Gdk.RGBA.from_color(Gdk.Color.parse(colors[cur_color])[1])

        cur_color = (cur_color + 1) % len(colors)

        return info

    @staticmethod
    def event_data_new():
        data = EventData()
        data.pointer_info = {}
        data.touch_info = {}

        return data

    def update_axes_from_event(self, event, data):
        device = event.get_device()
        source_device = event.get_source_device()
        sequence = event.get_event_sequence()
        tool = event.get_device_tool()
        if event.type == Gdk.EventType.TOUCH_END or event.type == Gdk.EventType.TOUCH_CANCEL:
            return data.touch_info.pop(sequence, False)

        elif event.type == Gdk.EventType.LEAVE_NOTIFY:
            return data.pointer_info.pop(device, False)

        if not sequence:
            info = data.pointer_info.get(device, None)

            if not info:
                info = self.axes_info_new()
                data.pointer_info.setdefault(device, info)
        else:
            info = data.touch_info.get(sequence, None)

            if not info:
                info = self.axes_info_new()
                data.touch_info.setdefault(sequence, info)

        info.event = event
        if info.last_source != source_device:
            info.last_source = source_device

        if info.last_tool != tool:
            info.last_tool = tool
        info.axes = None

        if event.type == Gdk.EventType.TOUCH_BEGIN or event.type == Gdk.EventType.TOUCH_UPDATE:
            if sequence and event.touch.emulating_pointer:
                data.pointer_info.remove(device)
        if event.type == Gdk.EventType.MOTION_NOTIFY:
            info.axes = [event.motion.axes for _ in range(source_device.get_n_axes())]
        elif event.type == Gdk.EventType.BUTTON_PRESS or event.type == Gdk.EventType.BUTTON_RELEASE:
            info.axes = [event.button.axes for _ in range(source_device.get_n_axes())]
        rlt, info.x, info.y = event.get_coords()

    def event_cb(self, widget, event, user_data):
        self.update_axes_from_event(event, user_data)
        widget.queue_draw()
        return False

    @staticmethod
    def render_arrow(cr, x_diff, y_diff, label):
        cr.save()
        cr.new_path()
        cr.move_to(0, 0)
        cr.line_to(x_diff, y_diff)
        cr.stroke()

        cr.move_to(x_diff, y_diff)
        cr.show_text(label)

        cr.restore()

    @staticmethod
    def draw_axes_info(widget, cr, info, allocation):
        axes = info.last_source.get_axes()
        cr.save()

        cr.set_line_width(1)
        Gdk.cairo_set_source_rgba(cr, info.color)

        cr.move_to(0, info.y)
        cr.line_to(allocation.width, info.y)
        cr.move_to(info.x, 0)
        cr.line_to(info.x, allocation.height)
        cr.stroke()
        cr.translate(info.x, info.y)
        if not info.axes:
            cr.restore()
            return
        if axes & Gdk.AxisFlags.PRESSURE:
            _, pressure = info.event.get_axis(Gdk.AxisUse.PRESSURE)

            pattern = cairo.RadialGradient(0, 0, 0, 0, 0, 100)
            pattern.add_color_stop_rgba(pressure, 1, 0, 0, pressure)
            pattern.add_color_stop_rgba(1, 0, 0, 1, 0)

            cr.set_source(pattern)

            cr.arc(0, 0, 100, 0, 2 * GLib.PI)
            cr.fill()

        if axes & Gdk.AxisFlags.XTILT and axes & Gdk.AxisFlags.YTILT:
            _, tilt_x = info.last_source.get_axis(Gdk.AxisUse.XTILT)
            _, tilt_y = info.event.get_axis(Gdk.AxisUse.YTILT)

            EventBoxWindow.render_arrow(cr, tilt_x * 100, tilt_y * 100, "Tilt")

        if axes & Gdk.AxisFlags.DISTANCE:
            dashes = (5.0, 5.0)
            _, distance = info.event.get_axis(Gdk.AxisFlags.DISTANCE)

            cr.save()

            cr.move_to(distance * 100, 0)

            cr.set_source_rgb(0.0, 0.0, 0.0)
            cr.set_dash(dashes, 2, 0.0)
            cr.arc(0, 0, distance * 100, 0, 2 * GLib.PI)
            cr.stroke()

            cr.move_to(0, -distance * 100)
            extents = cr.text_extents("Distance")
            cr.rel_move_to(-extents.width / 2, 0)
            cr.show_text("Distance")

            cr.move_to(0, 0)

            cr.restore()

        if axes & Gdk.AxisFlags.WHEEL:
            _, wheel = info.event.get_axis(Gdk.AxisUse.WHEEL)

            cr.save()
            cr.set_line_width(10)
            cr.set_source_rgba(0, 0, 0, 0.5)

            cr.new_sub_path()
            cr.arc(0, 0, 100, 0, wheel * 2 * GLib.PI)
            cr.stroke()
            cr.restore()

        if axes & Gdk.AxisFlags.ROTATION:
            _, rotation = info.event.get_axis(Gdk.AxisUse.ROTATION)
            rotation *= 2 * GLib.PI

            cr.save()
            cr.rotate(- GLib.PI / 2)
            cr.set_line_cap(cairo.LINE_CAP_ROUND)
            cr.set_line_width(5)

            cr.new_sub_path()
            cr.arc(0, 0, 100, 0, rotation)
            cr.stroke()
            cr.restore()

        if axes & Gdk.AxisFlags.SLIDER:
            _, slider = info.event.get_axis(Gdk.AxisUse.SLIDER)

            cr.save()

            cr.move_to(0, -10)
            cr.rel_line_to(0, -50)
            cr.rel_line_to(10, 0)
            cr.rel_line_to(-5, 50)
            cr.close_path()

            cr.clip_preserve()

            pattern = cairo.LinearGradient(0, -10, 0, -60)
            pattern.add_color_stop_rgb(0, 0, 1, 0)
            pattern.add_color_stop_rgb(1, 1, 0, 0)
            cr.set_source(pattern)

            mask = cairo.LinearGradient(0, -10, 0, -60)
            mask.add_color_stop_rgba(0, 0, 0, 0, 1)
            mask.add_color_stop_rgba(slider, 0, 0, 0, 1)
            mask.add_color_stop_rgba(slider, 0, 0, 0, 0)
            mask.add_color_stop_rgba(1, 0, 0, 0, 0)
            cr.mask(mask)

            cr.set_source_rgb(0, 0, 0)
            cr.stroke()

            cr.restore()

        if axes & Gdk.AxisFlags.X and axes & Gdk.AxisFlags.Y:
            # Tilt
            cr.save()
            _, tilt_x = info.event.get_axis(Gdk.AxisUse.X)
            _, tilt_y = info.event.get_axis(Gdk.AxisUse.Y)

            EventBoxWindow.render_arrow(cr, tilt_x, tilt_y, "Tilt")
            cr.restore()

            # pressure
            cr.save()
            _, pressure = info.event.get_axis(Gdk.AxisUse.X)

            pattern = cairo.RadialGradient(0, 0, 0, 0, 0, 100)
            pattern.add_color_stop_rgba(pressure, 1, 0, 0, pressure)
            pattern.add_color_stop_rgba(1, 0, 0, 1, 0)

            cr.set_source(pattern)

            cr.arc(0, 0, 50, 0, 2 * GLib.PI)
            cr.fill()
            cr.restore()

            # dashes
            dashes = (5.0, 5.0)
            _, distance = info.event.get_axis(Gdk.AxisUse.X)
            cr.save()

            cr.move_to(distance, 0)

            cr.set_dash(dashes)
            cr.arc(0, 0, distance, 0, 2 * GLib.PI)
            cr.stroke()

            cr.move_to(0, -distance)
            extents = cr.text_extents("Distance")
            cr.rel_move_to(-extents[3] / 2, 0)
            cr.show_text("Distance")

            cr.move_to(0, 0)

            cr.restore()

            # slider
            slider = 1
            cr.save()

            cr.move_to(0, -10)
            cr.rel_line_to(0, -50)
            cr.rel_line_to(10, 0)
            cr.rel_line_to(-5, 50)
            cr.close_path()

            cr.clip_preserve()

            pattern = cairo.LinearGradient(0, -10, 0, -60)
            pattern.add_color_stop_rgb(0, 0, 1, 0)
            pattern.add_color_stop_rgb(1, 1, 0, 0)
            cr.set_source(pattern)

            mask = cairo.LinearGradient(0, -10, 0, -60)
            mask.add_color_stop_rgba(0, 0, 0, 0, 1)
            mask.add_color_stop_rgba(slider, 0, 0, 0, 1)
            mask.add_color_stop_rgba(slider, 0, 0, 0, 0)
            mask.add_color_stop_rgba(1, 0, 0, 0, 0)
            cr.mask(mask)

            cr.set_source_rgb(0, 0, 0)
            cr.stroke()

            cr.restore()

            #
            cr.save()
            cr.set_line_cap(cairo.LINE_CAP_ROUND)
            cr.set_line_width(5)

            cr.new_sub_path()
            cr.arc(0, 0, 120, 0, 2 * GLib.PI)
            cr.stroke()
            cr.restore()

        cr.restore()

    @staticmethod
    def tool_type_to_string(tool_type):
        if tool_type == Gdk.InputSource.PEN:
            return "Pen"
        elif tool_type == Gdk.InputSource.ERASER:
            return "Eraser"
        elif tool_type == Gdk.InputSource.BRUSH:
            return "Brush"
        elif tool_type == Gdk.InputSource.PENCIL:
            return "Pencil"
        elif tool_type == Gdk.InputSource.AIRBRUSH:
            return "Airbrush"
        elif tool_type == Gdk.InputSource.MOUSE:
            return "Mouse"
        elif tool_type == Gdk.InputSource.LENS:
            return "Lens cursor"
        elif tool_type == Gdk.InputSource.UNKNOWN:
            return "Unknown"
        else:
            return "Unknown"

    @staticmethod
    def draw_device_info(widget, cr, sequence, y, info):
        cr.save()

        string = "Source: " + info.last_source.get_name()

        if sequence:
            string += "\nSequence: " + str(sequence)

        if info.last_tool:
            tool_type = EventBoxWindow.tool_type_to_string(info.last_tool.get_tool_type())
            serial = info.last_tool.get_serial()
            string += "\nTool: " + tool_type

            if serial != 0:
                string += ", Serial: %lx" % serial

        cr.move_to(10, y)
        layout = widget.create_pango_layout(string)
        PangoCairo.show_layout(cr, layout)
        cr.stroke()
        height = layout.get_pixel_size()[1]

        Gdk.cairo_set_source_rgba(cr, info.color)
        cr.set_line_width(10)
        cr.move_to(0, y)

        y = y + height
        cr.line_to(0, y)
        cr.stroke()

        cr.restore()
        return y

    def draw_cb(self, widget, cr, user_data):
        y = 0
        data = user_data
        allocation = widget.get_allocation()

        # Draw Abs info
        for key, value in data.pointer_info.items():
            # run this
            self.draw_axes_info(widget, cr, value, allocation)
        for key, value in data.touch_info.items():
            self.draw_axes_info(widget, cr, value, allocation)

        # Draw name, color legend and misc data
        for key, value in data.pointer_info.items():
            # run this
            self.draw_device_info(widget, cr, None, y, value)
        for key, value in data.touch_info.items():
            self.draw_device_info(widget, cr, key, y, value)
        return False


def main():
    win = EventBoxWindow()
    win.connect("delete-event", Gtk.main_quit)
    win.show_all()
    Gtk.main()


if __name__ == "__main__":
    main()

关于画图可参见Cairo系列

附录

Gdk.EventButton

Fields

NameTypeAccessDescription
axesfloatr/w移动到设备的(x,y)位置, 如果设备为鼠标这个值为None.
buttonintr/w按下或释放的键值 值为1到5。通常1是鼠标左键, 2是中间键, 3是右键.
deviceGdk.Devicer/wthe master device that the event originated from. Use Gdk.Event.get_source_device() to get the slave device.
send_eventintr/wTrue if the event was sent explicitly.
stateGdk.ModifierTyper/wa bit-mask representing the state of the modifier keys (e.g. Control, Shift and Alt) and the pointer buttons. See Gdk.ModifierType.
timeintr/w鼠标点击时的时间
typeGdk.EventTyper/w事件的类别.
windowGdk.Windowr/wthe window which received the event.
xfloatr/w相对于依附的window的x轴位置.
x_rootfloatr/w相对于屏幕的x轴位置.
yfloatr/w相对于依附的window的y轴位置.
y_rootfloatr/w相对于屏幕的y轴位置.





代码下载地址:http://download.csdn.net/detail/a87b01c14/9594728

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sanxiaochengyu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值