Nightmare1
@Nightmare1
Программист

Возможно ли окно у окна отключить взаимодействие?

Нужно создать окно, которое имеет только функцию отображения, но не имеет функции обработки взаимодействия с пользователем. Т.е. при кликанье и таскании окон сквозь это фрейм происходит то же самое что происходиит при кликаньи и таскании окон без этого фрейма. У кого есть соображения по поводу реализации.
python ver 3 +
PyQt5

import sys
from PyQt5 import QtGui, QtCore, uic
from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QApplication
import random as r
import threading, time

class MainWindow(QMainWindow):
    def __init__(self, screen_size):
        QMainWindow.__init__(self)
        self.setWindowFlags(
            QtCore.Qt.WindowStaysOnTopHint |
            QtCore.Qt.FramelessWindowHint |
            QtCore.Qt.X11BypassWindowManagerHint
        )
        self.size = size  + QtCore.QSize(220, 32)
        self.setGeometry(
            QtWidgets.QStyle.alignedRect(
                QtCore.Qt.LeftToRight, QtCore.Qt.AlignCenter,
                self.size,
                QtWidgets.qApp.desktop().availableGeometry()
        ))

        self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)

        def update_widget():
            time.sleep(3)
            self.update()

        threading.Thread(target=update_widget).start()

    def mousePressEvent(self, event):
        QtWidgets.qApp.quit()

    def paintEvent(self, event):
        width, height = 100, 200
        qp = QtGui.QPainter(self)
        qp.setBrush(QtGui.QColor(r.randint(0, 255),r.randint(0, 255),r.randint(0, 255)))       
        qp.drawRect(100, 100, width, height)        

if __name__ == '__main__':
    app = QApplication(sys.argv)
    screen = app.primaryScreen()
    print('Screen: %s' % screen.name())
    size = screen.size()
    print('Size: %d x %d' % (size.width(), size.height()))
    rect = screen.availableGeometry()
    print('Available: %d x %d' % (rect.width(), rect.height()))
    mywindow = MainWindow(size)
    mywindow.show()
    app.exec_()


self.setAttribute(  QtCore.Qt.WA_TransparentForMouseEvents ) # ничего не меняется
self.setWindowFlags( QtCore.Qt.WindowTransparentForInput ) # Появляется рамка главного окна, взаимодействие с окном 
# не прозрачно.
  • Вопрос задан
  • 406 просмотров
Решения вопроса 1
Nightmare1
@Nightmare1 Автор вопроса
Программист
Нашёл решение ,флаг QtCore.Qt.WindowTransparentForInput отключает возможность взаимодействия мышью и клавиатурой с плоскостью отображения.

self.setWindowFlags(
            QtCore.Qt.WindowStaysOnTopHint |
            QtCore.Qt.FramelessWindowHint |
            QtCore.Qt.X11BypassWindowManagerHint
            | QtCore.Qt.WindowTransparentForInput
        )
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@EldarAliev7661
Задать self.setWindowFlags(QtCore.Qt.Dialog). или создать его как диалоговое окно QtWidget.QDialog(parent).

Qt::Dialog - Указывает, что виджет представляет собой окно, которое должно быть оформлено как диалоговое окно (т. е. обычно в строке заголовка нет кнопок развертывания и свертывания). Это тип по умолчанию дляQDialog. Если вы хотите использовать его в качестве модального диалога, его следует запускать из другого окна или иметь родительский элемент и использовать сQWidget::windowModalityсвойство. Если вы сделаете его модальным, диалоговое окно не позволит другим окнам верхнего уровня приложения получать какие-либо данные. Мы ссылаемся на окно верхнего уровня, у которого есть родительский элемент, как на вторичное окно.
https://doc.qt.io/qt-5/qt.html#WindowModality-enum


Мне этот вариант подашёл. При открытии вторых окон родительское окно блокируется. У QDialog по умолчанию стоит флаг Dialog, но не смотря на это с этим флагом появляется эффект затемнения родительского окна, что мне понравилось.

class Window(QtWidgets.QMainWindow):

    def __init__(self):
        super(Window, self).__init__()
        # .... code
        self.show()

    def _openSettings(self):
        WindowSettings(self)



class WindowSettings(QtWidgets.QDialog):

    def __init__(self, window):
        super(WindowSettings, self).__init__(window, QtCore.Qt.Window)
        self.setWindowFlags(QtCore.Qt.Dialog)
        self.setWindowModality(QtCore.Qt.WindowModal)

        # .... code
        self.show()

    def save(self):
        # code saveing  К примеру self.window.setSettings(arg)
        self.deleteLater()
Ответ написан
Комментировать
Vindicar
@Vindicar
RTFM!
Не знаю, есть ли решение через PyQT, но точно есть решение через WinAPI.
SetWindowRgn() позволяет задать активный регион для окна. Точки, не входящие в этот регион, не будут обрабатываться ни при рисовании, ни при кликах.

Пример

import ctypes
import ctypes.wintypes as w

def ErrorIfZero(result, func, args):
    if not result:
        raise ctypes.WinError(ctypes.get_last_error())
    return result

# используем user32.dll и kernel32.dll
kernel32 = ctypes.windll.kernel32
user32 = ctypes.windll.user32
gdi32 = ctypes.windll.gdi32
# описываем используемые функции, типы и константы 
kernel32.GetConsoleWindow.argtypes = []
kernel32.GetConsoleWindow.restype = w.HWND
kernel32.GetConsoleWindow.check = ErrorIfZero

user32.GetWindowRect.argtypes = [w.HWND, w.LPRECT]
user32.GetWindowRect.restype = w.BOOL
user32.GetWindowRect.check = ErrorIfZero

user32.SetWindowRgn.argtypes = [w.HWND, w.HRGN, w.BOOL]
user32.SetWindowRgn.restype = w.INT
user32.SetWindowRgn.check = ErrorIfZero

gdi32.DeleteObject.argtypes = [w.HANDLE]
gdi32.DeleteObject.restype = w.BOOL
gdi32.DeleteObject.check = ErrorIfZero

gdi32.CreateRectRgnIndirect.argtypes = [w.LPRECT]
gdi32.CreateRectRgnIndirect.restype = w.HRGN
gdi32.CreateRectRgnIndirect.check = ErrorIfZero

gdi32.CombineRgn.argtypes = [w.HRGN, w.HRGN, w.HRGN, w.INT]
gdi32.CombineRgn.restype = w.INT
gdi32.CombineRgn.check = ErrorIfZero
RGN_AND  = 1
RGN_OR   = 2
RGN_XOR  = 3
RGN_DIFF = 4
RGN_COPY = 5


hWnd = kernel32.GetConsoleWindow()
r = w.RECT()
user32.GetWindowRect(hWnd, ctypes.byref(r))
r.left, r.right = 0, r.right - r.left
r.top, r.bottom = -50, r.bottom - r.top #почему-то есть косяк с заголовком окна
hole = w.RECT(r.right // 4, r.bottom // 4, 3 * r.right // 4, 3 * r.bottom // 4)

hRgn = gdi32.CreateRectRgnIndirect(ctypes.byref(r))
hHole = gdi32.CreateRectRgnIndirect(ctypes.byref(hole))
gdi32.CombineRgn(hRgn, hRgn, hHole, RGN_DIFF)
gdi32.DeleteObject(hHole)

user32.SetWindowRgn(hWnd, hRgn, True)

input('Press Enter to fix the hole.')

user32.SetWindowRgn(hWnd, 0, True)
gdi32.DeleteObject(hRgn)

Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы