Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. Click-through window will blink due setWindowFlags
Forum Updated to NodeBB v4.3 + New Features

Click-through window will blink due setWindowFlags

Scheduled Pinned Locked Moved Unsolved Qt for Python
3 Posts 2 Posters 750 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • C Offline
    C Offline
    Celles
    wrote on last edited by Celles
    #1

    Hello! I'm new to PyQt and also I'm writing my first python app. It's pretty simple, an invisible root window with floating children windows containing images. These windows can sometimes have lowered opacity and be set to click through so the user can draw through them on their painting or 3D program of choice.

    I'm using Qt.WindowType.WindowTransparentForInput to make the windows click-through, it was the only method that worked. The issue is that setting window flags automatically hides them, forcing me to show() them. The resulting blink looks like a glitch, it's really bad.

    Is there any other way to make windows transparent to at least left-clicks that wouldn't involve hiding and showing the window again?

    If not I've came up with a workaround for the blinking. It's a convoluted illusion and sometimes doesn't work either:

    1. I'm taking a screenshot of the window with flags about to be altered.
    2. That window is covered with a new one with the screenshot to create the illusion it's still there.
    3. The appearance of the placeholder window fires a signal for the flag to be set. The real window behind it disappears and is shown again.
    4. The reveal of the real window fires a second signal for the placeholder be hidden.

    Unfortunately, it turns out that isVisible() only informs someone set a window to be show, not that it's actually drawn. It always returns True when there's no placeholder yet.

    I've set the first signal to fire when the mouse enters the placeholder then, as it'll be shown on top of the old window. This Enter event the very last event fired when the placeholder shows up, and it still doesn't guarantee the paint event was done. 1 in out of 10 times the signal will manage to fire before the placeholder is ready. I'm having the same issue when restoring the real window.

    These are the events for the placeholder:

    Type.ZOrderChange               (placeholder) - is spontaneous: False
    Type.Show                       (placeholder) - is spontaneous: False
    Type.CursorChange               (placeholder) - is spontaneous: False
    Type.ShowToParent               (placeholder) - is spontaneous: False
    Type.ZOrderChange               (placeholder) - is spontaneous: False
    Type.Paint                      (placeholder) - is spontaneous: True
    Type.UpdateLater                (placeholder) - is spontaneous: False
    Type.UpdateRequest              (placeholder) - is spontaneous: False
    Type.Paint                      (placeholder) - is spontaneous: True
    Type.Enter                      (placeholder) - is spontaneous: False
    

    There's always an UpdateRequest before the final Paint event, then it fires Enter as the fake window pops up under the cursor. The real window restore is similar, but without the final Enter since it's being forced to appear under the placeholder. None of these events seems to guarantee the window was rendered, this that it was requested.

    Ideas? Either an alterative method to make windows click-through without hiding them or a way to detect painting was done on a window would help.

    On, and I'm using PyQt6 on Windows, but am aiming to make the app multiplatform.

    1 Reply Last reply
    0
    • C Offline
      C Offline
      Celles
      wrote on last edited by Celles
      #2

      I've set this aside for a while but started to poke at it again. Looks like there is another method that could help with setting flags without hiding the window:

      QtWidgets.QWidget.overrideWindowFlags( WindowFlags )
      

      "Sets the window flags for the widget to flags, without telling the window system.
      Do not call this function unless you really know what you’re doing."

      Sounds ideal if I can control when the window system gets told about the new flags. And how do you notify it?

      ¯\(ツ)/¯

      I've been scouring the internet to fulfil that "know what you're doing" warning, but there are no detailed docs, no actual examples. I've only found a thread from 2009 with zero replies. No wonder no one seems to be using it. Doing a simple stay on top test looks like doing nothing at all:

      flags = self.windowFlags()
      flags |= Qt.WindowType.WindowStaysOnTopHint
      self.overrideWindowFlags(flags)
      

      The window won't disappear, but it won't update either. I've tried to repaint, update, even hide and show but it's no good. I've not found any pyqt native method to notify the window system, and if I'm supposed to use low level messages from another modules to notify then overrideWindowFlags isn't that useful. I might just setflags with them as well.

      P.s.: Besides hiding the widget, a regular setWindowFlag will remove the winId and reassign it, then set the icon again. Override doesn't do any of this. I've been fumbling with the winId then, but again the lack of methods is getting in the way.

      1 Reply Last reply
      0
      • L Offline
        L Offline
        lachdanan
        wrote on last edited by
        #3

        I run into the same issue. Except I am using Pyside2. Is there any way to fix this issue? Calling update hides the window. So after setWindowFlags function, I have to call show function but like OP it flickers. Not sure why this sort of design is implemented. Can this be remedied in a future version or is there a workaround? My code is like this:

        def setPassThroughMode(window, enable):
            if enable:
                # Set the window to be transparent for input
                window.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint | QtCore.Qt.WindowTransparentForInput)
            else:
                # Restore the normal floating window behavior
                window.setWindowFlags(QtCore.Qt.Tool | QtCore.Qt.FramelessWindowHint)
        
            window.setAttribute(QtCore.Qt.WA_TransparentForMouseEvents, enable)
            window.setAttribute(QtCore.Qt.WA_NoMousePropagation, enable)
        
            # Ensure changes take effect
            window.show()  # Reapply visibility to update flags
        
        def togglePassThroughMode(window):
            # Check if the window is valid
            if not shiboken2.isValid(window):
                return
        
            # Check if the window is in pass-through mode
            isPassThrough = isPassThroughEnabled(window)
            
            # Toggle the state using setPassThroughMode
            setPassThroughMode(window, not isPassThrough)
        
            # To turn it off, you have to call the function twice
            if isPassThrough:
                setPassThroughMode(window, not isPassThrough)
        
        

        I have to call it twice to turn these flags off also, not sure why that is.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved