Gtk.EventBox有自己的窗口。对于那些没有自己窗口的部件捕捉事件是非常有用的
方法修饰词 | 方法名及参数 |
---|---|
static | new () |
get_above_child () | |
get_visible_window () | |
set_above_child (above_child) | |
set_visible_window (visible_window) |
Name | Type | Flags | Short Description |
---|---|---|---|
above-child | bool | r/w/en | Whether the event-trapping window of the eventbox is above the window of the child widget as opposed to below it. |
visible-window | bool | r/w/en | Whether the event box is visible, as opposed to invisible and only used to trap events. |
Name | Short 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 . 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系列
Name | Type | Access | Description |
---|---|---|---|
axes | float | r/w | 移动到设备的(x,y)位置, 如果设备为鼠标这个值为None. |
button | int | r/w | 按下或释放的键值 值为1到5。通常1是鼠标左键, 2是中间键, 3是右键. |
device | Gdk.Device | r/w | the master device that the event originated from. Use Gdk.Event.get_source_device() to get the slave device. |
send_event | int | r/w | True if the event was sent explicitly. |
state | Gdk.ModifierType | r/w | a bit-mask representing the state of the modifier keys (e.g. Control, Shift and Alt) and the pointer buttons. See Gdk.ModifierType. |
time | int | r/w | 鼠标点击时的时间 |
type | Gdk.EventType | r/w | 事件的类别. |
window | Gdk.Window | r/w | the window which received the event. |
x | float | r/w | 相对于依附的window的x轴位置. |
x_root | float | r/w | 相对于屏幕的x轴位置. |
y | float | r/w | 相对于依附的window的y轴位置. |
y_root | float | r/w | 相对于屏幕的y轴位置. |
代码下载地址:http://download.csdn.net/detail/a87b01c14/9594728