1. 程式人生 > 程式設計 >使用Python來做一個螢幕錄製工具的操作程式碼

使用Python來做一個螢幕錄製工具的操作程式碼

一、寫在前面

作為一名測試,有時候經常會遇到需要錄屏記錄自己操作,方便後續開發同學定位。以前都是用ScreenToGif來錄屏製作成動態圖,偶爾的機會看到python也能實現。那就趕緊學習下。

二、效果展示

三、知識串講

這次要講的東西可能比較多了,涉及到pyqt5 GUI軟體的製作、QThread多執行緒的使用、Sikuli庫的圖形操作、win32庫的模擬鍵盤操作、cv2庫的寫視訊檔案等。下面我們一點點來蠶食我這次寫的程式碼。

1、GUI介面製作

這次我用的是現成的Pyqt5介面佈局類,QVBoxLayout。這個類可以快速協助我完成按鈕的垂直分佈,而且按鈕新增也更方便。

button1 = QPushButton("自定義錄屏")
layout.addWidget(button1)

兩行程式碼就完成了按鈕的命名和新增。我之前玩qt時,用的都是qt的UI介面,對應生成的元件程式碼也比較複雜。因此,在開發一些少量按鈕、簡單佈局時可以用QVBoxLayout類。如果喜歡水平佈局,可以用QHBoxLayout類,使用方法是一樣的。

另外,在按鈕點選關聯的功能函式,即work()方法時,如果想帶引數,可以通過lambda匿名函式來實現。這 也是個小技巧。

# 不帶引數
button1.clicked.connect(self.work)
# 帶引數
button1.clicked.connect(lambda: self.work(1))

2、QThread類的多執行緒使用

因為錄屏工具有開始和停止兩個功能,一開始時我用的是單執行緒,發現工具就會卡死。查了一些資料,發現針對這種情況,應該要使用多執行緒來實現,而QT庫中本身就有多執行緒類--QThread。

使用方法是通過繼承QThread類,重寫run方法來實現的。

(但是其實這種使用方法,QT大神們是不贊成這樣使用的,我會在第2篇文章中再簡單說明更好的多執行緒使用方法)

這 裡要注意,work()函式必須是Ui_Mainwindow類方法,因為如果不是類方法,會在執行GUI時導致生命週期直接結束,導致錄屏程式碼沒見執行就報錯退出。

class WorkThread(QThread):
  def __init__(self,n):
    super(WorkThread,self).__init__()
    self.n = n

  def run(self):
    XXXXX

3、sikuli庫圖形識別

由於這個庫的使用方法和介紹,我在之前的部落格裡已經提過 了。因此只簡單地呈現下程式碼。這段程式碼主要是為了自定義錄屏時,可以獲取選擇範圍的座標值,並傳值給recording函式,從而完成自定義錄屏功能。

def SelectRegion():
  jvmPath = jpype.get_default_jvm_path()
  jpype.startJVM(jvmPath,'-ea','-Djava.class.path=F:\\sikuli\\1\\sikulixapi.jar') #載入jar包路徑
  Screen = jpype.JClass('org.sikuli.script.Screen')
  myscreen = Screen()
  region = myscreen.selectRegion() # 自定義獲取螢幕範圍
  return region

4、win32庫模擬鍵盤操作

其實這個庫不用也是可以的,我為什麼要用呢?主要是為了方便使用者在進行錄屏時,能自動將工具介面縮小。一切為了使用者嘛!

以下這段程式碼 是為了縮小工具視窗,其中91表示左win鍵,40表示方向向下鍵。****即win+向下鍵是可以實現視窗縮小功能的。****keybd_event(91,0)表示按下win鍵,

keybd_event(91,win32con.KEYEVENTF_KEYUP,0)則是鬆開win鍵。

另外,這裡為什麼要加 上sleep(0.5)?這是因為在按下win鍵後要延遲按方向鍵,不然是 不起作用的。

def Minimize_Window():
  win32api.keybd_event(91,0)
  time.sleep(0.5)
  win32api.keybd_event(40,0)
  time.sleep(0.5)
  win32api.keybd_event(91,0)
  win32api.keybd_event(40,0)

5、錄屏主程式碼

這段程式碼其實網上已經有很多類似的程式碼,並且我已經加了註釋,相信大家應該能理解。這裡我想註明下的是:如何停止錄屏。

如果大家有去 網上查如何停止錄屏的方法,很多人都會寫以下程式碼:

if cv2.waitKey(1) & 0xFF == ord('q'):
  break

然後告訴你,按q鍵就會停止錄屏。但是你會發現,實際情況根本停止不了,為什麼呢?因為還 有一句螢幕顯示的程式碼:

cv2.imshow('imm',img_bgr)
if cv2.waitKey(1) & 0xFF == ord('q'):
  break

如果你不親自執行一次,你以為會萬事大吉,但你錯了。這樣寫,會導致你的電腦螢幕被每一幀畫面給撐暴!因為用的while True,因此每一幀畫面都會顯示,即1S 25幀畫面會不停地顯示在你桌面上!

因此,綜上的問題,我採用了一種取巧的方法:在錄屏開始時生成一個標記檔案,通過標記檔案是否被刪除來判斷是否要停止錄屏功能。

四、示例程式碼

1、工具GUI介面程式碼:

# coding=utf-8
# @Software : PyCharm
#Python學習群827513319


import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
import time
import win32api,win32con
from recording import *

class WorkThread(QThread):
  def __init__(self,self).__init__()
    self.n = n

  def run(self):
    if self.n == 1:
      Minimize_Window()
      Recording(1)
    elif self.n == 2:
      Minimize_Window()
      Recording(2)
    else:
      StopRecording()

def Minimize_Window():
  win32api.keybd_event(91,0)

class Ui_Mainwindow():
  def setupUi(self,top):
    # 垂直佈局類QVBoxLayout
    layout = QVBoxLayout(top)
    # 新增錄屏相關按鈕
    button1 = QPushButton("自定義錄屏")
    layout.addWidget(button1)
    button2 = QPushButton("全屏錄屏")
    layout.addWidget(button2)
    button3 = QPushButton("停止錄屏")
    layout.addWidget(button3)
    self.text = QPlainTextEdit('歡迎使用!')
    layout.addWidget(self.text)
    button1.clicked.connect(lambda: self.work(1))
    button2.clicked.connect(lambda: self.work(2))
    button3.clicked.connect(lambda: self.work(3))

  def work(self,n):
    if n == 1 :
      print('已選擇自定義錄屏:')
      self.text.setPlainText('正在錄屏中,請等待……')
    elif n == 2 :
      print('已選擇全屏錄屏:')
      self.text.setPlainText('正在錄屏中,請等待……')
    else:
      print('已選擇結束錄屏:')
      self.text.setPlainText('錄屏結束!(點選關閉按鈕,可退出程式!)')
    self.workThread = WorkThread(n)
    self.workThread.start()

if __name__ == "__main__":
  app = QApplication(sys.argv)
  top = QWidget()
  top.setWindowTitle('錄屏小工具')
  top.resize(300,170)
  ui = Ui_Mainwindow()
  ui.setupUi(top)
  top.show()
  sys.exit(app.exec_())# coding=utf-8

2、錄屏函式

# coding=utf-8
# @Software : PyCharm

from PIL import ImageGrab
import numpy as np
import cv2
import os
import jpype

def Recording(tag=1):
  # 錄屏開始時建立test.txt,作為結束錄屏的條件
  #Python學習群827513319
  if not os.path.exists('test.txt'):
    f = open('test.txt','w')
    f.close()
  # 根據tag值判斷自定義錄屏或全錄屏
  if tag == 1:
    r = SelectRegion()
    record_region = (r.x,r.y,r.w + r.x,r.h + r.y) # 自定義錄屏的範圍(左上座標、右下座標)
  elif tag == 2:
    record_region = None
  image = ImageGrab.grab(record_region) # 獲取指定範圍的螢幕物件
  width,height = image.size
  fourcc = cv2.VideoWriter_fourcc(*'XVID')
  video = cv2.VideoWriter('test.avi',fourcc,25,(width,height)) # 預設視訊為25幀
  while True:
    captureImage = ImageGrab.grab(record_region) # 抓取指定範圍的螢幕
    frame = cv2.cvtColor(np.array(captureImage),cv2.COLOR_RGB2BGR)
    video.write(frame) # 將每幀畫面寫視訊檔案
    # 停止錄屏的條件:test.txt被刪除
    if not os.path.exists('test.txt'):
      break
  video.release()
  cv2.destroyAllWindows()

def SelectRegion():
  jvmPath = jpype.get_default_jvm_path()
  jpype.startJVM(jvmPath,'-Djava.class.path=F:\\sikuli\\1\\sikulixapi.jar') #載入jar包路徑
  Screen = jpype.JClass('org.sikuli.script.Screen')
  myscreen = Screen()
  region = myscreen.selectRegion() # 自定義獲取螢幕範圍
  return region

def StopRecording():
  os.remove('test.txt') #停止錄屏的觸發條件

if __name__ == "__main__":
  Recording()

五、總結

至此,基本實現了錄屏小工具的程式碼開發。但是如果你是對程式碼中的相關庫不熟悉,或者都沒下載相關的庫,那我相信你還會遇到很多坑。因此,為了方便一些小夥伴能快速把程式碼跑起來,我將在下一篇文章中講講我在開發時遇到的一些坑,方便大家能避免這些問題。好了,今天就先到這裡!Bye!

以上所述是小編給大家介紹的使用Python來做一個螢幕錄製工具的操作程式碼,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回覆大家的。在此也非常感謝大家對我們網站的支援!
如果你覺得本文對你有幫助,歡迎轉載,煩請註明出處,謝謝!