PySide로 Drop Indicator를 독자적으로 그리기(흑마술로 QProxyStyle을 실현한다)
독자적으로 그려 Indicator를 눈에 띄게 하고 싶다.
그러나 일은 간단하지 않으며 StyleSheet에는 Drop Indicator 설정이 없습니다.
Qt로 Drop Indicator를 독자적으로 그리려면 QProxyStyle을 사용하지만 PySide 및 PyQt에서는 QProxyStyle이 존재하지 않는 것이다.
그래서 PySide를 Hack하여 Drop Indicator의 묘화를 횡단한다.
덧붙여 이 방법은 정당한 방법이 아닌 흑마술이다, 미래의 PySide에서도 유효한지는 보증할 수 없다.
우선은 정당한 방법으로 그리기를 가로 채어 보자.
합법적인 방법: 자신만의 스타일 만들기
우선은 정당한 방법을 생각하자.
스스로 QStyle 클래스를 상속해, QStyle::drawPrimitive 메소드를 오버라이드(override) 하는 방법이다.
내 환경은 Windows이므로 QWindowsStyle을 상속합니다.
class MyWindowsStyle(QWindowsStyle):
def drawPrimitive(self, element, option, painter, widget):
if element == QStyle.PE_IndicatorItemViewItemDrop:
pen = QPen(Qt.red)
pen.setWidth(2)
painter.setPen(pen)
if not option.rect.isNull():
painter.drawRect(option.rect)
return
super(MyWindowsStyle, self).drawPrimitive(element, option, painter, widget)
위의 예에서는 Drop Indicator를 빨강으로 하고 테두리를 두껍게 하고 있다.
이 스타일 클래스를 QApplication::setStyle로 설정한다.
my_style = MyWindowsStyle(parent_widget)
QApplication.setStyle(my_style)
잘 된 것 같지만, 외형이 전체적으로 옛 냄새가 났다.
Windows 버전의 PySide(Qt)에서는 표준 스타일은 QWindowStyle이 아니라 QWindowsVistaStyle이 적용된다.
그러나 QWindowsVistaStyle은 동적으로 로드되는 Plugin 스타일이기 때문에 클래스 상속을 할 수 없는 것이다.
또 특정의 스타일 클래스를 계승해 버리기 위해(때문에), Mac나 Linux에서도 같은 룩&필이 되어 버린다.
이러한 단점이 신경 쓰이지 않는다면이 방법을 권장합니다.
그렇다면 검은 마술을 사용하여 QWindowsVistaStyle의 드로잉을 가로 채어 보자.
QWindowsVistaStyle의 인스턴스 생성
우선은 QWindowsVistaStyle 인스턴스의 생성이다.
스타일의 생성에는 QStyleFactory 클래스를 사용한다.
vista_style = QStyleFactory.create("windowsvista")
이제 QWindowsVistaStyle 인스턴스가 생성되었습니다.
덧붙여서 각 환경의 표준 스타일 클래스와 키명(QStyleFactory.create에 건네주는 캐릭터 라인)을 조사하는 것은 이하와 같이 한다.
QApplication.style().metaObject().className()
>>> QWindowsVistaStyle
QApplication.style().objectName()
>>> windowsvista
인스턴스의 프록시 클래스 만들기
스타일 인스턴스를 포괄하는 Proxy 클래스를 만듭니다.
class ProxyStyle(QCommonStyle):
TranslateMethods = [
'drawComplexControl', 'drawControl', 'drawItemText', 'generatedIconPixmap',
'hitTestComplexControl', 'pixelMetric', 'polish', 'sizeFromContents',
'sizeFromContents', 'standardPixmap', 'styleHint', 'styleHint',
'subControlRect', 'subElementRect', 'unpolish'
]
def __init__(self, style, parent=None):
super(ProxyStyle, self).__init__(parent)
self._style = style
for method_name in self.TranslateMethods:
setattr(self, method_name, getattr(self._style, method_name))
def drawPrimitive(self, element, option, painter, widget):
if element == QStyle.PE_IndicatorItemViewItemDrop:
pen = QPen(Qt.red)
pen.setWidth(2)
painter.setPen(pen)
if not option.rect.isNull():
painter.drawRect(option.rect)
return
self._style.drawPrimitive(element, option, painter, widget)
봐주면 알겠지만, 강인하고 진흙스러운 방법으로 위양을 하고 있다.
덧붙여서 PySide 객체는
__getattr__
에 의한 위양 트릭은 사용할 수 없다.강한 검은 마술로 QProxyStyle을 구현하고 있다.
이 클래스에서 스타일 인스턴스를 동적으로 프록시하여 QApplication에 스타일로 정의합니다.
proxy_style = ProxyStyle(vista_style)
QApplication.setStyle(proxy_style)
잘 된 것 같다.
아래와 같이 StyleSheet를 병용해 배경을 회색으로 해도 문제 없게 동작하고 있다.
tree_view.setStyleSheet("QTreeView { background-color: gray }")
요약
이 방법은 전혀 우아하지 않습니다.
View의 paintEvent를 오버라이드(override) 해, 스스로 모두 draw 하는 방법도 있지만, View의 종류마다 draw를 바꿀 필요가 있어 매우 귀찮다.
가능하면 스타일 설정으로 극복하고 싶은 곳이다.
더 좋은 방법이 있으면, 꼭 교수 바랍니다.
Reference
이 문제에 관하여(PySide로 Drop Indicator를 독자적으로 그리기(흑마술로 QProxyStyle을 실현한다)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://qiita.com/pashango2/items/c368f07bdce4b780124c텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)