QLineGradient ровные границы между цветами
Задача состоит в том, чтобы во всех item's, которые находятся в первой колонке QTreeWidget закрасить background, но не просто одним цветом, а должно быть закрашено 40% ширины item'a одним цветом, другие 60% другим и еще не большое условие, границы между цветами, должны быть ровными, без размытия, эффекта смешивания цветов. Пробую так:
self.treeWidget = QTreeWidget()
self.treeWidget.setColumnCount(3)
self.treeWidget.setHeaderLabels(['1', '2', '3'])
self.treeWidget.addTopLevelItem(QTreeWidgetItem(['item1', 'item2', 'item3']))
grad = QLinearGradient(QPointF(0, 0),QPointF(self.treeWidget.columnWidth(0), 0))
grad.setStops([(0.4, QColor(255, 0, 0)),(0.41, QColor(0, 255, 0)),])
grad.setCoordinateMode(QLinearGradient.CoordinateMode.ObjectBoundingMode)
self.treeWidget.topLevelItem(0).setBackground(0, grad)
Собственно получается ерунда, как сделать правильно? Может лучше использовать другой способ? Какой?
Ответы (2 шт):
градиент как бы градиент и задаст :) Тут надо немного сложнее. Отрисовывать фон самостоятельно, перегружая QTreeWidget::drawRow
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QBrush, QColor
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QGridLayout, QWidget
from PyQt5.QtCore import QSize, QRect
# Нам нужен свой "кастомный" виджет, в котором перегрузим отрисовку строки
class MyTreeWidget(QTreeWidget):
def drawRow(self, painter, option, index): # Перегружаем отрисовку строки
if index.column() == 0: # фон меняем только для первого столбца
rect = self.visualRect(index) # узнаем геометрическое расположение ячейки
corner = rect.width() * 0.6 # вычисляем ширину по которой будут разделяться цвета
rect1 = QRect(rect.left(), rect.top(), corner, rect.height()) # прямоугольник для первого цвета
rect2 = QRect(rect.left() + corner, rect.top(), rect.width() - corner, rect.height()) # то же самое для второго
# отрисовываем фон
painter.save()
brush = QBrush(QColor(255, 0, 0))
painter.fillRect(rect1, brush)
brush = QBrush(QColor(0, 255, 0))
painter.fillRect(rect2, brush)
painter.restore()
super(QTreeWidget, self).drawRow(painter, option, index) # дальнейшей отрисовкой занимается оригинальный QTreeWidget::drawRow
class MainWindow(QMainWindow):
def __init__(self):
QMainWindow.__init__(self)
self.setMinimumSize(QSize(400, 400))
central_widget = QWidget(self)
self.setCentralWidget(central_widget)
grid_layout = QGridLayout()
self.treeWidget = MyTreeWidget()
self.treeWidget.setColumnCount(3)
self.treeWidget.setHeaderLabels(['1', '2', '3'])
self.treeWidget.addTopLevelItem(QTreeWidgetItem(['myitem11', 'item12', 'item13']))
self.treeWidget.addTopLevelItem(QTreeWidgetItem(['item21', 'item22', 'item23']))
central_widget.setLayout(grid_layout)
grid_layout.addWidget(self.treeWidget, 0, 0)
if __name__ == "__main__":
app = QApplication(sys.argv)
mw = MainWindow()
mw.show()
sys.exit(app.exec())
Сразу стоит отметить что можно конечно фон отрисовать используя обычный QTrwwWidgetItem::setBackground(column, brush), но такой фон не будет никак реагировать на изменение размера ячеек
Дело было в координатном пространстве, от которого рассчитывается ширина градиента, просто нужно было перевести в логический мод:
grad = QLinearGradient(QPointF(0, 0), QPointF(self.treeWidget.columnWidth(2), 0))
stop1 = round(itemListSell[i]['total'] / maxSellOrder, 2)
stop2 = stop1 + 0.01
grad.setStops([(stop1, QColor(255, 0, 0)),(stop2, QColor(0, 255, 0)),]) grad.setCoordinateMode(QLinearGradient.CoordinateMode.LogicalMode)
И теперь QLinearGradient.CoordinateMode.LogicalMode, берет координаты с ширины столбца, в реальных размерах, а не (x1: 0, x2: 0 y1: 1, y2: 1)
И да, чтобы границы градиента были четкие и ровные, без размытия - нужно использовать минимальные границы между переходов цветов, у меня они прописаны в переменных stop1 и stop2