PySide: QPushButton stays highlighted after pressi

2019-07-21 04:29发布

问题:

In my tool, when the user pushes a button a popup window is created. My issue is that the button that the user presses to bring up the window stays highlighted (as if I have my mouse over it) on popup creation and remains that way even after the popup is deleted. I actually like this highlight while the popup is active (it visually connects the window to the popup which is nice), but I'd like it to go away when the window is deleted.

Below is an example to clarify what's happening:

If I click on create asset, then click on minor save the create asset button stays highlighted

CODE:

from PySide import QtCore, QtGui
import maya.OpenMayaUI as mui
from shiboken import wrapInstance 

def get_parent():
    ptr = mui.MQtUtil.mainWindow()
    return wrapInstance( long( ptr ), QtGui.QWidget )

############################################
class Tool_Window(QtGui.QDialog):
    def __init__(self, parent = get_parent() ):
        super(Tool_Window, self).__init__(parent)

        # Commands
        self.create_gui()
        self.create_layout()
        self.create_connections()

    #-------------------------------------------
    def create_gui(self):
        self.button1 = Push_Buttons()
        self.button1.setMaximumWidth(50)
        self.button2 = Push_Buttons()
        self.button2.setMaximumWidth(50)

    #-------------------------------------------
    def create_layout(self):
        layout = QtGui.QVBoxLayout()
        layout.addWidget(self.button1)
        layout.addWidget(self.button2)
        blank_layout = QtGui.QVBoxLayout()
        main_layout = QtGui.QHBoxLayout( self )
        main_layout.addLayout(blank_layout)
        main_layout.addLayout(layout)
        self.setLayout(layout)

    #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
    def create_connections(self):
        # Left click
        self.button1.clicked.connect( self.on_left_click )
        self.button2.clicked.connect( self.on_left_click )

    #-----#-----#-----#-----#-----#-----#-----#-----#-----#    
    def on_left_click(self):

        button = self.sender()

        self.popup = Popup_Window( self, button )                   
        self.popup.show()

############################################
class Push_Buttons( QtGui.QPushButton ):
    def __init__( self ):
        super( Push_Buttons, self ).__init__()

        self.setFocusPolicy(QtCore.Qt.NoFocus)

############################################
class Popup_Window( QtGui.QWidget ):
    def __init__( self, parent, button ):
        super( Popup_Window, self ).__init__(parent)

        self.setWindowFlags(QtCore.Qt.Popup)

        self.button_pos = button       
        self.parent = parent  

        self.setAttribute( QtCore.Qt.WA_DeleteOnClose )
        self.resize(230, 100)

        self.installEventFilter(self)

        self.create_gui()
        self.create_layout()
        self.create_connections()
        self.move_UI()   
        self.line_edit.setFocus()     

    #-------------------------------------------
    def create_gui( self ):
        ''' Visible GUI stuff '''
        self.my_label = QtGui.QLabel("default text")
        self.line_edit = QtGui.QLineEdit()
        self.line_edit.setMaxLength( 30 )
        self.push_btn = QtGui.QPushButton( "push" )
        self.push_btn.setMaximumWidth( 30 )

    #-------------------------------------------
    def create_layout( self ):

        self.button_layout = QtGui.QVBoxLayout()

        self.button_layout.addWidget( self.my_label, 0, 0 )
        self.button_layout.addWidget( self.line_edit, 1, 0 )
        self.button_layout.addWidget( self.push_btn, 2, 0 )

        self.setLayout(self.button_layout)

    #-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#
    def create_connections( self ):

        self.line_edit.textChanged.connect( self.on_text_changed )

    #-----#-----#-----#-----#-----#-----#-----#-----#-----#
    def on_text_changed( self, text ): 

        #---- set the text in label ----
        typed_name = self.line_edit.text()
        if " " in typed_name:
            typed_name.replace(" ", "")
        self.my_label.setText(typed_name) 

    #-------------------------------------------  
    def  eventFilter(self, source, event):

        if event.type() == QtCore.QEvent.WindowDeactivate:
            self.close()
        return QtGui.QWidget.eventFilter(self, source, event)

    #-------------------------------------------
    def move_UI( self ):
        self.line_edit.setFocus()
        y_btn = self.button_pos.mapToGlobal(QtCore.QPoint(0,0)).y()  
        x_win = self.parent.mapToGlobal(QtCore.QPoint(0,0)).x()

        w_pop = self.frameGeometry().width()

        x = x_win - w_pop - 12
        y = y_btn

        self.move(QtCore.QPoint(x,y))

############################################
if __name__ == '__main__':
    # Things to fix PySide Maya bug
    try:
        test_ui.close()
        test_ui.deleteLater()
    except:
        pass

    test_ui = Tool_Window()
    test_ui.show()

    try:
        test_ui.show()
    except:
        test_ui.close()
        test_ui.deleteLater()

回答1:

I was not able to reproduce your issue when the focus policy was set to the default value on both Windows 7 and Ubuntu (QtCore.Qt.FocusPolicy.StrongFocus). However, it was on both system after I've set the focus policy of the buttons to QtCore.Qt.FocusPolicy.NoFocus.

To solve this issue, I suggest, for the moment, to force a repaint of the Tool_Window instance, from the eventFilter method of the Popup_Window, when a close event is registered, as shown below:

def  eventFilter(self, source, event):

    if event.type() == QtCore.QEvent.WindowDeactivate:
        self.close()
    elif event.type() == QtCore.QEvent.Close:
        self.parent.repaint()
    return QtGui.QWidget.eventFilter(self, source, event)

It has solved the problem on both Windows7 and Ubuntu for me when the focus policity of the button was set to QtCore.Qt.FocusPolicy.NoFocus. I may investigate further to better understand what is going on, I'll keep you posted.

side note : I am not testing your code with OpenMayaUI, so maybe that is why I do not get the issue by default, but only after I explicitly set the focus policy of the buttons to NoFocus. Maybe OpenMayaUI force your buttons to have a NoFocus policy by default. It can be also because of differences between our OS and theme.



回答2:

I ran into this as well, on Maya 2018. I'm thinking it may be a Maya thing? I eventually ended up just rewriting the mouse click event, as the mouse click + release event - so that it never really enters the depressed state:

    def mousePressEvent(self, event):
        super(DragButton, self).mouseReleaseEvent(event)

Things I had also tried:

QPushButton().setDown(False)
QPushButton().setChecked(False)
QPushButton().setPressed(False)

QPushButton().setFocusPolicy(QtCore.Qt.NoFocus)
QPushButton().setFocusPolicy(QtCore.Qt.StrongFocus)

QPushButton().viewport().update()

event.accept()

QtCore.QTimer.singleShot(
    100, lambda: self.setFocusPolicy(QtCore.Qt.NoFocus)
)

QtCore.QTimer.singleShot(100, lambda: self.setDown(False))
super(DragButton, self).mousePressEvent(event)

No matter whatever I try, what I get is shown below, where the black buttons have been permanently depressed after a click + drag, although they're fine if I single click them:



回答3:

For some reason the highlight seems to remain when your Popup_Window class uses self.setWindowFlags(QtCore.Qt.Popup).

Instead you can remove that line and make Popup_Window class inherit from QDialog. Now the highlight won't remain when the new window appears. Though your original behavior was that you could only interact with the popup window when it's shown, so to achieve the same thing just call self.popup.exec_() instead of self.popup.show() to make it modal.

Now we have it working like it was without the button 'sticking' to a highlighted state.