#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_())