The desktop is too monotonous? Make a custom dynamic wallpaper with Python, and you can play videos!

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:

  1. UI layout design, confirm the function design of dynamic wallpaper
  2. Load the video, preview and read the video, save the video path, etc
  3. The dynamic wallpaper function realizes the application, obtains the desktop handle, rotates and loads the video
  4. 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!

Keywords: Python PyQt5

Added by massimoGornatti on Sun, 19 Dec 2021 01:51:19 +0200