Вы когда-нибудь задумывались о том, как было бы круто, если бы ваши wxPython приложения делали скриншоты себя? Что же, Андреа Гавана (один из главных разработчиков wxPython) нашёл отличный способ сделать это. А благодаря комбинации из отправленных им инструкций и того, что я прочёл в сторонних источниках, вы узнаете не только как сделать скриншот, но и как отправить его на принтер! Когда мы закончим, у вас будет приложение, которое должно выглядеть вот так:
Приступая к работе
Существует несколько способов создания этого проекта. Вы можете написать непосредственно код, делающий скриншоты, или же приложение, которое запускает этот код в нужный момент. Мы начнём с самого кода. В любом случае, давайте взглянем на него:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
import sys import wx import snapshotPrinter class MyForm(wx.Frame): def __init__(self): wx.Frame.__init__(self, None, title="Screenshot Tutorial") panel = wx.Panel(self) screenshotBtn = wx.Button(panel, label="Take Screenshot") screenshotBtn.Bind(wx.EVT_BUTTON, self.onTakeScreenShot) printBtn = wx.Button(panel, label="Print Screenshot") printBtn.Bind(wx.EVT_BUTTON, self.onPrint) sizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(screenshotBtn, 0, wx.ALL|wx.CENTER, 5) sizer.Add(printBtn, 0, wx.ALL|wx.CENTER, 5) panel.SetSizer(sizer) def onTakeScreenShot(self, event): """ Делает скриншот выбранного фрагмента экрана Основано на методе, предложенном Андреа Гавана """ print('Taking screenshot...') rect = self.GetRect() # Настройка ширины для Linux обнаружено Джоном Торресом # http://article.gmane.org/gmane.comp.python.wxpython/67327 if sys.platform == 'linux2': client_x, client_y = self.ClientToScreen((0, 0)) border_width = client_x - rect.x title_bar_height = client_y - rect.y rect.width += (border_width * 2) rect.height += title_bar_height + border_width # Сделать скриншот всей зоны DC (контекста устройства) dcScreen = wx.ScreenDC() # Создать битмап, в котором сохранится скриншот # Учтите, что битмап должен быть достаточно большим, чтобы в него поместился скриншот # -1 значит использование текущей стандартной глубины цвета bmp = wx.EmptyBitmap(rect.width, rect.height) # Создать в памяти DC, который будет использован непосредственно для скриншота memDC = wx.MemoryDC() # Прикажите DC использовать наш битмап # Все изображения из DC теперь переместится в битмап memDC.SelectObject(bmp) # Blit в данном случае скопируйте сам экран в кэш памяти # и, таким образом, он попадёт в битмап memDC.Blit( 0, # Скопируйте сюда координат Х 0, # Скопируйте сюда координат Y rect.width, # Скопируйте эту ширину rect.height, # Скопируйте эту высоту dcScreen, # Место, откуда нужно скопировать rect.x, # Какой офсет у Х в оригинальном DC (контексте устройства)? rect.y # Какой офсет у Y в оригинальном DC? ) # Select the Bitmap out of the memory DC by selecting a new # uninitialized Bitmap memDC.SelectObject(wx.NullBitmap) img = bmp.ConvertToImage() fileName = "myImage.png" img.SaveFile(fileName, wx.BITMAP_TYPE_PNG) print('...saving as png!') def onPrint(self, event): """ Отправляем скриншот на печать. """ printer = snapshotPrinter.SnapshotPrinter() printer.sendToPrinter() # Запустите программу if __name__ == "__main__": app = wx.App(False) frame = MyForm() frame.Show() app.MainLoop() |
Данный фрагмент кода был рамкой, содержащей две кнопки. Да, он немного скучный, но для примера вполне сгодится. Нас больше всего интересует метод onTakeScreenShot. Как я уже упоминал ранее, он основан на скрипте Андреа Гаваны. Как бы то ни было, я также добавил пару строк, написанных Джон Торресом, которые оптимизируют скрипт для Linux, ведь изначально он был написан для Windows. В комментариях я изложил историю кода, так что уделите ей немного времени, когда появится свободная минутка. Теперь мы научимся тому, как отправить скриншот на печать принтеру.
Простой скрипт для принтера
Создание простого приложения, которое распечатывает скриншот, по сложности примерно идентично созданию приложения для скриншота. Комбинация предыдущего скрипта с этим позволит вам создать простую утилиту для распечатки скриншотов.
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Когда мы закончим, эта утилита будет выглядеть примерно так:
Данный скрипт имеет чёткое название для изображения, так что, если вы хотите сохранить его под другим именем, вам придётся добавить эту возможность самостоятельно. Давайте уделим несколько минут прочтению самого кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 |
import os import wx from wx.html import HtmlEasyPrinting, HtmlWindow class SnapshotPrinter(wx.Frame): def __init__(self, title='Snapshot Printer'): wx.Frame.__init__(self, None, title=title, size=(650,400)) self.panel = wx.Panel(self) self.printer = HtmlEasyPrinting( name='Printing', parentWindow=None) self.html = HtmlWindow(self.panel) self.html.SetRelatedFrame(self, self.GetTitle()) if not os.path.exists('screenshot.htm'): self.createHtml() self.html.LoadPage('screenshot.htm') pageSetupBtn = wx.Button(self.panel, label='Page Setup') printBtn = wx.Button(self.panel, label='Print') cancelBtn = wx.Button(self.panel, label='Cancel') self.Bind(wx.EVT_BUTTON, self.onSetup, pageSetupBtn) self.Bind(wx.EVT_BUTTON, self.onPrint, printBtn) self.Bind(wx.EVT_BUTTON, self.onCancel, cancelBtn) sizer = wx.BoxSizer(wx.VERTICAL) btnSizer = wx.BoxSizer(wx.HORIZONTAL) sizer.Add(self.html, 1, wx.GROW) btnSizer.Add(pageSetupBtn, 0, wx.ALL, 5) btnSizer.Add(printBtn, 0, wx.ALL, 5) btnSizer.Add(cancelBtn, 0, wx.ALL, 5) sizer.Add(btnSizer) self.panel.SetSizer(sizer) self.panel.SetAutoLayout(True) def createHtml(self): ''' Creates an html file in the home directory of the application that contains the information to display the snapshot ''' print('creating html...') html = '''<html>\n<body>\n<center> <img src=myImage.png width=516 height=314> </center>\n</body>\n</html>''' with open('screenshot.htm', 'w') as fobj: fobj.write(html) def onSetup(self, event): self.printer.PageSetup() def onPrint(self, event): self.sendToPrinter() def sendToPrinter(self): self.printer.GetPrintData().SetPaperId(wx.PAPER_LETTER) self.printer.PrintFile(self.html.GetOpenedPage()) def onCancel(self, event): self.Close() if __name__ == '__main__': app = wx.App(False) frame = SnapshotPrinter() frame.Show() app.MainLoop() |
Данный маленький скрипт использует виджет HtmlWindow и метод HtmlEasyPrinting для отправки изображения на принтер. Другими словами, вы можете создать действительно простой HTML код (узнайте больше о методе createHtml), а затем применить HtmlWindow, чтобы отобразить его. Затем используйте HtmlEasyPrinting, чтобы отправить его на принтер. После чего отобразиться диалог, позволяющий выбрать на какой именно принтер отправить изображение.
Подведем итоги
Возможность сохранения скриншота вашего приложения может оказаться крайне полезной во время дебагинга. Например, если вы пишите автоматический тестер для вашего программного обеспечения, вы сможете сохранить скриншот того, как ваше приложение перестало отвечать или выдало предупреждение. Это поможет выяснить причину данного инцидента. Я надеюсь, что данная статья была вам полезна. Мне этот метод помогал не один раз.
Продолжение
Следующий урок №3: Как вставить иконку в строку заголовка
Предыдущий урок №1: Динамическое добавление и удаление виджетов
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»