【问题标题】:Windows updating breaks drawing on them with Python XlibWindows 更新中断了使用 Python Xlib 绘制它们
【发布时间】:2018-03-25 11:54:39
【问题描述】:

我正在尝试为自己编写一个有趣的项目,这是一个用 Python 编写的截图工具。我遇到了其中一部分的问题,即我想在屏幕上绘制一个矩形,获取坐标,然后对该区域进行截图。 I have this working for the most part, but when the window underneath the selection updates, it breaks the drawing of the rectangle.

这是一个显示问题的视频:https://gfycat.com/EmotionalThankfulFlycatcher

我已经尝试阅读 Xlib 文档,看看是否有一种方法可以让我轻松处理这个问题,但找不到任何东西。我可以尝试的另一种选择是截取整个屏幕的屏幕截图,然后从中进行选择,而不是截取实时桌面的某个区域。

有没有我可以处理这个问题,而无需截取整个桌面并裁剪它?

import sys
from Xlib import X, display, Xutil, xobject, Xcursorfont


class xselect:
    def __init__(self):
        # X display
        self.d = display.Display()

        # Screen
        self.screen = self.d.screen()

        # Draw on the root window (desktop surface)
        self.window = self.screen.root

    def select_region(self):

        # Set cursor to crosshair
        font = self.d.open_font('cursor')
        cursor = font.create_glyph_cursor(font, Xcursorfont.crosshair,
                                          Xcursorfont.crosshair+1,
                                          (65535, 65535, 65535), (0, 0, 0))

        self.window.grab_pointer(1, X.PointerMotionMask|X.ButtonReleaseMask|X.ButtonPressMask,
                X.GrabModeAsync, X.GrabModeAsync, X.NONE, cursor, X.CurrentTime)

        colormap = self.screen.default_colormap
        color = colormap.alloc_color(0, 0, 0)
        # Xor it because we'll draw with X.GXxor function
        xor_color = color.pixel ^ 0xffffff

        self.gc = self.window.create_gc(
            line_width = 1,
            line_style = X.LineSolid,
            fill_style = X.FillOpaqueStippled,
            fill_rule  = X.WindingRule,
            cap_style  = X.CapButt,
            join_style = X.JoinMiter,
            foreground = xor_color,
            background = self.screen.black_pixel,
            function = X.GXxor,
            graphics_exposures = False,
            subwindow_mode = X.IncludeInferiors,
        )

        done    = False
        started = False
        start   = dict(x=0, y=0)
        end     = dict(x=0, y=0)
        last    = None

        while not done:
            e = self.d.next_event()

            # Window has been destroyed, quit
            if e.type == X.DestroyNotify:
                sys.exit(0)

            # Mouse button press
            elif e.type == X.ButtonPress:
                # Left mouse button?
                if e.detail == 1:
                    start = dict(x=e.root_x, y=e.root_y)
                    started = True

                # Right mouse button?
                elif e.detail == 3:
                    sys.exit(0)

            # Mouse button release
            elif e.type == X.ButtonRelease:
                end = dict(x=e.root_x, y=e.root_y)
                if last:
                    self.draw_rectangle(start, last)
                done = True
                pass

            # Mouse movement
            elif e.type == X.MotionNotify and started:
                if last:
                    self.draw_rectangle(start, last)
                    last = None

                last = dict(x=e.root_x, y=e.root_y)
                self.draw_rectangle(start, last)
                pass

            # Keyboard key
            elif e.type == X.KeyPress:
                sys.exit(0)

            elif e.type == X.EnterNotify:
                print(' EnterNotify')

        self.d.ungrab_pointer(0)
        self.d.flush()

        coords = self.get_coords(start, end)
        if coords['width'] <= 1 or coords['height'] <= 1:
            sys.exit(0)
        else:
            return coords

    def get_coords(self, start, end):
        safe_start = dict(x=0, y=0)
        safe_end = dict(x=0, y=0)

        if start['x'] > end['x']:
            safe_start['x'] = end['x']
            safe_end['x']   = start['x']
        else:
            safe_start['x'] = start['x']
            safe_end['x']   = end['x']

        if start['y'] > end['y']:
            safe_start['y'] = end['y']
            safe_end['y']   = start['y']
        else:
            safe_start['y'] = start['y']
            safe_end['y']   = end['y']

        return {
            'start': {
                'x': safe_start['x'],
                'y': safe_start['y'],
            },
            'end': {
                'x': safe_end['x'],
                'y': safe_end['y'],
            },
            'width' : safe_end['x'] - safe_start['x'],
            'height': safe_end['y'] - safe_start['y'],
        }

    def draw_rectangle(self, start, end):
        coords = self.get_coords(start, end)
        self.window.rectangle(
            self.gc,
            coords['start']['x'],
            coords['start']['y'],
            coords['end']['x'] - coords['start']['x'],
            coords['end']['y'] - coords['start']['y']
        )

【问题讨论】:

    标签: python screenshot x11 xlib


    【解决方案1】:

    我自己还是 X11 的新手,但是 stackoverflow 上的 X11 标签几乎已经死了,所以我还是会尝试回答。

    如需截图,请查看this。您想使用 XGetImage,它允许您指定所需的矩形。

    现在要绘制矩形,据我所知,在根窗口上绘制可能非常有问题。您可以改为创建一个具有透明背景的全屏窗口。例如,这还允许您为矩形周围的区域赋予更深的色调。

    【讨论】:

      猜你喜欢
      • 2020-11-06
      • 1970-01-01
      • 1970-01-01
      • 2012-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多