Делайте скриншоты с фиксированными интервалами с помощью Python, используя threading.Таймер

#python #timer #gtk #pygtk #screenshot

#python #таймер #gtk #pygtk #скриншот

Вопрос:

Я пишу простое графическое приложение с PyGTK для создания скриншотов рабочего стола с фиксированными интервалами. Для планирования снимков я использую threading.Класс Timer и для создания снимков я использую os.системные вызовы scrot.

Когда я нажимаю кнопку начать делать скриншоты, вызывается метод GlapseMain.startscreenshot. Когда я нажимаю кнопку прекратить делать скриншоты, вызывается метод GlapseMain.stopscreenshot.

Дело в том, что во время работы приложения GTK скриншот не делается, хотя должен. Когда я нажимаю кнопку закрытия, он начинает делать скриншоты idefinitely.

Вот мой код:

 #!/usr/bin/env python
# -*- coding: utf8  -*-

import threading
import os

class GlapseMain:

def __init__(self):
    self.outputDir = os.getenv('HOME')
    self.quality = 80
    self.interval = 10
    self.numDigits = 15
    self.currentShot = 0

def startScreenshots(self, output, quality, interval):
    print 'Starting taking screenshots...'
    print 'Output folder: '   str(output)
    print 'Quality: '   str(quality)
    print 'Interval: '   str(interval)

    # Update attributes
    self.outputDir = output
    self.quality = quality
    self.interval = interval
    self.currentShot = 0

    # Create timer (first screenshot scheduled 1s ahead)
    self.timer = threading.Timer(1.0, self._takeScreenshot)
    self.timer.start()


def stopScreenshots(self):
    print 'Stopped taking screenshots.'

    self.timer.cancel()


def _takeScreenshot(self):
    # Build scrot command
    fileNumber = str(self.currentShot)
    fileNumber = fileNumber.zfill(self.numDigits - len(fileNumber))
    fileName = 'scr-'   fileNumber   '.jpg'

    command = 'scrot -q '   str(self.quality)   ' '   self.outputDir   os.sep   fileName

    print 'Taking screenshot: '   command   '...'

    os.system(command)

    # Schedule next screenshot
    self.currentShot = self.currentShot   1
    self.timer = threading.Timer(self.interval, self._takeScreenshot)
    self.timer.start()
  

Мой вывод выглядит примерно так:

 Starting taking screenshots...
Output folder: /home/david/glapse-screens
Quality: 80.0
Interval: 2.0
Stopped taking screenshots.
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000000.jpg...
Closing gLapse...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000001.jpg...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000002.jpg...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000003.jpg...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000004.jpg...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000005.jpg...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000006.jpg...
Taking screenshot: scrot -q 80.0 /home/david/glapse-screens/scr-00000000000007.jpg...
  

Надеюсь, вы могли бы мне помочь, большое вам спасибо.

Редактировать:

Я изменил подход, и теперь я использую потоки:

 def startScreenshots(self, output, quality, interval):
    print 'Starting taking screenshots...'
    print 'Output folder: '   str(output)
    print 'Quality: '   str(quality)
    print 'Interval: '   str(interval)

    # Update attributes
    self.outputDir = output
    self.quality = quality
    self.interval = interval
    self.currentShot = 0

    # Start a thread to take screenshots
    self.done = False
    self.thread = threading.Thread(target=self._takeScreenshot)
    self.thread.start()

def stopScreenshots(self):
    print 'Stopped taking screenshots.'
    self.done = True
    self.thread.join()


def _takeScreenshot(self):
    # Run until we're done
    while not self.done:
        # Build scrot command
        fileNumber = str(self.currentShot)
        fileNumber = fileNumber.zfill(self.numDigits - len(fileNumber))
        fileName = 'scr-'   fileNumber   '.jpg'

        command = 'scrot -q '   str(self.quality)   ' '   self.outputDir   os.sep   fileName

        print 'Taking screenshot: '   command   '...'

        os.system(command)

        # Schedule next screenshot
        print 'Scheduling next screenshot...'
        self.currentShot = self.currentShot   1
        time.sleep(self.interval)
  

Он выводит сообщение, но не выполняет инструкцию os.system, пока я не нажму кнопку stop.

Комментарии:

1. Почему вы использовали модуль потоковой обработки python вместо GLib.timeout_add метода и асинхронных GFile операций? Это должно сработать в большинстве случаев.

Ответ №1:

Для ответа:

Вам также необходимо вызвать

 gtk.gdk.threads_init()
  

перед вызовом gtk.main(), если вы хотите потоки с gtk


Вместо этого пусть _takeScreenshot() запускает цикл while и не запускает новый поток для следующего снимка экрана. У вас уже есть рабочий поток для этого, например

Вам также нужен поток вместо таймера

 def _takeScreenshot(self):
    while self.notDone:
         # take screen shot
         # ..
         time.sleep(self.interval)
  

Затем в вашем методе отмены сделайте что-то вроде:

 def stopScreenshots(self):
    self.notDone = False
    self.timer.join() # wait for thread to finish 
  

Комментарии:

1. Этот цикл while не просто заморозил бы графический интерфейс?

2. Нет, он выполняется в вашем потоке, а не в основном потоке приложения. В этом смысл потоков 🙂

3. Обратите внимание, что я предполагаю, что вы используете потоки, а не таймер, поскольку таймер заморозит графический интерфейс.

4. Я отредактировал свое сообщение с использованием поточного подхода, но оно печатает только сообщение о создании скриншота. Снимок не выполняется, пока я не нажму «Отмена», а затем, ну, больше скриншоты не делаются.

5. Отредактировал мой ответ. Вам также понадобится вызов gtk.threads_init() перед gtk.main().