#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().