IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PyQt Python Discussion :

Windows : utilisation de la "Non-client area"


Sujet :

PyQt Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre expérimenté Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Par défaut Windows : utilisation de la "Non-client area"
    Bonjour,

    je suis sous Windows 7 x64 et j'utilise PySide avec Python 3.

    Par curiosité j'ai cherché à mettre en pratique la technique employée ici http://msdn.microsoft.com/en-us/libr...=vs.85%29.aspx qui permet d'enlever la zone non cliente d'une fenêtre sous Windows tout en conservant les boutons de la barre de titre.

    J'ai donc cherché à intercepter les messages de la sorte

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
     
    from PySide.QtGui import QApplication, QWidget
     
    class Window(QWidget):
        def __init__(self):
            QWidget.__init__(self)
     
        def winEvent(self, msg, result):
            print(msg)
            return QWidget.winEvent(self, msg, result)
     
    if __name__ == '__main__':
        app = QApplication([])
        win = Window()
        win.show()
        app.exec_()
    mais je n'ai pas trouvé quoi que ce soit de très utile.

    Le but final et de pouvoir implémenter ce fameux DwmDefWindowProc qui permet d'avoir les boutons de la barre de titre fonctionnels tout en ayant la possibilité de dessiner sur la totalité de la fenêtre (barre de titre inclue) un peu comme le font Chrome et Firefox.

    Je sais également qu'il est possible d'intercepter les évènements de l'application au niveau de la QApplication mais j'aimerai éviter de ralentir le tout en faisant un hook depuis Python.

    Si quelqu'un a une piste je suis preneur.

    PS: Je sais que ce genre de technique n'est absolument pas portable mais c'est juste pour savoir si c'est possible.

  2. #2
    Expert confirmé

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 307
    Par défaut
    P'têt que ceci repondra à ta question:

    http://www.developpez.net/forums/d92...s/qt-dwm-aero/

  3. #3
    Membre expérimenté Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Par défaut
    Merci pour ta réponse.

    Je vais tenter de convertir en Python et voir si ça donne quelque chose de concluant.

    EDIT: J'ai essayé de convertir sans succès (trop de références à des fonctions issues de l'API win32).

    J'ai également installé QtCreator et testé la librairie QDwm et ça ne fait pas exactement ce que je désire. Je mettrai à jour le sujet si j'arrive à quelque chose de concluant.

  4. #4
    Membre expérimenté Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Par défaut
    J'ai réussi à avoir quelque chose de fonctionnel (non sans bugs) mais uniquement avec PyQt4 car PySide a un bug et il manque des attributs au paramètre msg de la méthode winEvent (donc impossibe d'aller plus loin).

    Voilà ce que ça donne en terme de code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
     
    from PyQt4.QtGui import QApplication, QWidget, QLabel
    from PyQt4.QtCore import Qt
    import ctypes
    from ctypes.wintypes import POINT
     
    WM_CREATE     = 0x0001
    WM_NCCALCSIZE = 0x0083
    WM_NCHITTEST  = 0x0084
     
    WS_OVERLAPPED = 0x00000000L
    WS_CAPTION = 0x00C00000L
    WS_MINIMIZEBOX = 0x00020000L
    WS_MAXIMIZEBOX = 0x00010000L
    WS_THICKFRAME = 0x00040000L
    WS_SYSMENU = 0x00080000L
    WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
     
    HTNOWHERE = 0
    HTCAPTION = 2
    HTLEFT = 10
    HTRIGHT = 11
    HTTOP = 12
    HTTOPLEFT = 13
    HTTOPRIGHT = 14
    HTBOTTOM = 15
    HTBOTTOMLEFT = 0x10
    HTBOTTOMRIGHT = 17
     
    NULL  = 0
    TRUE  = 1
    FALSE = 0
    TOPEXTENDWIDTH = 27
    BOTTOMEXTENDWIDTH = 20
    LEFTEXTENDWIDTH = 8
    RIGHTEXTENDWIDTH = 8
     
     
    def LOWORD(dword): return dword & 0x0000ffff
    def HIWORD(dword): return dword >> 16    
     
    class MARGINS(ctypes.Structure):
        _fields_ = [
            ("cxLeftWidth", ctypes.c_int),
            ("cxRightWidth", ctypes.c_int),
            ("cyTopHeight", ctypes.c_int),
            ('cyBottomHeight', ctypes.c_int)
        ]
     
    class WINDOWPOS(ctypes.Structure):
        _fields_ = [("hwnd", ctypes.wintypes.HWND),
                    ("hwndInsertAfter", ctypes.wintypes.HWND),
                    ("x", ctypes.c_int),
                    ("y", ctypes.c_int),
                    ("cx", ctypes.c_int),
                    ("cy", ctypes.c_int),
                    ("flags", ctypes.c_uint)]
     
    class NCCALCSIZE_PARAMS(ctypes.Structure):
        _fields_ = [("rgrc", ctypes.wintypes.RECT * 3),
                    ("lppos", WINDOWPOS)]
     
    class Application(QApplication):
        def __init__(self):
            QApplication.__init__(self, [])
            self.w = Window()
            self.w.show()
     
    class Window(QWidget):
        def __init__(self):
            QWidget.__init__(self)
            self.setAttribute(Qt.WA_TranslucentBackground)
            margins = MARGINS(-1, -1, -1, -1)
            _handlel = ctypes.c_int(int(self.winId()))
            ctypes.windll.dwmapi.DwmExtendFrameIntoClientArea(_handlel, ctypes.byref(margins))
            self.lbl = QLabel('test', parent=self)
            self.lbl.move(0, 0)
            self.lbl.resize(100, 30)
            self.setStyleSheet('background-color: red;')
            self.setMinimumSize(320, 240)
     
        def winEvent(self, msg):
            lRet = 0L
            _ptr = ctypes.c_int(0)
            ptr = ctypes.pointer(_ptr)
            fCallDWP = bool(ctypes.windll.dwmapi.DwmDefWindowProc(
                                    ctypes.c_int(int(self.winId())),
                                    ctypes.c_int(int(msg.message)),
                                    ctypes.c_long(msg.wParam),
                                    ctypes.c_long(msg.lParam),
                                    ptr))
            lRet = ptr.contents.value
            if msg.message == WM_NCCALCSIZE and msg.wParam == TRUE:
            #    aa = ctypes.wintypes.LPARAM(msg.lParam)
            #    pncsp = ctypes.cast(ctypes.pointer(aa), ctypes.POINTER(NCCALCSIZE_PARAMS)).contents
     
            #    pncsp.rgrc[0].left   = pncsp.rgrc[0].left   + 0
            #    pncsp.rgrc[0].top    = pncsp.rgrc[0].top    + 0
            #    pncsp.rgrc[0].right  = pncsp.rgrc[0].right  - 0
            #    pncsp.rgrc[0].bottom = pncsp.rgrc[0].bottom - 0
     
                fCallDWP = True
                lRet = 0L
     
            if msg.message == WM_NCHITTEST and lRet == 0:
                lRet = HitTestNCA(ctypes.c_int(int(self.winId())), msg.wParam, msg.lParam);
                if lRet != HTNOWHERE:
                    fCallDWP = True
     
            return (fCallDWP, lRet)
     
     
    # Hit test the frame for resizing and moving.
    def HitTestNCA(hWnd, wParam, lParam):
        # Get the point coordinates for the hit test.
        ptMouse = ctypes.wintypes.POINT(LOWORD(lParam), HIWORD(lParam))
     
        # Get the window rectangle.
        rcWindow = ctypes.wintypes.RECT()
        ctypes.windll.user32.GetWindowRect(hWnd, ctypes.pointer(rcWindow))
     
        # Get the frame rectangle, adjusted for the style without a caption.
        rcFrame = ctypes.wintypes.RECT(0)
        ctypes.windll.user32.AdjustWindowRectEx(ctypes.pointer(rcFrame), WS_OVERLAPPEDWINDOW & (not WS_CAPTION), FALSE, NULL)
     
        # Determine if the hit test is for resizing. Default middle (1,1).
        uRow = 1
        uCol = 1
        fOnResizeBorder = False
     
        # Determine if the point is at the top or bottom of the window.
        if (ptMouse.y >= rcWindow.top and ptMouse.y < rcWindow.top + TOPEXTENDWIDTH):
            fOnResizeBorder = (ptMouse.y < (rcWindow.top - rcFrame.top))
            uRow = 0
        elif (ptMouse.y < rcWindow.bottom and ptMouse.y >= rcWindow.bottom - BOTTOMEXTENDWIDTH):
            uRow = 2
     
        # Determine if the point is at the left or right of the window.
        if (ptMouse.x >= rcWindow.left and ptMouse.x < rcWindow.left + LEFTEXTENDWIDTH):
            uCol = 0
        elif (ptMouse.x < rcWindow.right and ptMouse.x >= rcWindow.right - RIGHTEXTENDWIDTH):
            uCol = 2
     
     
        # Hit test (HTTOPLEFT, ... HTBOTTOMRIGHT)
        hitTests = [
            [HTTOPLEFT, HTTOP if fOnResizeBorder else HTCAPTION, HTTOPRIGHT],
            [HTLEFT, HTNOWHERE, HTRIGHT],
            [HTBOTTOMLEFT, HTBOTTOM, HTBOTTOMRIGHT]
        ]
        return hitTests[uRow][uCol]
     
    if __name__ == '__main__':
        Application().exec_()
    si quelqu'un à une idée pour détecter dynamiquement les valeurs des bordures je suis preneur

    EDIT: pour information, j'ai utilisé cet article http://technet.microsoft.com/en-us/query/bb688195

  5. #5
    Membre expérimenté Avatar de ashren
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    101
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 101
    Par défaut
    Bonjour,

    ayant décidé de me pencher à nouveau sur le sujet, j'ai converti le code C++ disponible ici http://sourceforge.net/projects/qdwm/ en pur Python3/ctypes.

    Le tout non exempt de bugs évidemment (ne marche pas sur Python2 par exemple).

    Je précise également que je suis en x64 donc les appels ctypes sont peut-être incorrects.

    Je marque ma question comme résolue.

    EDIT: Ajout du code

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    255
    256
    257
    258
    259
    260
    261
    262
    263
    264
    265
    266
    267
    268
    269
    270
    271
    272
    273
    274
    275
    276
    277
    278
    279
    280
    281
    282
    283
    284
    285
    286
    287
    288
    289
    290
    291
    292
    293
    294
    295
    296
    297
    298
    299
    300
    301
    302
    303
    304
    305
    306
    307
    308
    309
    310
    311
    312
    313
    314
    315
    316
    317
    318
    319
    320
    321
    322
    323
    324
    325
    326
    327
    328
    329
    330
    331
    332
    333
    334
    335
    336
    337
    338
    339
    340
    341
    342
    343
    344
    345
    346
    347
    348
    349
    350
    351
    352
    353
    354
    355
    356
    357
    358
    359
    360
    361
    362
    363
    364
    365
    366
    367
    368
    369
    370
    371
    372
    373
    374
    375
    376
    377
    378
    379
    380
    381
    382
    383
    384
    385
    386
    387
    388
    389
    390
    391
    392
    393
    394
    395
    396
    397
    398
    399
    400
    401
    402
    403
    404
    405
    406
    407
    408
    409
    410
    411
    412
    413
    414
    415
    416
    417
    418
    419
    420
    421
    422
    423
    424
    425
    426
    427
    428
    429
    430
    431
    432
    433
    434
    435
    436
    437
    438
    439
    440
    441
    442
    443
    444
    445
    446
    447
    448
    449
    450
    451
    452
    453
    454
    455
    456
    457
    458
    459
    460
    461
    462
    463
    464
    465
    466
    467
    468
    469
    470
    471
    472
    473
    474
    475
    476
    477
    478
    479
    480
    481
     
    import ctypes
    from ctypes import wintypes
     
    from PyQt4 import QtGui, QtCore
    from PyQt4.QtCore import Qt
     
    class WMargins(ctypes.Structure):
        _fields_ = [
            ("cxLeftWidth", ctypes.c_int),
            ("cxRightWidth", ctypes.c_int),
            ("cyTopHeight", ctypes.c_int),
            ('cyBottomHeight', ctypes.c_int)
        ]
     
    WM_NCCALCSIZE = 0x0083
    WM_NCHITTEST  = 0x0084
    WM_NCPAINT = 133
    WM_NCMOUSEMOVE = 160
    WM_THEMECHANGED = 794
    WM_DWMCOMPOSITIONCHANGED = 798
     
    WS_OVERLAPPED = 0x00000000
    WS_CAPTION = 0x00C00000
    WS_MINIMIZEBOX = 0x00020000
    WS_MAXIMIZEBOX = 0x00010000
    WS_THICKFRAME = 0x00040000
    WS_SYSMENU = 0x00080000
    WS_OVERLAPPEDWINDOW = WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
     
    HTNOWHERE = 0
    HTCLIENT = 1
    HTCAPTION = 2
    HTMINBUTTON = 8
    HTMAXBUTTON = 9
    HTLEFT = 10
    HTRIGHT = 11
    HTTOP = 12
    HTTOPLEFT = 13
    HTTOPRIGHT = 14
    HTBOTTOM = 15
    HTBOTTOMLEFT = 0x10
    HTBOTTOMRIGHT = 17
    HTCLOSE = 20
    HTHELP = 21
     
    NULL = 0
    TRUE  = 1
    FALSE = 0
     
    SWP_FRAMECHANGED = 32
     
    ncHitZone = (
        (HTTOPLEFT, HTLEFT, HTLEFT, HTBOTTOMLEFT),
        (HTTOP, HTCAPTION, HTNOWHERE, HTBOTTOM),
        (HTTOPRIGHT, HTRIGHT, HTRIGHT, HTBOTTOMRIGHT)
    )
     
    def LOWORD(dword): return dword & 0x0000ffff
    def HIWORD(dword): return dword >> 16
     
    def GET_X_LPARAM(p):
        return LOWORD(p)
    def GET_Y_LPARAM(p):
        return HIWORD(p)
     
    class QWindowsHelper(object):
        _instance = None
     
        @classmethod
        def instance(cls):
            if not cls._instance:
                cls._instance = QWindowsHelper()
            return cls._instance
     
        def __init__(self):
            self.DwmDefWindowProc = ctypes.windll.dwmapi.DwmDefWindowProc
            self.DwmIsCompositionEnabled = ctypes.windll.dwmapi.DwmIsCompositionEnabled
            self.DwmExtendFrameIntoClientArea = ctypes.windll.dwmapi.DwmExtendFrameIntoClientArea
            self.IsThemeActive = ctypes.windll.uxtheme.IsThemeActive
     
    def qWinHelper():
        return QWindowsHelper.instance()
     
    def GetWindowRect(hwnd, rect):
        ctypes.windll.user32.GetWindowRect(ctypes.c_int(int(hwnd)), ctypes.byref(rect))
     
    SetWindowPos = ctypes.windll.user32.SetWindowPos
    AdjustWindowRectEx = ctypes.windll.user32.AdjustWindowRectEx
     
    class Win(QtGui.QMainWindow):
        themeChanged = QtCore.pyqtSignal()
        compositionChanged = QtCore.pyqtSignal()
        def __init__(self):
            QtGui.QMainWindow.__init__(self)
            self.setAttribute(Qt.WA_TranslucentBackground, True)
            self.__frameRemoved = False
            self.__margins = QtCore.QMargins(0, 0, 0, 0)
            self.setBorderSize(-1)
            self.setTitleBarSize(-1)
            self.__titleBarHover = QtGui.QStyle.SC_None
            self.__titleBarState = QtGui.QStyle.State_None
     
        def winEvent(self, wMsg):
            result = 0
            hasHandled = False
            res = ctypes.c_int(0)
            _ptr = ctypes.c_int(0)
            ptr = ctypes.pointer(_ptr)
     
            if self.isAeroActivated():
                hasHandled = bool(qWinHelper().DwmDefWindowProc(ctypes.c_int(int(self.winId())),
                                                                ctypes.c_int(int(wMsg.message)),
                                                                ctypes.c_long(int(wMsg.wParam)),
                                                                ctypes.c_long(int(wMsg.lParam)),
                                                                ptr))
                res = ptr.contents.value
     
            if wMsg.message == WM_NCCALCSIZE and wMsg.wParam == TRUE and self.__frameRemoved:
                hasHandled = True
                res = 0
     
            if wMsg.message == WM_NCHITTEST and res == 0 and self.__frameRemoved:
                if not (res == HTCLOSE or res == HTMAXBUTTON or res == HTMINBUTTON or res == HTHELP):
                    res = self.ncHitTest(wMsg)
     
                if res != HTNOWHERE:
                    hasHandled = True
     
            if wMsg.message == WM_DWMCOMPOSITIONCHANGED or wMsg.message == WM_THEMECHANGED:
                self.updateFrame()
                if self.isAeroActivated():
                    self.updateMargins()
     
                if wMsg.message == WM_DWMCOMPOSITIONCHANGED:
                    self.compositionChanged.emit()
     
                self.themeChanged.emit()
     
                self.repaint()
     
            if wMsg.message == WM_NCPAINT and not self.isThemeActivated():
                hasHandled = True
     
            if wMsg.message == WM_NCMOUSEMOVE:
                cx = 0
                cy = 0
                realWin = ctypes.wintypes.RECT()
     
                GetWindowRect(wMsg.hwnd, realWin)
     
                cx = GET_X_LPARAM(wMsg.lParam) - realWin.left
                cy = GET_Y_LPARAM(wMsg.lParam) - realWin.top
     
                self.ncMouseMove(cx, cy)
     
            if hasHandled:
                result = res
            return (hasHandled, result)
            return hasHandled
     
        def isAeroActivated(self):
            isDwmEnabled = ctypes.c_bool()
            hr = ctypes.HRESULT()
     
            if QtCore.QSysInfo.WindowsVersion < QtCore.QSysInfo.WV_VISTA:
                return False
     
            hr = qWinHelper().DwmIsCompositionEnabled(ctypes.byref(isDwmEnabled))
            if hr != 0:
                return False
     
            return bool(isDwmEnabled) == True
     
        def updateMargins(self, hWnd=0):
            if hWnd == 0:
                hWnd = self.winId()
     
            mar = WMargins()
            mar.cxLeftWidth = self.__margins.left()
            mar.cxRightWidth = self.__margins.right()
            mar.cyBottomHeight = self.__margins.bottom()
            mar.cyTopHeight = self.__margins.top()
     
            if self.__frameRemoved:
                mar.cxLeftWidth += self.borderSize()
                mar.cxRightWidth += self.borderSize()
                mar.cyBottomHeight += self.borderSize()
                mar.cyTopHeight += self.titleBarSize() + self.borderSize()
     
            qWinHelper().DwmExtendFrameIntoClientArea(ctypes.c_int(int(hWnd)), ctypes.byref(mar))
     
        def setFrameRemoved(self, isRemoved):
            self.__frameRemoved = isRemoved
            self.updateFrame()
            self.updateMargins()
            self.setMouseTracking(isRemoved)
     
        def setExtraMargins(self, margins):
            self.__margins = margins
            self.updateMargins()
     
        def updateFrame(self, hWnd=0):
            if hWnd == 0:
                hWnd = self.winId()
     
            rcClient = ctypes.wintypes.RECT()
            GetWindowRect(hWnd, rcClient)
     
            SetWindowPos(ctypes.c_int(int(hWnd)), NULL, rcClient.left, rcClient.top,
                rcClient.right - rcClient.left,
                rcClient.bottom - rcClient.top, SWP_FRAMECHANGED)
     
        def ncHitTest(self, wMsg):
            cur = QtCore.QPoint(GET_X_LPARAM(wMsg.lParam), GET_Y_LPARAM(wMsg.lParam))
            xPos = 1
            yPos = 2
     
            rcWin = ctypes.wintypes.RECT()
            GetWindowRect(wMsg.hwnd, rcWin)
     
            if self.hasControls(cur.x() - rcWin.left, cur.y() - rcWin.top):
                return HTCLIENT
     
            rcFrame = ctypes.wintypes.RECT(0)
            AdjustWindowRectEx(ctypes.byref(rcFrame), WS_OVERLAPPEDWINDOW & ~WS_CAPTION, False, NULL)
     
            if cur.y() > rcWin.top and cur.y() <= rcWin.top + self.borderSize():
                yPos = 0
            elif cur.y() > rcWin.top + self.borderSize() and cur.y() <= rcWin.top + self.borderSize() + self.titleBarSize():
                yPos = 1
            elif cur.y() >= rcWin.bottom - self.borderSize() and cur.y() < rcWin.bottom:
                yPos = 3
     
            if cur.x() >= rcWin.left and cur.x() < rcWin.left + self.borderSize():
                xPos = 0
            elif cur.x() >= rcWin.right - self.borderSize() and cur.x() < rcWin.right:
                xPos = 2
     
            return ncHitZone[xPos][yPos]
     
        def setBorderSize(self, size):
            if size < 0:
                self.__borderSize = -1
            else:
                self.__borderSize = size
     
            if self.__frameRemoved:
                self.updateFrame()
                self.updateMargins()
     
        def setTitleBarSize(self, size):
            if size < 0:
                self.__titleBarSize = -1
            else:
                self.__titleBarSize = size
     
            if self.__frameRemoved:
                self.updateFrame()
                self.updateMargins()
     
        def paintEvent(self, e):
            if self.isAeroActivated():
                p = QtGui.QPainter(self)
                r = QtCore.QRect()
     
                p.setBrush(self.palette().window())
                p.setPen(Qt.NoPen)
     
                if self.__frameRemoved:
                    r.setLeft(self.borderSize() + self.__margins.left())
                    r.setWidth(self.width() - (2 * self.borderSize() + self.__margins.left() + self.__margins.right()))
                    r.setTop(self.borderSize() + self.titleBarSize() + self.__margins.top())
                    r.setHeight(self.height() - (2 * self.borderSize() + self.titleBarSize()
                        + self.__margins.top() + self.__margins.bottom()))
                else:
                    r.setLeft(self.__margins.left())
                    r.setWidth(self.width() - self.__margins.left() - self.__margins.right())
                    r.setTop(self.__margins.top())
                    r.setHeight(self.height() - self.__margins.top() - self.__margins.bottom())
     
                p.drawRect(r)
            else:
                if self.__frameRemoved:
                    self.paintWinFrame()
                else:
                    p = QtGui.QPainter(self)
     
                    p.setBrush(self.palette().window())
                    p.setPen(Qt.NoPen)
     
                    p.drawRect(0, 0, self.width(), self.height())
     
        def isThemeActivated(self):
            if QtCore.QSysInfo.WindowsVersion < QtCore.QSysInfo.WV_XP:
                return False
     
            return qWinHelper().IsThemeActive() == True
     
        def paintWinFrame(self):
            p = QtGui.QStylePainter()
            p.begin(self)
     
            p.setPen(Qt.NoPen)
            p.setBrush(self.palette().window())
            p.drawRect(0, 0, self.width(), self.height())
     
            pal = self.palette()
            if self.isActiveWindow():
                pal.setCurrentColorGroup(QtGui.QPalette.Active)
            else:
                pal.setCurrentColorGroup(QtGui.QPalette.Inactive)
     
            frame = QtGui.QStyleOptionFrame()
            frame.initFrom(self)
            frame.lineWidth = self.borderSize()
     
            title = QtGui.QStyleOptionTitleBar()
            title.initFrom(self)
            if self.isThemeActivated():
                title.rect.setRect(0, 0, self.width(), self.borderSize() + self.titleBarSize())
            else:
                title.rect.setRect(self.borderSize(), self.borderSize(), self.width() - 2 * self.borderSize(),
                self.titleBarSize() + self.style().pixelMetric(QtGui.QStyle.PM_MdiSubWindowFrameWidth))
            title.state = QtGui.QStyle.State_Active if self.isActiveWindow() else QtGui.QStyle.State_None
            title.palette = pal
            title.titleBarState = title.state
            if self.isMaximized():
                title.titleBarState |= Qt.WindowMaximized
            title.subControls = title.subControls and ~QtGui.QStyle.SC_TitleBarSysMenu
            title.activeSubControls = 0
     
            p.drawPrimitive(QtGui.QStyle.PE_FrameWindow, frame)
            p.drawComplexControl(QtGui.QStyle.CC_TitleBar, title)
     
            title.subControls &= ~QtGui.QStyle.SC_TitleBarLabel
            title.titleBarFlags = self.windowFlags()
            title.activeSubControls = self.__titleBarHover
            title.state = self.__titleBarState
            if self.isThemeActivated():
                title.rect.setRect(0, 0 - self.style().pixelMetric(QtGui.QStyle.PM_MdiSubWindowFrameWidth), self.width(),
                self.style().pixelMetric(QtGui.QStyle.PM_TitleBarHeight) + self.style().pixelMetric(QtGui.QStyle.PM_MdiSubWindowFrameWidth))
            else:
                title.rect.setRect(self.borderSize(), self.borderSize(), self.width() - 2 * self.borderSize(),
                self.style().pixelMetric(QtGui.QStyle.PM_TitleBarHeight))
     
            p.drawComplexControl(QtGui.QStyle.CC_TitleBar, title)
     
            p.end()
     
        def borderSize(self):
            if self.__borderSize < 0:
                return self.style().pixelMetric(QtGui.QStyle.PM_MDIFrameWidth)
     
            return self.__borderSize
     
        def titleBarSize(self):
            return self.__titleBarSize
     
        def ncMouseMove(self, cx, cy):
            if not self.__frameRemoved or self.isAeroActivated():
                self.__titleBarHover = QtGui.QStyle.SC_None
                self.__titleBarState = QtGui.QStyle.State_None
                return
     
            title = QtGui.QStyleOptionTitleBar()
            title.initFrom(self)
            title.titleBarFlags = self.windowFlags()
            if self.isThemeActivated():
                title.rect.setRect(0, 0, self.width(), self.style().pixelMetric(QtGui.QStyle.PM_TitleBarHeight))
            else:
                title.rect.setRect(self.borderSize(), self.borderSize(), self.width() - 2 * self.borderSize(),
                self.style().pixelMetric(QtGui.QStyle.PM_TitleBarHeight))
     
            if self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarCloseButton, NULL).contains(cx, cy):
                if self.__titleBarHover != QtGui.QStyle.SC_TitleBarCloseButton:
                    self.__titleBarHover = QtGui.QStyle.SC_TitleBarCloseButton
                    self.__titleBarState = QtGui.QStyle.State_MouseOver
                    self.repaint()
            elif self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarMaxButton, NULL).contains(cx, cy) and not self.isMaximized():
                if self.__titleBarHover != QtGui.QStyle.SC_TitleBarMaxButton:
                    self.__titleBarHover = QtGui.QStyle.SC_TitleBarMaxButton
                    self.__titleBarState = QtGui.QStyle.State_MouseOver
                    self.repaint()
            elif self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarMinButton, NULL).contains(cx, cy):
                if self.__titleBarHover != QtGui.QStyle.SC_TitleBarMinButton:
                    self.__titleBarHover = QtGui.QStyle.SC_TitleBarMinButton
                    self.__titleBarState = QtGui.QStyle.State_MouseOver
                    self.repaint()
            elif self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarMaxButton, NULL).contains(cx, cy) and self.isMaximized():
                if self.__titleBarHover != QtGui.QStyle.SC_TitleBarNormalButton:
                    self.__titleBarHover = QtGui.QStyle.SC_TitleBarNormalButton
                    self.__titleBarState = QtGui.QStyle.State_MouseOver
                    self.repaint()
            else:
                if self.__titleBarHover != QtGui.QStyle.SC_None:
                    self.__titleBarHover = QtGui.QStyle.SC_None
                    self.__titleBarState = QtGui.QStyle.State_None
                    self.repaint()
     
        def hasControls(self, cx, cy):
            title = QtGui.QStyleOptionTitleBar()
            title.initFrom(self)
            title.titleBarFlags = self.windowFlags()
            title.rect.setRect(0, 0, self.width(), self.style().pixelMetric(QtGui.QStyle.PM_TitleBarHeight))
     
            if self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarCloseButton, None).contains(cx, cy):
                return True
            if self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarMaxButton, None).contains(cx, cy):
                return True
            if self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarMinButton, None).contains(cx, cy):
                return True
            if self.style().subControlRect(QtGui.QStyle.CC_TitleBar, title, QtGui.QStyle.SC_TitleBarNormalButton, None).contains(cx, cy):
                return True
     
            rcWin = ctypes.wintypes.RECT()
            GetWindowRect(self.winId(), rcWin)
     
            w = QtGui.QApplication.widgetAt(cx + rcWin.left, cy + rcWin.top)
            if w != NULL and w != self:
                return True
     
            return False
     
        def ncMousePress(self, *args):
            if self.__titleBarHover != QtGui.QStyle.SC_None:
                self.__titleBarState = QtGui.QStyle.State_Sunken
                self.repaint()
     
        def ncMouseRelease(self, *args):
            if self.__titleBarState == QtGui.QStyle.State_Sunken:
                self.__titleBarState = QtGui.QStyle.State_MouseOver
                self.repaint()
     
                if self.__titleBarHover == QtGui.QStyle.SC_TitleBarCloseButton:
                    self.close()
                elif self.__titleBarHover == QtGui.QStyle.SC_TitleBarMaxButton:
                    self.showMaximized()
                elif self.__titleBarHover == QtGui.QStyle.SC_TitleBarMinButton:
                    self.showMinimized()
                elif self.__titleBarHover == QtGui.QStyle.SC_TitleBarNormalButton:
                    self.showNormal()
     
        def mousePressEvent(self, eve):
            realWin = ctypes.wintypes.RECT()
            GetWindowRect(self.winId(), realWin)
     
            self.ncMousePress(eve.globalX() - realWin.left,
                eve.globalY() - realWin.top)
     
        def mouseMoveEvent(self, eve):
            realWin = ctypes.wintypes.RECT()
            GetWindowRect(self.winId(), realWin)
     
            self.ncMouseMove(eve.globalX() - realWin.left,
                eve.globalY() - realWin.top)
     
        def mouseReleaseEvent(self, eve):
            realWin = ctypes.wintypes.RECT()
            GetWindowRect(self.winId(), realWin)
     
            self.ncMouseRelease(eve.globalX() - realWin.left,
                eve.globalY() - realWin.top)
     
        def isFrameRemoved(self):
            return self.__frameRemoved
     
        def extraMargins(self):
            return self.__margins
     
    if __name__ == '__main__':
        app = QtGui.QApplication([])
        win = Win()
        win.setFrameRemoved(True)
        win.setDocumentMode(True)
        win.setTitleBarSize(win.titleBarSize() + 50)
        win.setContentsMargins(win.borderSize(), win.titleBarSize() + win.borderSize(), win.borderSize(), win.borderSize())
        btn = QtGui.QPushButton("TEST", win)
        win.setCentralWidget(btn)
        win.show()
        app.exec_()

  6. #6
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour ashren,

    Beau code, dont une ligne sur 2 contient des instructions que je connais pas .

    Ce code semble fonctionner sur Windows 7 64 bits / Python 2.7 si le but est d'obtenir une fenêtre avec un gros bouton qui prend toute la zone cliente, et une barre haute anormalement grande. Par contre, quand je clique sur test, il ne se passe rien.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Painting on non client area
    Par Eric_M dans le forum VB.NET
    Réponses: 4
    Dernier message: 10/12/2010, 23h46
  2. [VB.NET] utiliser une classe ou non
    Par maxxou dans le forum Windows Forms
    Réponses: 2
    Dernier message: 23/09/2006, 01h09
  3. [BOOST] utilisation de boost uBLAS non compile avec visual c++
    Par le_voisin dans le forum Autres éditeurs
    Réponses: 5
    Dernier message: 06/09/2006, 22h03
  4. [Tableaux] Utiliser un regexp ou non ?
    Par renaud26 dans le forum Langage
    Réponses: 4
    Dernier message: 18/07/2006, 13h35
  5. [Windows]utiliser une dll c# en java
    Par dude666 dans le forum API standards et tierces
    Réponses: 3
    Dernier message: 01/07/2005, 02h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo