QSS не применен к первому QSizeGrip в (составной виджет) в QVBoxLayout

#python #pyside #qtstylesheets #pyside2

#python #pyside #qtstylesheets #pyside2

Вопрос:

Как показано ниже, виджет TestWidget содержит QFrame и CSS-стилизованный QSizeGrip . Несколько TestWidget экземпляров помещены в QVBoxLayout

 from PySide import QtGui, QtCore
import sys

class TestWidget(QtGui.QWidget):
    def __init__(self , parent=None):
        super(TestWidget , self).__init__(parent)

        layout = QtGui.QVBoxLayout()
        layout.setContentsMargins( 0 , 0 , 0 , 0 )

        frame = QtGui.QFrame()
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setMinimumHeight( 100 )

        grip = QtGui.QSizeGrip(self)
        grip.setStyleSheet( "QSizeGrip { image: url(dots.png); }")
        grip.setCursor(QtCore.Qt.SplitVCursor)

        layout.addWidget(frame)
        layout.addWidget( grip , 0 , QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight )

        self.setLayout(layout)

class TestApp(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(TestApp, self).__init__(parent)

        track1 = TestWidget()
        track2 = TestWidget()
        track3 = TestWidget()

        centralWidget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(centralWidget)

        layout.addWidget(track1)
        layout.addWidget(track2)
        layout.addWidget(track3)

        self.setCentralWidget(centralWidget)
        self.show() 

if __name__=="__main__":
    app=QtGui.QApplication(sys.argv)
    myapp = TestApp();
    sys.exit(app.exec_())   
  

Как показано ниже, указатель размера первого TestWidget в QVBoxLayout появляется, только если TestWidget это единственный элемент в макете.

введите описание изображения здесь
введите описание изображения здесь
введите описание изображения здесь

Версия Qt 4.8.7

Версия PySide 1.2.2


Версия программы PySide2 (ниже) имеет ту же проблему

 from PySide2 import QtCore
from PySide2.QtWidgets import QApplication, QWidget , QMainWindow , QGraphicsView , QVBoxLayout , QFrame , QSizeGrip , QWidget

import sys

class TestWidget(QWidget):
    def __init__(self , parent=None):
        super(TestWidget , self).__init__(parent)

        layout = QVBoxLayout()
        layout.setContentsMargins( 0 , 0 , 0 , 0 )

        frame = QFrame()
        frame.setFrameShape(QFrame.StyledPanel)
        frame.setMinimumHeight( 100 )

        grip = QSizeGrip(self)
        grip.setStyleSheet( "QSizeGrip { image: url(dots.png); }")
        grip.setCursor(QtCore.Qt.SplitVCursor)

        layout.addWidget(frame)
        layout.addWidget( grip , 0 , QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight )

        self.setLayout(layout)

class TestApp(QMainWindow):
    def __init__(self, parent=None):
        super(TestApp, self).__init__(parent)

        track1 = TestWidget()
        track2 = TestWidget()
        track3 = TestWidget()

        centralWidget = QWidget()
        layout = QVBoxLayout(centralWidget)

        layout.addWidget(track1)
        layout.addWidget(track2)
        layout.addWidget(track3)

        self.setCentralWidget(centralWidget)
        self.show() 

if __name__=="__main__":
    app = QApplication(sys.argv)
    myapp = TestApp();
    sys.exit(app.exec_())   
  

Версия PySide2 5.12.1

Комментарии:

1. @eyllanesc Извините, я был завален в последнее время. Кстати, я сообщил об этом как об ошибке PySide / PySide2 bugreports.qt.io/browse/PYSIDE-978

2. Но это не ошибка, ошибка в том, что поведение не документировано

3. @eyllanesc Я понимаю, что ты имеешь в виду. Поведение запрограммировано для, но ИМО это нарушает принцип наименьшего удивления

4. Хорошо, согласно этому принципу отчет должен быть в Qt, а не в PySide2. 🙂

5. Эта проблема была помечена как ошибка Qt.

Ответ №1:

То, что наблюдается, является предопределенным поведением, но не документировано, если исходный код будет пересмотрен, это будет наблюдаться:

 Qt::Corner QSizeGripPrivate::corner() const
{
    Q_Q(const QSizeGrip);
    QWidget *tlw = qt_sizegrip_topLevelWidget(const_cast<QSizeGrip *>(q));
    const QPoint sizeGripPos = q->mapTo(tlw, QPoint(0, 0));
    bool isAtBottom = sizeGripPos.y() >= tlw->height() / 2;
    bool isAtLeft = sizeGripPos.x() <= tlw->width() / 2;
    if (isAtLeft)
        return isAtBottom ? Qt::BottomLeftCorner : Qt::TopLeftCorner;
    else
        return isAtBottom ? Qt::BottomRightCorner : Qt::TopRightCorner;
}
  

Где замечено, что sizeGrip размещается в верхней части, если он находится в верхней части окна, и это является причиной поведения, которое он наблюдает.

Обходной путь заключается в перезаписи метода paintEvent в QSizeGrip:

PySide2:

 import sys
from PySide2 import QtCore, QtGui, QtWidgets

class SizeGrip(QtWidgets.QSizeGrip):
    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        opt = QtWidgets.QStyleOptionSizeGrip()
        opt.initFrom(self)
        opt.corner = QtCore.Qt.BottomRightCorner
        self.style().drawControl(QtWidgets.QStyle.CE_SizeGrip, opt, painter, self)

class TestWidget(QtWidgets.QWidget):
    def __init__(self , parent=None):
        super(TestWidget , self).__init__(parent)
        layout = QtWidgets.QVBoxLayout(self)
        layout.setContentsMargins( 0 , 0 , 0 , 0 )
        frame = QtWidgets.QFrame()
        frame.setFrameShape(QtWidgets.QFrame.StyledPanel)
        frame.setMinimumHeight( 100 )
        grip = SizeGrip(self)
        grip.setStyleSheet('''QSizeGrip { 
            image: url(dots.png);
        }''')
        layout.addWidget(frame)
        layout.addWidget(grip , 0 , QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight )

class TestApp(QtWidgets.QMainWindow):
    def __init__(self, parent=None):
        super(TestApp, self).__init__(parent)
        centralWidget = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout(centralWidget)
        for _ in range(3):
            layout.addWidget(TestWidget())
        self.setCentralWidget(centralWidget)
        self.show()

if __name__=="__main__":
    app = QtWidgets.QApplication(sys.argv)
    myapp = TestApp();
    sys.exit(app.exec_())   
  

PySide:

 import sys
from PySide import QtCore, QtGui

class SizeGrip(QtGui.QSizeGrip):
    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        opt = QtGui.QStyleOptionSizeGrip()
        opt.initFrom(self)
        opt.corner = QtCore.Qt.BottomRightCorner
        self.style().drawControl(QtGui.QStyle.CE_SizeGrip, opt, painter, self)

class TestWidget(QtGui.QWidget):
    def __init__(self , parent=None):
        super(TestWidget , self).__init__(parent)
        layout = QtGui.QVBoxLayout(self)
        layout.setContentsMargins( 0 , 0 , 0 , 0 )
        frame = QtGui.QFrame()
        frame.setFrameShape(QtGui.QFrame.StyledPanel)
        frame.setMinimumHeight( 100 )
        grip = SizeGrip(self)
        grip.setStyleSheet('''QSizeGrip { 
            image: url(dots.png);
        }''')
        grip.setCursor(QtCore.Qt.SplitVCursor)
        layout.addWidget(frame)
        layout.addWidget(grip , 0 , QtCore.Qt.AlignBottom | QtCore.Qt.AlignRight )

class TestApp(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(TestApp, self).__init__(parent)
        centralWidget = QtGui.QWidget()
        layout = QtGui.QVBoxLayout(centralWidget)
        for _ in range(3):
            layout.addWidget(TestWidget())
        self.setCentralWidget(centralWidget)
        self.show()

if __name__=="__main__":
    app = QtGui.QApplication(sys.argv)
    myapp = TestApp();
    sys.exit(app.exec_())   
  

введите описание изображения здесь