Gtk.OffscreenWindow严格意在用于获得不属于正常插件层次结构的一部分部件的快照。由于Gtk.OffscreenWindow是一个顶级小部件则无法获得与它充满窗口的快照,因为你不能装在另一个顶层一个顶级部件。
我们的想法是把一个小部件和手动设置它的状态,将其添加到Gtk.OffscreenWindow,然后检索快照作为cairo.Surface或GdkPixbuf.Pixbuf。
Gtk.OffscreenWindow从Gtk.Window派生只是作为一个实现细节。应用程序不应该使用任何Gtk.Window的特定API来操作这个对象。它应被视为没有父窗口的Gtk.Bin小部件。
当包含屏幕外的小部件重绘,Gtk.OffscreenWindow会发送Gtk.Widget::damage-event信号。
Gtk.OffscreenWindow是Gtk.Window的直接子类
方法修饰词 | 方法名及参数 |
---|---|
static | new () |
get_pixbuf () | |
get_surface () |
Name | Type | Flags | Short Description |
---|
Name | Short Description |
---|
#!/usr/bin/env python3
# Created by xiaosanyu at 16/7/17
# section 042
#
# author: xiaosanyu
# website: yuxiaosan.tk \
# http://blog.csdn.net/a87b01c14
# created: 16/7/17
TITLE = "GtkOffscreenWindow"
DESCRIPTION = """
Gtk.OffscreenWindow is strictly intended to be used for obtaining snapshots of widgets
that are not part of a normal widget hierarchy. Since Gtk.OffscreenWindow is a toplevel widget
you cannot obtain snapshots of a full window with it since you cannot pack
a toplevel widget in another toplevel.
this demo has a bug
"self.offwindow.realize()"
This line of code will generate a bug when it run in gtk-demo.py
please run this demo in the console
"""
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, GObject
import cairo
class OffscreenWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="GtkOffscreenWindow Effects")
self.connect("delete-event", Gtk.main_quit)
self.set_size_request(300, 100)
self.creat_widget("1")
self.creat_offwindow()
def creat_widget(self, name):
hbox = Gtk.HBox(spacing=6)
# 不理解,为什么要在这里使用add,如果这句话往后移,会报错
if name == "1":
self.add(hbox)
backbutton = Gtk.Button()
backbutton.add(Gtk.Image.new_from_icon_name("go-previous", 4))
entry = Gtk.Entry()
applybutton = Gtk.Button.new_with_label("Apply")
applybutton.connect("clicked", self.on_click, name)
hbox.pack_start(backbutton, False, False, 0)
hbox.pack_start(entry, True, True, 0)
hbox.pack_start(applybutton, False, False, 0)
return hbox
@staticmethod
def on_click(widget, name):
print("onclick", name)
def creat_offwindow(self):
self.offwindow = Gtk.OffscreenWindow.new()
self.offwindow.add(self.creat_widget("2"))
self.offwindow.realize()
def do_draw(self, cr):
window = self.get_window()
if Gtk.cairo_should_draw_window(cr, window):
if self.offwindow:
Gtk.render_background(self.get_style_context(), cr, 0, 0, self.get_allocated_width(),
self.get_allocated_height())
self.offwindow.show_all()
surface = self.offwindow.get_surface()
height = self.offwindow.get_size().height
cr.set_source_surface(surface, 0, 0)
cr.paint()
matrix = cairo.Matrix(1.0, 0.0, 0.3, 1.0, 0.0, 0.0)
matrix.scale(1.0, -1.0)
matrix.translate(-10, - 3 * height - 10)
cr.transform(matrix)
cr.set_source_surface(surface, 0, height)
# create linear gradient as mask-pattern to fade out the source
mask = cairo.LinearGradient(0.0, height, 0.0, 2 * height)
mask.add_color_stop_rgba(0.0, 0.0, 0.0, 0.0, 0.0)
mask.add_color_stop_rgba(0.25, 0.0, 0.0, 0.0, 0.01)
mask.add_color_stop_rgba(0.5, 0.0, 0.0, 0.0, 0.25)
mask.add_color_stop_rgba(0.75, 0.0, 0.0, 0.0, 0.5)
mask.add_color_stop_rgba(1.0, 0.0, 0.0, 0.0, 1.0)
cr.mask(mask)
def main():
win = OffscreenWindow()
win.show_all()
Gtk.main()
if __name__ == "__main__":
main()
代码解析:
创建两个一样的HBox,一个添加到Gtk.OffscreenWindow
一个添加到Gtk.Window。
在Gtk.Window的do_draw方法中,获取Gtk.OffscreenWindow的快照
surface = self.offwindow.get_surface()
然后用它画出两个快照,一个正常布局,一个倒立
Gtk.Window是GObject.Object的直接子类
方法修饰词 | 方法名及参数 |
---|---|
static at_pointer () | |
static | constrain_size (geometry, flags, width, height) |
static | new (parent, attributes, attributes_mask) |
static | process_all_updates () |
static | set_debug_updates (setting) |
beep () | |
begin_move_drag (button, root_x, root_y, timestamp) | |
begin_move_drag_for_device (device, button, root_x, root_y, timestamp) | |
begin_paint_rect (rectangle) | |
begin_paint_region (region) | |
begin_resize_drag (edge, button, root_x, root_y, timestamp) | |
begin_resize_drag_for_device (edge, device, button, root_x, root_y, timestamp) | |
cairo_create () | |
configure_finished () | |
coords_from_parent (parent_x, parent_y) | |
coords_to_parent (x, y) | |
create_gl_context () | |
create_similar_image_surface (format, width, height, scale) | |
create_similar_surface (content, width, height) | |
deiconify () | |
destroy () | |
destroy_notify () | |
enable_synchronized_configure () | |
end_paint () | |
ensure_native () | |
flush () | |
focus (timestamp) | |
freeze_toplevel_updates_libgtk_only () | |
freeze_updates () | |
fullscreen () | |
fullscreen_on_monitor (monitor) | |
geometry_changed () | |
get_accept_focus () | |
get_background_pattern () | |
get_children () | |
get_children_with_user_data (user_data) | |
get_clip_region () | |
get_composited () | |
get_cursor () | |
get_decorations () | |
get_device_cursor (device) | |
get_device_events (device) | |
get_device_position (device) | |
get_device_position_double (device) | |
get_display () | |
get_drag_protocol () | |
get_effective_parent () | |
get_effective_toplevel () | |
get_event_compression () | |
get_events () | |
get_focus_on_map () | |
get_frame_clock () | |
get_frame_extents () | |
get_fullscreen_mode () | |
get_geometry () | |
get_group () | |
get_height () | |
get_modal_hint () | |
get_origin () | |
get_parent () | |
get_pass_through () | |
get_pointer () | |
get_position () | |
get_root_coords (x, y) | |
get_root_origin () | |
get_scale_factor () | |
get_screen () | |
get_source_events (source) | |
get_state () | |
get_support_multidevice () | |
get_toplevel () | |
get_type_hint () | |
get_update_area () | |
get_user_data () | |
get_visible_region () | |
get_visual () | |
get_width () | |
get_window_type () | |
has_native () | |
hide () | |
iconify () | |
input_shape_combine_region (shape_region, offset_x, offset_y) | |
invalidate_maybe_recurse (region, child_func, *user_data) | |
invalidate_rect (rect, invalidate_children) | |
invalidate_region (region, invalidate_children) | |
is_destroyed () | |
is_input_only () | |
is_shaped () | |
is_viewable () | |
is_visible () | |
lower () | |
mark_paint_from_clip (cr) | |
maximize () | |
merge_child_input_shapes () | |
merge_child_shapes () | |
move (x, y) | |
move_region (region, dx, dy) | |
move_resize (x, y, width, height) | |
peek_children () | |
process_updates (update_children) | |
raise_ () | |
register_dnd () | |
reparent (new_parent, x, y) | |
resize (width, height) | |
restack (sibling, above) | |
scroll (dx, dy) | |
set_accept_focus (accept_focus) | |
set_background (color) | |
set_background_pattern (pattern) | |
set_background_rgba (rgba) | |
set_child_input_shapes () | |
set_child_shapes () | |
set_composited (composited) | |
set_cursor (cursor) | |
set_decorations (decorations) | |
set_device_cursor (device, cursor) | |
set_device_events (device, event_mask) | |
set_event_compression (event_compression) | |
set_events (event_mask) | |
set_focus_on_map (focus_on_map) | |
set_fullscreen_mode (mode) | |
set_functions (functions) | |
set_geometry_hints (geometry, geom_mask) | |
set_group (leader) | |
set_icon_list (pixbufs) | |
set_icon_name (name) | |
set_keep_above (setting) | |
set_keep_below (setting) | |
set_modal_hint (modal) | |
set_opacity (opacity) | |
set_opaque_region (region) | |
set_override_redirect (override_redirect) | |
set_pass_through (pass_through) | |
set_role (role) | |
set_shadow_width (left, right, top, bottom) | |
set_skip_pager_hint (skips_pager) | |
set_skip_taskbar_hint (skips_taskbar) | |
set_source_events (source, event_mask) | |
set_startup_id (startup_id) | |
set_static_gravities (use_static) | |
set_support_multidevice (support_multidevice) | |
set_title (title) | |
set_transient_for (parent) | |
set_type_hint (hint) | |
set_urgency_hint (urgent) | |
set_user_data (user_data) | |
shape_combine_region (shape_region, offset_x, offset_y) | |
show () | |
show_unraised () | |
show_window_menu (event) | |
stick () | |
thaw_toplevel_updates_libgtk_only () | |
thaw_updates () | |
unfullscreen () | |
unmaximize () | |
unstick () | |
withdraw () |
do_create_surface (width, height) |
do_from_embedder (embedder_x, embedder_y, offscreen_x, offscreen_y) |
do_to_embedder (offscreen_x, offscreen_y, embedder_x, embedder_y) |
Name | Type | Flags | Short Description |
---|---|---|---|
cursor Gdk.Cursor r/w Cursor |
Name | Short Description |
---|---|
create-surface | The ::create-surface signal is emitted when an offscreen window needs its surface (re)created, which happens either when the window is first drawn to, or when the window is being resized. |
from-embedder | The ::from-embedder signal is emitted to translate coordinates in the embedder of an offscreen window to the offscreen window. |
pick-embedded-child | The ::pick-embedded-child signal is emitted to find an embedded child at the given position. |
to-embedder | The ::to-embedder signal is emitted to translate coordinates in an offscreen window to its embedder. |
#!/usr/bin/env python3
# Created by xiaosanyu at 16/7/17
# section 043
#
# author: xiaosanyu
# website: yuxiaosan.tk \
# http://blog.csdn.net/a87b01c14
# created: 16/7/17
TITLE = "Rotated Button"
DESCRIPTION = """
Offscreen windows can be used to transform parts of a widget
hierarchy. Note that the rotated button is fully functional.
"""
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, GObject
from math import *
class RotatedBin(Gtk.Bin):
def __init__(self, *args, **kwargs):
Gtk.Bin.__init__(self, *args, **kwargs)
self.set_has_window(True)
self.angle = 0.0
self.child = None
self.offscreen_window = None
@classmethod
def new(cls, *args, **kwargs):
return GObject.new(cls, *args, **kwargs)
def to_child(self, widget_x, widget_y):
s = sin(self.angle)
c = cos(self.angle)
child_area = self.child.get_allocation()
w = c * child_area.width + s * child_area.height
h = s * child_area.width + c * child_area.height
x = widget_x
y = widget_y
x -= (w - child_area.width) / 2
y -= (h - child_area.height) / 2
x -= child_area.width / 2
y -= child_area.height / 2
xr = x * c + y * s
yr = y * c - x * s
x = xr
y = yr
x += child_area.width / 2
y += child_area.height / 2
return x, y
def to_parent(self, offscreen_x, offscreen_y):
s = sin(self.angle)
c = cos(self.angle)
child_area = self.child.get_allocation()
w = c * child_area.width + s * child_area.height
h = s * child_area.width + c * child_area.height
x = offscreen_x
y = offscreen_y
x -= child_area.width / 2
y -= child_area.height / 2
xr = x * c - y * s
yr = x * s + y * c
x = xr
y = yr
x += child_area.width / 2
y += child_area.height / 2
x -= (w - child_area.width) / 2
y -= (h - child_area.height) / 2
return x, y
def pick_offscreen_child(self, offscreen_window, widget_x, widget_y):
if self.child and self.child.get_visible():
x, y = self.to_child(widget_x, widget_y)
child_area = self.child.get_allocation()
if 0 <= x < child_area.width and 0 <= y < child_area.height:
return self.offscreen_window
def offscreen_window_to_parent(self, window, parent_x, parent_y, offscreen_x, offscreen_y):
parent_x, parent_y = self.to_parent(offscreen_x, offscreen_y)
return parent_x, parent_y
def offscreen_window_from_parent(self, window, parent_x, parent_y, offscreen_x, offscreen_y):
offscreen_x, offscreen_y = self.to_child(parent_x, parent_y)
return offscreen_x, offscreen_y
def do_realize(self):
attributes = Gdk.WindowAttr()
child_requisition = Gtk.Requisition()
self.set_realized(True)
allocation = self.get_allocation()
border_width = self.get_border_width()
attributes.x = allocation.x + border_width
attributes.y = allocation.y + border_width
attributes.width = allocation.width - 2 * border_width
attributes.height = allocation.height - 2 * border_width
attributes.window_type = Gdk.WindowType.CHILD
attributes.event_mask = self.get_events() \
| Gdk.EventMask.EXPOSURE_MASK \
| Gdk.EventMask.POINTER_MOTION_MASK \
| Gdk.EventMask.BUTTON_PRESS_MASK \
| Gdk.EventMask.BUTTON_RELEASE_MASK \
| Gdk.EventMask.SCROLL_MASK \
| Gdk.EventMask.ENTER_NOTIFY_MASK \
| Gdk.EventMask.LEAVE_NOTIFY_MASK
attributes.visual = self.get_visual()
attributes.wclass = Gdk.WindowWindowClass.INPUT_OUTPUT
attributes_mask = Gdk.WindowAttributesType.X | Gdk.WindowAttributesType.Y | Gdk.WindowAttributesType.VISUAL
window = Gdk.Window.new(self.get_parent_window(), attributes, attributes_mask)
self.set_window(window)
window.set_user_data(self)
window.connect("pick-embedded-child", self.pick_offscreen_child)
attributes.window_type = Gdk.WindowType.OFFSCREEN
child_requisition.width = child_requisition.height = 0
if self.child and self.child.get_visible():
child_allocation = self.child.get_allocation()
attributes.width = child_allocation.width
attributes.height = child_allocation.height
self.offscreen_window = Gdk.Window.new(self.get_screen().get_root_window(), attributes,
attributes_mask)
self.offscreen_window.set_user_data(self)
if self.child:
self.child.set_parent_window(self.offscreen_window)
Gdk.offscreen_window_set_embedder(self.offscreen_window, window)
self.offscreen_window.connect("to-embedder", self.offscreen_window_to_parent)
self.offscreen_window.connect("from-embedder", self.offscreen_window_from_parent)
self.offscreen_window.show()
def do_unrealize(self):
self.offscreen_window.set_user_data(None)
self.offscreen_window.destroy()
self.offscreen_window = None
self.child.unrealize()
def do_child_type(self):
if self.child:
return GObject.TYPE_NONE
return Gtk.Widget
def do_add(self, widget):
if not self.child:
if self.offscreen_window:
widget.set_parent_window(self.offscreen_window)
widget.set_parent(self)
self.child = widget
def do_remove(self, widget):
was_visible = widget.get_visible()
if self.child == widget:
widget.unparent()
self.child = None
if was_visible and self.get_visible():
self.queue_resize()
def do_forall(self, include_internals, callback, *callback_data):
if not callback:
return
if self.child:
callback(self.child, *callback_data)
def set_angle(self, angle):
self.angle = angle
self.queue_resize()
self.offscreen_window.geometry_changed()
def size_request(self):
requisition = Gtk.Requisition()
child_requisition = Gtk.Requisition()
child_requisition.width = 0
child_requisition.height = 0
if self.child and self.child.get_visible():
child_requisition = self.child.get_preferred_size()[0]
s = sin(self.angle)
c = cos(self.angle)
w = c * child_requisition.width + s * child_requisition.height
h = s * child_requisition.width + c * child_requisition.height
border_width = self.get_border_width()
requisition.width = border_width * 2 + w
requisition.height = border_width * 2 + h
return requisition
def do_get_preferred_width(self):
requisition = self.size_request()
return requisition.width, requisition.width
def do_get_preferred_height(self):
requisition = self.size_request()
return requisition.height, requisition.height
def do_size_allocate(self, allocation):
self.set_allocation(allocation)
border_width = self.get_border_width()
w = allocation.width - border_width * 2
h = allocation.height - border_width * 2
if self.get_realized():
self.get_window().move_resize(allocation.x + border_width,
allocation.y + border_width,
w, h)
if self.child and self.child.get_visible():
child_allocation = Gdk.Rectangle()
s = sin(self.angle)
c = cos(self.angle)
child_requisition = self.child.get_preferred_size()[0]
child_allocation.x = 0
child_allocation.y = 0
child_allocation.height = child_requisition.height
if c == 0.0:
child_allocation.width = h / s
elif s == 0.0:
child_allocation.width = w / c
else:
child_allocation.width = min((w - s * child_allocation.height) / c,
(h - c * child_allocation.height) / s)
if self.get_realized():
self.offscreen_window.move_resize(
child_allocation.x,
child_allocation.y,
child_allocation.width,
child_allocation.height)
child_allocation.x = child_allocation.y = 0
self.child.size_allocate(child_allocation)
def do_damage_event(self, event):
self.get_window().invalidate_rect(None, False)
return True
def do_draw(self, cr):
window = self.get_window()
if Gtk.cairo_should_draw_window(cr, window):
if self.child and self.child.get_visible():
surface = Gdk.offscreen_window_get_surface(self.offscreen_window)
child_area = self.child.get_allocation()
# transform
s = sin(self.angle)
c = cos(self.angle)
w = c * child_area.width + s * child_area.height
h = s * child_area.width + c * child_area.height
cr.translate((w - child_area.width) / 2, (h - child_area.height) / 2)
cr.translate(child_area.width / 2, child_area.height / 2)
cr.rotate(self.angle)
cr.translate(-child_area.width / 2, -child_area.height / 2)
# clip
cr.rectangle(
0, 0,
self.offscreen_window.get_width(),
self.offscreen_window.get_height())
cr.clip()
# paint
cr.set_source_surface(surface, 0, 0)
cr.paint()
if Gtk.cairo_should_draw_window(cr, self.offscreen_window):
Gtk.render_background(self.get_style_context(), cr, 0, 0, self.offscreen_window.get_width(),
self.offscreen_window.get_height())
if self.child:
self.propagate_draw(self.child, cr)
return False
class OffscreenWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="GdkOffscreenWindow Rotated Button")
# self.set_size_request(200, 150)
self.set_border_width(10)
box = Gtk.VBox(spacing=6)
scale = Gtk.Scale.new_with_range(Gtk.Orientation.HORIZONTAL, 0, GLib.PI_2, 0.01)
scale.set_draw_value(False)
box.pack_start(scale, False, False, 0)
bin = RotatedBin.new()
box.pack_start(bin, True, True, 0)
scale.connect("value-changed", self.scale_changed, bin)
button = Gtk.Button("A Button")
bin.add(button)
self.add(box)
@staticmethod
def scale_changed(scale, bin):
bin.set_angle(scale.get_value())
def main():
win = OffscreenWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
if __name__ == "__main__":
main()
#!/usr/bin/env python3
# Created by xiaosanyu at 16/7/17
# section 044
#
# author: xiaosanyu
# website: yuxiaosan.tk \
# http://blog.csdn.net/a87b01c14
# created: 16/7/17
TITLE = "Effects"
DESCRIPTION = """
Offscreen windows can be used to render elements multiple times to achieve various effects.
"""
import gi
import cairo
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GLib, GObject
from math import *
class MirrorBin(Gtk.Bin):
def __init__(self, *args, **kwargs):
Gtk.Bin.__init__(self, *args, **kwargs)
self.set_has_window(True)
self.child = None
self.offscreen_window = None
@classmethod
def new(cls, *args, **kwargs):
return GObject.new(cls, *args, **kwargs)
@staticmethod
def to_child(widget_x, widget_y):
x = widget_x
y = widget_y
return x, y
@staticmethod
def to_parent(offscreen_x, offscreen_y):
x = offscreen_x
y = offscreen_y
return x, y
def pick_offscreen_child(self, offscreen_window, widget_x, widget_y):
if self.child and self.child.get_visible():
x, y = self.to_child(widget_x, widget_y)
child_area = self.child.get_allocation()
if 0 <= x < child_area.width and 0 <= y < child_area.height:
return self.offscreen_window
def offscreen_window_to_parent(self, window, parent_x, parent_y, offscreen_x, offscreen_y):
parent_x, parent_y = self.to_parent(offscreen_x, offscreen_y)
return parent_x, parent_y
def offscreen_window_from_parent(self, window, parent_x, parent_y, offscreen_x, offscreen_y):
offscreen_x, offscreen_y = self.to_child(parent_x, parent_y)
return offscreen_x, offscreen_y
def do_realize(self):
attributes = Gdk.WindowAttr()
child_requisition = Gtk.Requisition()
self.set_realized(True)
allocation = self.get_allocation()
border_width = self.get_border_width()
attributes.x = allocation.x + border_width
attributes.y = allocation.y + border_width
attributes.width = allocation.width - 2 * border_width
attributes.height = allocation.height - 2 * border_width
attributes.window_type = Gdk.WindowType.CHILD
attributes.event_mask = self.get_events() \
| Gdk.EventMask.EXPOSURE_MASK \
| Gdk.EventMask.POINTER_MOTION_MASK \
| Gdk.EventMask.BUTTON_PRESS_MASK \
| Gdk.EventMask.BUTTON_RELEASE_MASK \
| Gdk.EventMask.SCROLL_MASK \
| Gdk.EventMask.ENTER_NOTIFY_MASK \
| Gdk.EventMask.LEAVE_NOTIFY_MASK
attributes.visual = self.get_visual()
attributes.wclass = Gdk.WindowWindowClass.INPUT_OUTPUT
attributes_mask = Gdk.WindowAttributesType.X | Gdk.WindowAttributesType.Y | Gdk.WindowAttributesType.VISUAL
window = Gdk.Window.new(self.get_parent_window(), attributes, attributes_mask)
self.set_window(window)
window.set_user_data(self)
window.connect("pick-embedded-child", self.pick_offscreen_child)
attributes.window_type = Gdk.WindowType.OFFSCREEN
child_requisition.width = child_requisition.height = 0
if self.child and self.child.get_visible():
child_allocation = self.child.get_allocation()
attributes.width = child_allocation.width
attributes.height = child_allocation.height
self.offscreen_window = Gdk.Window.new(self.get_screen().get_root_window(), attributes,
attributes_mask)
self.offscreen_window.set_user_data(self)
if self.child:
self.child.set_parent_window(self.offscreen_window)
Gdk.offscreen_window_set_embedder(self.offscreen_window, window)
self.offscreen_window.connect("to-embedder", self.offscreen_window_to_parent)
self.offscreen_window.connect("from-embedder", self.offscreen_window_from_parent)
self.offscreen_window.show()
def do_unrealize(self):
self.offscreen_window.set_user_data(None)
self.offscreen_window.destroy()
self.offscreen_window = None
self.child.unrealize()
def do_child_type(self):
if self.child:
return GObject.TYPE_NONE
return Gtk.Widget
def do_add(self, widget):
if not self.child:
if self.offscreen_window:
widget.set_parent_window(self.offscreen_window)
widget.set_parent(self)
self.child = widget
def do_remove(self, widget):
was_visible = widget.get_visible()
if self.child == widget:
widget.unparent()
self.child = None
if was_visible and self.get_visible():
self.queue_resize()
def do_forall(self, include_internals, callback, *callback_data):
if not callback:
return
if self.child:
callback(self.child)
def size_request(self):
requisition = Gtk.Requisition()
child_requisition = Gtk.Requisition()
child_requisition.width = 0
child_requisition.height = 0
if self.child and self.child.get_visible():
child_requisition = self.child.get_preferred_size()[0]
border_width = self.get_border_width()
requisition.width = border_width * 2 + child_requisition.width + 10
requisition.height = border_width * 2 + + child_requisition.height * 2 + 10
return requisition
def do_get_preferred_width(self):
requisition = self.size_request()
return requisition.width, requisition.width
def do_get_preferred_height(self):
requisition = self.size_request()
return requisition.height, requisition.height
def do_size_allocate(self, allocation):
self.set_allocation(allocation)
border_width = self.get_border_width()
w = allocation.width - border_width * 2
h = allocation.height - border_width * 2
if self.get_realized():
self.get_window().move_resize(allocation.x + border_width,
allocation.y + border_width,
w, h)
if self.child and self.child.get_visible():
child_allocation = Gdk.Rectangle()
child_requisition = self.child.get_preferred_size()[0]
child_allocation.x = 0
child_allocation.y = 0
child_allocation.height = child_requisition.height
child_allocation.width = child_requisition.width
if self.get_realized():
self.offscreen_window.move_resize(
child_allocation.x,
child_allocation.y,
child_allocation.width,
child_allocation.height)
self.child.size_allocate(child_allocation)
def do_damage_event(self, event):
self.get_window().invalidate_rect(None, False)
return False
def do_draw(self, cr):
window = self.get_window()
if Gtk.cairo_should_draw_window(cr, window):
if self.child and self.child.get_visible():
surface = Gdk.offscreen_window_get_surface(self.offscreen_window)
height = self.offscreen_window.get_height()
# paint the offscreen child
cr.set_source_surface(surface, 0, 0)
cr.paint()
matrix = cairo.Matrix(1.0, 0.0, 0.3, 1.0, 0.0, 0.0)
matrix.scale(1.0, -1.0)
matrix.translate(-10, - 3 * height - 10)
cr.transform(matrix)
cr.set_source_surface(surface, 0, height)
# create linear gradient as mask-pattern to fade out the source */
mask = cairo.LinearGradient(0.0, height, 0.0, 2 * height)
mask.add_color_stop_rgba(0.0, 0.0, 0.0, 0.0, 0.0)
mask.add_color_stop_rgba(0.25, 0.0, 0.0, 0.0, 0.01)
mask.add_color_stop_rgba(0.5, 0.0, 0.0, 0.0, 0.25)
mask.add_color_stop_rgba(0.75, 0.0, 0.0, 0.0, 0.5)
mask.add_color_stop_rgba(1.0, 0.0, 0.0, 0.0, 1.0)
# paint the reflection */
cr.mask(mask)
elif Gtk.cairo_should_draw_window(cr, self.offscreen_window):
Gtk.render_background(self.get_style_context(), cr, 0, 0, self.offscreen_window.get_width(),
self.offscreen_window.get_height())
if self.child:
self.propagate_draw(self.child, cr)
return False
class OffscreenWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="GdkOffscreenWindow Effects")
# self.set_size_request(300, 150)
self.set_border_width(10)
vbox = Gtk.VBox()
bin = MirrorBin.new()
group = Gtk.SizeGroup.new(Gtk.SizeGroupMode.VERTICAL)
hbox = Gtk.HBox(spacing=6)
backbutton = Gtk.Button()
backbutton.add(Gtk.Image.new_from_icon_name("go-previous", 4))
group.add_widget(backbutton)
entry = Gtk.Entry()
entry.set_text("Hello World")
entry.set_editable(True)
entry.connect("focus-in-event", self.focus_in)
entry.connect("focus_out_event", self.focus_out)
entry.connect("changed", self.changed)
group.add_widget(entry)
applybutton = Gtk.Button.new_with_label("Apply")
group.add_widget(applybutton)
bin.connect("key-press-event",
self.window_key_press_event_cb, entry)
self.add(vbox)
vbox.pack_start(bin, True, True, 0)
bin.add(hbox)
hbox.pack_start(backbutton, False, False, 0)
hbox.pack_start(entry, True, True, 0)
hbox.pack_start(applybutton, False, False, 0)
def focus_in(self, widget, event):
return True
def focus_out(self, widget, event):
return True
def changed(self, widget):
return True
def window_key_press_event_cb(self, window, event, entry):
if entry.is_focus():
entry.emit("insert-at-cursor", event.string)
return False
def main():
win = OffscreenWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
if __name__ == "__main__":
main()
代码下载地址:http://download.csdn.net/detail/a87b01c14/9594728