preface
Some time ago, I wrote several articles with PyQt5 about Python made a cool music player,Custom desktop animation Pendant,Automatic license plate recognition system . Today, let's continue to share a practical case and take you to develop a custom dynamic desktop wallpaper with PyQt5 of Python. It's fun and interesting!
First, let's take a look at the final custom dynamic wallpaper effect:
Next, let's introduce the production process of this custom dynamic desktop.
1, Core function design
In general, we need to turn our favorite video into a dynamic desktop. The knowledge points mainly include video extraction and analysis, video rotation, PyQt5 form setting, desktop handle acquisition, custom dynamic desktop wallpaper implementation, etc.
The disassembly requirements can be roughly sorted out. We need to complete them in the following steps:
- UI layout design, confirm the function design of dynamic wallpaper
- Load the video, preview and read the video, save the video path, etc
- The dynamic wallpaper function realizes the application, obtains the desktop handle, rotates and loads the video
- Close dynamic wallpaper, online wallpaper resource acquisition, etc
2, Implementation steps
Some fans reported that they wanted to follow the article and knock the code, but it was not worth the specific modules and package files. Later, I will release all the modules used first.
import os import sys from subprocess import call from threading import Thread from time import sleep import cv2 from PyQt5 import QtCore, QtWidgets from PyQt5.QtCore import Qt, QTimer from PyQt5.QtGui import QImage, QPixmap, QIcon from PyQt5.QtWidgets import QGridLayout, QPushButton, QMainWindow, QFileDialog, QLabel, QSystemTrayIcon, \ QAction, QMenu, QMessageBox from os import path as pathq
1. UI layout design
According to the functions required by the dynamic wallpaper, first carry out the UI layout design. We still use it this time pyqt5. It mainly includes loading and reading local video, video loading preview, dynamic wallpaper application, dynamic wallpaper closing, etc. The core design code is as follows:
# author: CSDN dragon juvenile def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(505, 615) MainWindow.setToolButtonStyle(QtCore.Qt.ToolButtonIconOnly) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.pushButton = QtWidgets.QPushButton(self.centralwidget) self.pushButton.setGeometry(QtCore.QRect(22, 10, 89, 31)) self.pushButton.setObjectName("pushButton") self.pushButton.clicked.connect(self.openmp4) self.pushButton.setStyleSheet( '''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:yellow;}''') self.groupBox = QtWidgets.QGroupBox(self.centralwidget) self.groupBox.setGeometry(QtCore.QRect(22, 50, 452, 351)) self.groupBox.setObjectName("groupBox") self.widget = QtWidgets.QWidget(self.groupBox) self.widget.setGeometry(QtCore.QRect(11, 20, 430, 291)) self.widget.setObjectName("widget") self.gridLayout_3 = QtWidgets.QGridLayout(self.widget) self.gridLayout_3.setObjectName("gridLayout_3") self.label = QLabel(self) self.label.resize(400, 300) self.label.setText("Waiting for video...") self.gridLayout_3.addWidget(self.label) self.close_widget = QtWidgets.QWidget(self.centralwidget) self.close_widget.setGeometry(QtCore.QRect(420, 0, 93, 41)) self.close_widget.setObjectName("close_widget") self.close_layout = QGridLayout() # Create a grid layout layer for the left part self.close_widget.setLayout(self.close_layout) # Set the layout of the left part as a grid self.left_close = QPushButton("") # close button self.left_close.clicked.connect(self.close) self.left_visit = QPushButton("") # Blank button #self.left_visit.clicked.connect(MainWindow.big) self.left_mini = QPushButton("") # Minimize button self.left_mini.clicked.connect(MainWindow.mini) self.close_layout.addWidget(self.left_mini, 0, 0, 1, 1) self.close_layout.addWidget(self.left_close, 0, 2, 1, 1) self.close_layout.addWidget(self.left_visit, 0, 1, 1, 1) self.left_close.setFixedSize(15, 15) # Sets the size of the close button self.left_visit.setFixedSize(15, 15) # Set button size self.left_mini.setFixedSize(15, 15) # Set minimize button size self.left_close.setStyleSheet( '''QPushButton{background:#F76677;border-radius:5px;}QPushButton:hover{background:red;}''') self.left_visit.setStyleSheet( '''QPushButton{background:#F7D674;border-radius:5px;}QPushButton:hover{background:yellow;}''') self.left_mini.setStyleSheet( '''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''') self.horizontalLayout = QtWidgets.QHBoxLayout(self.close_widget) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.pushButton_2 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_2.setGeometry(QtCore.QRect(77, 440, 133, 41)) self.pushButton_2.setObjectName("pushButton_2") self.pushButton_2.clicked.connect(self.play) self.pushButton_2.setStyleSheet( '''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''') self.pushButton_3 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_3.setGeometry(QtCore.QRect(308, 440, 111, 41)) self.pushButton_3.setObjectName("pushButton_3") self.pushButton_3.clicked.connect(self.close_wall) self.pushButton_3.setStyleSheet( '''QPushButton{background:#F76677;border-radius:5px;}QPushButton:hover{background:red;}''') self.pushButton_4 = QtWidgets.QPushButton(self.centralwidget) self.pushButton_4.setGeometry(QtCore.QRect(187, 540, 133, 21)) self.pushButton_4.setObjectName("pushButton_4") self.pushButton_4.clicked.connect(self.openurl) self.pushButton_4.setStyleSheet( '''QPushButton{background:#222225;color:white;border-radius:5px;}QPushButton:hover{background:#222225;color:skyblue}''') MainWindow.setCentralWidget(self.centralwidget) self.menubar = QtWidgets.QMenuBar(MainWindow) self.menubar.setGeometry(QtCore.QRect(0, 0, 505, 23)) self.menubar.setObjectName("menubar") MainWindow.setMenuBar(self.menubar) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) QtCore.QMetaObject.connectSlotsByName(MainWindow) self.groupBox.setStyleSheet(''' color:white ''') MainWindow.setWindowOpacity(0.95) # Set window transparency MainWindow.setAttribute(Qt.WA_TranslucentBackground) MainWindow.setWindowFlag(Qt.FramelessWindowHint) # Hide border # author: Dragon junior def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) self.pushButton.setText(_translate("MainWindow", "Select from local")) self.groupBox.setTitle(_translate("MainWindow", "preview")) self.pushButton_2.setText(_translate("MainWindow", "application")) self.pushButton_3.setText(_translate("MainWindow", "Close wallpaper")) self.pushButton_4.setText(_translate("MainWindow", "Online resources"))
The UI implementation effect is as follows:
After the UI layout design is completed, let's start the implementation of video reading, loading and preview functions.
2. Video loading Preview
Next, we can read the video locally according to our favorite video, and play the video preview. Here is a video demonstration. Bloggers still use the previous one Ziyan little sister's dance video Give a demonstration.
Read video:
To read video, we can open the file dialog box, select video resources, and start a sub thread to start and stop video playback. The core code is as follows:
# author: CSDN dragon juvenile def openmp4(self): try: global path path, filetype = QFileDialog.getOpenFileName(None, "Select file", '.', "video file (*.AVI;*.mov;*.rmvb;*.rm;*.FLV;*.mp4;*.3GP)") # ;;All Files (*) if path == "": # No files selected return self.slotStart() t = Thread(target=self.Stop) t.start() # Start the thread, that is, let the thread start execution except Exception as e: print (e)
Video stream reading and playing:
Next, we need to read, load and display the video file by frame, and realize the animation effect through the timer. The core code is as follows:
# author: CSDN dragon juvenile def slotStart(self): videoName = path if videoName != "": # '' canceled for user self.cap = cv2.VideoCapture(videoName) self.timer_camera.start(50) self.timer_camera.timeout.connect(self.openFrame)
# author: CSDN dragon juvenile def openFrame(self): if (self.cap.isOpened()): ret, self.frame = self.cap.read() if ret: frame = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB) if self.detectFlag == True: # Detection code self frame self.label_num.setText("There are " + str(5) + " people.") height, width, bytesPerComponent = frame.shape bytesPerLine = bytesPerComponent * width q_image = QImage(frame.data, width, height, bytesPerLine, QImage.Format_RGB888).scaled(self.label.width(), self.label.height()) self.label.setPixmap(QPixmap.fromImage(q_image)) else: self.cap.release() self.timer_camera.stop() # Stop timer
So far, we can read and load the video and preview the video. The effects are as follows:
3. Realization of dynamic wallpaper function
To realize desktop wallpaper replacement, we first need to obtain the desktop handle, find the desktop form, overwrite the desktop form, call the loaded video stream, and play the dynamic wallpaper.
Get desktop handle:
# author: CSDN dragon juvenile def pretreatmentHandle(): hwnd = win32gui.FindWindow("Progman", "Program Manager") win32gui.SendMessageTimeout(hwnd, 0x052C, 0, None, 0, 0x03E8) hwnd_WorkW = None while 1: hwnd_WorkW = win32gui.FindWindowEx(None, hwnd_WorkW, "WorkerW", None) if not hwnd_WorkW: continue hView = win32gui.FindWindowEx(hwnd_WorkW, None, "SHELLDLL_DefView", None) # print('hwmd_hView: ', hView) if not hView: continue h = win32gui.FindWindowEx(None, hwnd_WorkW, "WorkerW", None) while h: win32gui.SendMessage(h, 0x0010, 0, 0) # WM_CLOSE h = win32gui.FindWindowEx(None, hwnd_WorkW, "WorkerW", None) break return hwnd
Desktop overwrite:
We can create a class to inherit the form and load, read and play the video stream. The core code is as follows:
# author: CSDN dragon juvenile class MyMainWindow(QMainWindow, Ui_MainWindow): def __init__(self, parent=None): super(MyMainWindow, self).__init__(parent) self.ui = Ui_MainWindow() self.ui.setupUi(self) self.player = QMediaPlayer() self.player.setNotifyInterval(10000) self.player.setVideoOutput(self.ui.videowidget) self.player.setMuted(bool(1 - self.player.isMuted())) self.setWindowFlags(Qt.FramelessWindowHint) self.setupUi(self) self.go() # author: CSDN dragon juvenile def go(self): self.ui.videowidget.setFullScreen(True) with open("./filename.txt", 'r', encoding='utf-8') as f: file_name = f.read() if file_name =='': file_name = 'lkf.mp4' print (file_name) if not os.path.exists(file_name): sys.exit() media = QMediaContent(QUrl(file_name)) self.player.setMedia(media) self.mplayList = QMediaPlaylist() self.mplayList.addMedia(QMediaContent(QUrl.fromLocalFile(file_name))) self.player.setPlaylist(self.mplayList) self.mplayList.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop) win_hwnd = int(self.winId()) video_h = int(self.ui.videowidget.winId()) win32gui.SetParent(win_hwnd, h) win32gui.SetParent(video_h, h) win32gui.SetParent(video_h, win_hwnd) self.player.play()
Here, we directly package the above py file into an EXE file. Next, we bind events on the "application" control and directly call exe for execution to realize the application function of dynamic wallpaper playback. The core code is as follows:
# author: CSDN dragon juvenile def play(self): if path == '': reply = QtWidgets.QMessageBox.question(self, 'Tips', "The selected video is not loaded", QtWidgets.QMessageBox.Yes) return with open("./filename.txt", 'w', encoding='utf-8') as f: f.truncate(0) print(f.write(str(path))) try: try: call('taskkill /F /IM play.exe') except: pass os.system('start play.exe') except: pass try: if self.cap != []: self.cap.release() self.timer_camera.stop() # Stop timer else: Warming = QMessageBox.warning(self, "Warming", "Push the left upper corner button to Quit.", QMessageBox.Yes) except: pass
In this way, we have completed the dynamic wallpaper loading application function, and the effect is as follows:
4. Turn off dynamic wallpaper
Finally, we can turn off the current dynamic wallpaper playback function. We need to release and cancel the current desktop video playback. The code is as follows:
# author: CSDN dragon juvenile def close_wall(self): try: call('taskkill /F /IM play.exe') except: pass
The effects are as follows:
So far, the whole custom dynamic desktop wallpaper function has been completed. Let's run it together to see the effect of dynamic wallpaper.
We'll stop here today and continue to work hard tomorrow!
If the content of this article is helpful to you, please like it three times, pay attention and collect it with support.
Creation is not easy, white whoring is not good. Your support and recognition is the biggest driving force for my creation. See you in the next article!
Dragon youth
If there are any mistakes in this blog, please comment and advice. Thank you very much!