用户交互后,如何在Python中从模块中的类传递pixbuf

时间:2018-12-01 20:14:12

标签: python multithreading class callback gtk

我正在使用python模块来处理屏幕截图。如果单独使用,模块本身也可以正常工作。但是,当我将其导入到我的主项目中时,我在等待用户选择要捕获的区域后无法弄清楚如何返回pixbuf。 这是屏幕截图模块:

class CaptureRegion():
def __init__(self):
    self.ThePic = None
    self.drawArea = Gtk.DrawingArea()
    self.drawArea.connect('draw',self.onDraw)
    mBox = Gtk.VBox(False,2) 
    mBox.pack_start(self.drawArea,True,True,2)
    self.MaskWin = Gtk.Window()
    self.MaskWin.set_position(Gtk.WindowPosition.CENTER)
    self.MaskWin.connect("key-press-event", self.KeyPress)
    self.MaskWin.connect("button-press-event", self.ButtonPress)
    self.MaskWin.connect("button-release-event", self.ButtonRelease)
    self.MaskWin.connect("motion-notify-event", self.Motion)
    self.MaskWin.add(mBox)

    self.button_x = 0
    self.button_y = 0
    self.button_down = False
    self.sel_rect = Gdk.Rectangle(-10, -10, 10, 10)

    self.capfull = CaptureScreen() 
    self.fullpixbuf = self.capfull.Go()

def onDraw(self, widget, event):
    print("Draw")
    myGdkWindow = self.MaskWin.get_window()
    self.cr = Gdk.cairo_create(myGdkWindow)

    self.cr.set_operator(cairo.OPERATOR_SOURCE)
    self.cr.set_source_rgb(1,1,1)
    Gdk.cairo_set_source_pixbuf(self.cr, self.fullpixbuf, 5, 5)
    self.cr.paint()

    self.cr.set_line_width(1)
    self.cr.set_source_rgb(0,0,0)


    if self.button_down == True:

        x = self.sel_rect.x
        y = self.sel_rect.y
        w = self.sel_rect.width
        h = self.sel_rect.height

        if w <= 0 or h <= 0:
            return True

        self.cr.rectangle(x,y,w,h)
        self.cr.set_source_rgba(0.2, 0.6, 0.8, 0.35)
        self.cr.set_line_width(2)
        self.cr.stroke()
    return True

def Motion(self,widget,event):
    if self.button_down == False:
        return False
    x1,y1 = self.button_x, self.button_y
    x2,y2 = event.x, event.y
    x = int(min(x1,x2))
    y = int(min(y1,y2))
    w = int(abs(x1-x2))
    h = int(abs(y1-y2))
    old = self.sel_rect
    self.sel_rect.x = x
    self.sel_rect.y = y
    self.sel_rect.width = w
    self.sel_rect.height = h

    win = self.MaskWin.get_window()
    sx, sy, sw, sh = self.MaskWin.get_window().get_geometry()
    self.drawArea.queue_draw_area(sx,sy,sw,sh)

def ButtonPress(self,widget,event):
    if not event.button == 1:
        return False
    print("button down")
    self.debounce = 0
    self.button_x, self.button_y = event.x, event.y
    self.button_down = True

    return True

def ButtonRelease(self,widget,event):
    self.button_down = False
    x = self.sel_rect.x
    y = self.sel_rect.y
    w = self.sel_rect.width
    h = self.sel_rect.height
    self.drawArea.queue_draw_area(x-1, y-1, w-1, h-1)
    if self.debounce == 0:
        self.debounce += 1
        print("Snipping x:%s y:%s w:%s h:%s" %(x,y,w,h))
        self.ThePic = Gdk.pixbuf_get_from_window(self.MaskWin.get_window(), x, y, w, h)
        self.MaskWin.hide()

        #option 2:    to return ThePic here after the selection is made thru a callback to a function in the main class 
        # i.e.
        #self.CallbackInMain(self.ThePic)    (not sure how to callback to the main class, self is wrong maybe?)


def KeyPress(self,widget,event):
    if event.keyval == Gdk.KEY_Escape:
        self.ThePic = None
        return

def WaitThread(self):
    for i in range(1, 50):
            time.sleep(0.1)
            print(i)
    self.done_waiting.set() 


def Go(self):
    self.MaskWin.fullscreen()
    self.MaskWin.show_all()
    self.MaskWin.set_decorated(False)

    #option 1 find a way to wait for the selection to complete like this:  
    #(this code doesnt end, the self.done_waiting.set() call doesnt stop it)
    # self.done_waiting = threading.Event()
    # self.thread = threading.Thread(target=self.WaitThread)
    # self.thread.start()
    # self.done_waiting.wait(1)
    # print("Main thread is done waiting")
    return(self.ThePic)
class CaptureScreen():  
def __init__(self):
    self.ThePic = None

def Go(self):
    screen = Gdk.get_default_root_window()
    x, y, width, height = screen.get_geometry()
    self.fullpixbuf = Gdk.pixbuf_get_from_window(screen, x, y, width, height)
    return(self.fullpixbuf)

我这样调用类:

import Screentshot as Shot
self.captureregion = Shot.CaptureRegion()
pic = self.captureregion.Go()
pic.savev("region.png",'png',(),())

使用CaptureScreen类可以捕获整个屏幕,因此我可以直接从CaptureScreen.Go()函数返回pixbuf。但是,对于CaptureRegion类,我必须等待用户选择区域,并且我不确定在用户选择后如何让CaptureRegion.Go()返回pixbuf。我有两个想法,一个是使用线程等待选择完成,然后从Capture Region.Go()返回pixbuf(代码中的选项1),第二个想法是让屏幕截图类回调函数可以在pixbuf中作为主要函数使用一个arg(代码中的选项2)

我对类不是很熟悉,也从未使用过线程模块。香港专业教育学院搜索并发现了大量信息,我只是无法完全绕开我需要做的事情。

1 个答案:

答案 0 :(得分:0)

当然,既然我终于对此发表了一个问题,我就知道了。我只需要在Go(self,mainself)中添加第二个arg并在主代码中调用一个函数即可。

这就是我所改变的:

def ButtonRelease(self,widget,event):
    self.button_down = False
    x = self.sel_rect.x
    y = self.sel_rect.y
    w = self.sel_rect.width
    h = self.sel_rect.height
    self.drawArea.queue_draw_area(x-1, y-1, w-1, h-1)
    if self.debounce == 0:
        self.debounce += 1
        print("Snipping x:%s y:%s w:%s h:%s" %(x,y,w,h))
        self.ThePic = Gdk.pixbuf_get_from_window(self.MaskWin.get_window(), x, y, w, h)
        self.MaskWin.hide()

        self.GotTheShot = True
        self.mainself.ScreenShotCallBack(self.ThePic)

def Go(self,main):
    self.mainself = main
    self.GotTheShot = False
    self.MaskWin.fullscreen()
    self.MaskWin.show_all()
    self.MaskWin.set_decorated(False)

这是调用和回调:

def ScreenShotRegion(self):
    pic = self.captureregion.Go(self)# self,mainself... self passed by default
    pic.savev("region.png",'png',(),())

def ScreenShotCallBack(self,capturepixbuf):
    self.window.show_all()
    capturepixbuf.savev("region.png",'png',(),())