Python 如何使用PyQT5创建应用程序桌面工具栏UI

Python 如何使用PyQT5创建应用程序桌面工具栏UI,python,windows,pyqt5,Python,Windows,Pyqt5,如何将UI制作/注册为应用程序桌面工具栏(Windows),以防止其他应用程序使用UI使用的桌面区域?需要在底部创建自定义的类似任务栏的面板,并使其余窗口适合大小,而不是ui下。至少我从和中找到了问题。经过对PyQt5的一些调整后,它对我起了作用 """ Registering an Application Desktop Toolbar in Windows for PyQt5 window. Taken from https://gist.github.com/swdevbali/

如何将UI制作/注册为应用程序桌面工具栏(Windows),以防止其他应用程序使用UI使用的桌面区域?需要在底部创建自定义的类似任务栏的面板,并使其余窗口适合大小,而不是ui下。

至少我从和中找到了问题。经过对PyQt5的一些调整后,它对我起了作用

    """
Registering an Application Desktop Toolbar in Windows for PyQt5 window.

Taken from https://gist.github.com/swdevbali/495f902162446b30cd567b2a44d86d79 and 
           https://github.com/sabren/ceomatic/blob/master/wxappbars.py, 
thanks for swdevbali and sabren
Adapted by Elendiar.
"""
import ctypes, sys
from ctypes import wintypes
from ctypes import *
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QApplication, QDesktopWidget, QWidget
from PyQt5.QtCore import *
from copy import deepcopy

shell32 = windll.shell32
user32 = windll.user32
import win32api, win32con, win32gui

class APPBARDATA(Structure):
    _fields_= [
        ("cbSize", wintypes.DWORD),
        ("hWnd", wintypes.HWND),
        ("uCallbackMessage", ctypes.c_ulong),
        ("uEdge", c_ulong),
        ("rc", wintypes.RECT),
        ("lParam", wintypes.LPARAM),
    ]
PAPPBARDATA = POINTER(APPBARDATA)


class ABEdge:
    Left = 0
    Top = 1
    Right = 2
    Bottom = 3
    Float = 4


class ABMsg:
    ABM_NEW = 0
    ABM_REMOVE = 1
    ABM_QUERYPOS = 2
    ABM_SETPOS = 3
    ABM_GETSTATE = 4
    ABM_GETTASKBARPOS = 5
    ABM_ACTIVATE = 6
    ABM_GETAUTOHIDEBAR = 7
    ABM_SETAUTOHIDEBAR = 8
    ABM_WINDOWPOSCHANGED = 9
    ABM_SETSTATE = 10


class ABNotify:
    ABN_STATECHANGE = 0
    ABN_POSCHANGED = 1
    ABN_FULLSCREENAPP = 2
    ABN_WINDOWARRANGE = 3




class RegisterInfo(object):

    def __init__(self):
        self._window = None

        self.callbackId = 0
        self.isRegistered = False
        self.edge = ABEdge.Float
        self.originalStyle = None
        self.originalPosition = None
        self.originalSize = None
        self.originalResizeMode = None


    @property
    def window(self):
        return self._window

    @window.setter
    def window(self, window):
        self._window = window
        self._hWnd = window.winId().__int__()
        self._oldWndProc = win32gui.SetWindowLong(self._hWnd,
                                                 win32con.GWL_WNDPROC,
                                                 self.WndProc)

    # http://wiki.wxpython.org/HookingTheWndProc
    def WndProc(self, hWnd, msg, wParam, lParam ):
        if msg == win32con.WM_DESTROY:
            self._restoreOldWndProc()
        elif msg == self.callbackId:
            if wParam == ABNotify.ABN_POSCHANGED:
                _ABSetPos(self.edge, self.window)
        else:
            return win32gui.\
                CallWindowProc(self._oldWndProc, hWnd, msg, wParam, lParam)


    def _restoreOldWndProc(self):
        win32api.SetWindowLong(self._hWnd,
                               win32con.GWL_WNDPROC,
                               self._oldWndProc)

_registeredWindowInfo = {}
def _GetRegisterInfo(appbarWindow):
    geometry = appbarWindow.geometry()
    reg = RegisterInfo()
    reg.callBackId = 0
    reg.window = appbarWindow
    reg.isRegistered = False
    reg.edge = ABEdge.Top
    reg.originalStyle = appbarWindow.windowFlags()
    reg.originalPosition = QPoint(geometry.x(), geometry.y())
    reg.originalSize = QSize(geometry.width(), geometry.height())
    _registeredWindowInfo[appbarWindow] = reg
    return _registeredWindowInfo[appbarWindow]


def _RestoreWindow(appbarWindow):
    info = _GetRegisterInfo(appbarWindow)
    appbarWindow.setWindowFlags(info.originalStyle)
    appbarWindow.move(info.originalPosition)
    appbarWindow.resize(info.originalSize)

def SetAppBar(appbarWindow, edge, barSize):

    info = _GetRegisterInfo(appbarWindow)
    info.edge = edge
    abd = APPBARDATA()
    abd.cbSize = wintypes.DWORD(sizeof(abd))
    abd.hWnd = wintypes.HWND(appbarWindow.winId().__int__())

    if (edge == ABEdge.Float) and info.isRegistered:
        shell32.SHAppBarMessage(ABMsg.ABM_REMOVE, PAPPBARDATA(abd))
        info.isRegistered = False
        _RestoreWindow(appbarWindow)

    elif not info.isRegistered:
        info.isRegistered = True
        info.callbackId = win32api.RegisterWindowMessage("AppBarMessage")
        shell32.SHAppBarMessage(ABMsg.ABM_NEW, PAPPBARDATA(abd))

    appbarWindow.setWindowFlags(Qt.FramelessWindowHint | Qt.WindowStaysOnTopHint) 
    _ABSetPos(info.edge, appbarWindow, barSize)

def RemoveAppBar(appbarWindow):
    print('REMOVING')
    info = _GetRegisterInfo(appbarWindow)
    abd = APPBARDATA()
    shell32.SHAppBarMessage(ABMsg.ABM_REMOVE, PAPPBARDATA(abd))
    info.isRegistered = False
    #_RestoreWindow(appbarWindow)

def _DoResize(appBarWindow, rect):
    appBarWindow.resize(rect.Width, rect.Height)
    appBarWindow.move(rect.Left, rect.Top)


def _ABSetPos(edge, appbarWindow, barSize):
    barData = APPBARDATA()
    barData.cbSize = wintypes.DWORD(sizeof(barData))
    barData.hWnd = appbarWindow.winId().__int__()
    barData.uEdge = edge
    screen = QDesktopWidget().screenGeometry()

    deskW = screen.width()
    deskH = screen.height()

    if barData.uEdge == ABEdge.Left or barData.uEdge == ABEdge.Right:
        winW = barSize
        winH = deskH
        barData.rc.top = 0
        barData.rc.bottom = deskH
        if barData.uEdge == ABEdge.Left:
            barData.rc.left = 0
            barData.rc.right = winW
        else:
            barData.rc.right = deskW
            barData.rc.left = deskW - winW
    else:
        winW = deskW
        winH = barSize
        barData.rc.left = 0
        barData.rc.right = deskW
        if barData.uEdge == ABEdge.Top:
            barData.rc.top = 0
            barData.rc.bottom = winH
        else:
            barData.rc.bottom = deskH
            barData.rc.top = deskH - winH

    oldLeft = deepcopy(barData.rc.left)  # deepcopy because after reopen x from 0 
                become w -> 222 and window isnt visible.
    shell32.SHAppBarMessage(ABMsg.ABM_QUERYPOS, PAPPBARDATA(barData))
    shell32.SHAppBarMessage(ABMsg.ABM_SETPOS, PAPPBARDATA(barData))
    barData.rc.left = deepcopy(oldLeft)

    def _resize():
        x = barData.rc.left
        y = barData.rc.top
        w = barData.rc.right - barData.rc.left
        h = barData.rc.bottom - barData.rc.top
        appbarWindow.resize(w, h)
        appbarWindow.move(x, y)


    # This is done async, because windows will send a resize after a new appbar is 
    added.
    # if we size right away, the windows resize comes last and overrides us.
    QTimer.singleShot(300, _resize)


if __name__=="__main__":
    # DPI scaling
    # QApplication.setAttribute(Qt.AA_EnableHighDpiScaling, True)
    # QApplication.setAttribute(Qt.AA_UseHighDpiPixmaps, True)
    app = QtWidgets.QApplication(sys.argv)
    win = QWidget()
    win.setWindowFlags(Qt.FramelessWindowHint |
                            Qt.WindowStaysOnTopHint |
                            Qt.CustomizeWindowHint |
                            Qt.Tool
                            ) 
    btn = QtWidgets.QPushButton('Click-to-close', win)
    btn.clicked.connect(QtWidgets.qApp.quit)
    barSize = 222
    SetAppBar(win, ABEdge.Left, barSize)
    win.show()
    sys.exit(app.exec_())

你能不能试着澄清一下你想要实现什么,可能是你打算做什么的一些截图或模型?@musicamante我希望如果最大化,每个窗口都不会捕获应用程序的区域。并将其调整为静止自由窗口区域。我只知道idk是如何在Pyqt5中实现的,因为我读到的关于QToolbar的所有内容都是关于widget toolbar的,我不明白。据我所知,Qt还没有直接提供这个功能。通过C++实现它是可能的,但是使用Python可能会更难,因为你必须找到一种方法来使用注册API的Windows API来进行通信。@ MyiMaMaTe,我必须设法找到DLLCAL。类似的东西,但我不能帮助你很多,因为我主要使用Linux,对不起。