Получить QColor в произвольном положении в диапазоне 0-1 QGradientC++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 Получить QColor в произвольном положении в диапазоне 0-1 QGradient

Сообщение Anonymous »

Objective
Я хочу получить цвет Visual в произвольной позиции в 0,0 - Диапазон любого данного QGradient.
Это может потребоваться для правильного вычисления новых промежуточных остановок между существующими или для получения цвета в определенной точке, чтобы использовать его в качестве ссылки на отображение в градиенте. which seemed reasonable.
Gradients can have many colors set at different points, which can be set by using QVariantAnimation.setKeyValueAt().
They also can have no 0.0 or 1.0 stops, meaning that if, for example, the first stop is at 0.2 and the last is at 0.8, the start и конечные значения анимации должны быть установлены также с относительным первым и последним цветом.
Моя первоначальная попытка состояла в том, чтобы создать временную анимацию, а затем установить его значения ключей на основе градиентных остановок: использование setcurrenttime () на основе компьютерной позиции в продолжительности анимации () позволяет получить код. Реализация: < /p>
Обратите внимание, что я не могу написать код C ++, поэтому я предоставлю код на основе Python для следующих примеров. Ответы на основе C ++ также будут хорошо приняты, хотя.

Код: Выделить всё

def gradientColorAt(grad, pos):
if pos = 1:
return grad.stops()[-1][1]
ani = QVariantAnimation()
ani.setDuration(1000)
startDone = False
for stop, color in grad.stops():
if not startDone:
startDone = True
ani.setStartValue(color)
if not stop:
continue
ani.setKeyValueAt(stop, color)
if stop < 1:
ani.setEndValue(color)
ani.setCurrentTime(round(1000 * pos))
return ani.currentValue()

выше , по -видимому, работает нормально, если все цвета полностью непрозрачны. Позже я понял, что аналогичный пост также предложил аналогичный подход в некоторых его ответах. /> qt, по -видимому, следует конвенции, также используемой в современных веб -браузерах, для которых переходы между цветами не строго следуют линейным значениям в своих компонентах (красный, зеленый, синий и альфа), а также рассматривают «прозрачный» цвет, основанный на возможном переходе к другому цвету, и даже если концепция прозрачного < /code> на самом деле является «транспрессовым черным». Qcolor (qt.transparent) is ровно qcolor (0, 0, 0, 0) . Несмотря на то, что Qcolor (255, 0, 0, 0) будет иметь одинаковый результат для целей градиентов как в qt , так и общих браузерах, это не один и тот же цвет.
рассматривает следующий пример:
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *

app = QApplication([])

win = QWidget()
lay = QVBoxLayout(win)

grad = QLinearGradient(0, 0, 1, 0)
grad.setCoordinateMode(grad.ObjectBoundingMode)
grad.setColorAt(1, Qt.green)

transBlack = QColor(Qt.transparent)
transRed = QColor(255, 0, 0, 0)
pal = app.palette()

for color in (transBlack, transRed):
grad.setColorAt(0, color)
pal.setBrush(QPalette.Window, QBrush(grad))
widget = QWidget()
widget.setAutoFillBackground(True)
widget.setPalette(pal)
lay.addWidget(widget)

win.resize(400, 400)
win.show()

app.exec()

И вот результат:

Предлагает аналогичные узор (такие that.
Nonetheless, the issue is that the above QVariantAnimation attempt does not follow the same pattern, as it simply uses an internal interpolator that linearly evaluates all color components.
Let's add the gradientColorAt() function to the above code, along with the following class:

Код: Выделить всё

class GradientViewer(QWidget):
def __init__(self, gradient):
super().__init__()
self.gradient = QLinearGradient(gradient)

def paintEvent(self, event):
qp = QPainter(self)
width = self.width()
height = self.height()
for x in range(width + 1):
qp.setPen(gradientColorAt(self.gradient, x / width))
qp.drawLine(x, 0, x, height)
< /code>
Затем добавьте соответствующие экземпляры в макет с использованием тех же градиентов: < /p>
...
# replace the above for loop
for color in (transBlack, transRed):
grad.setColorAt(0, color)
pal.setBrush(QPalette.Window, QBrush(grad))
widget = QWidget()
widget.setAutoFillBackground(True)
widget.setPalette(pal)
lay.addWidget(widget)
# custom widget using the same gradient
lay.addWidget(GradientViewer(grad))
...
и вот результат:

. Источники, которые выглядели многообещающими: механизм Raster Painting имеет функцию GenerateGradientColartable () (см. Это в браузере кода), которая, по -видимому, используется для создания растрового кэша, основанного на арбитральном размере цветовых интерполяций в градиенте. Qvariantanimation Подкласс, основанный на этом коде: < /p>

Код: Выделить всё

class QColorInterpolator(QVariantAnimation):
def interpolated(self, c1, c2, pos):
if pos = 1:
return c2
first = c1.rgba64()
first = QRgba64.fromRgba64(
first.red(), first.green(), first.blue(), (first.alpha() * 256) >> 8
).premultiplied()
second = c2.rgba64()
second = QRgba64.fromRgba64(
second.red(), second.green(), second.blue(), (second.alpha() * 256) >> 8
).premultiplied()
r1 = first.red()  16,
)
< /code>
 Очевидно, что приведенный выше класс на самом деле не нужен, так как интерполяция может быть достигнута с помощью относительных шагов между остановками. Единственным преимуществом является возможность использования интерполированного () 
, который всегда будет использовать диапазон 0-1 между кадрами ключей. It may not be completely efficient, but results in a cleaner code.
Unfortunately, my limited understanding of color composition and alpha premultiplication seem to show its problems: replacing QVariantAnimation with QColorInterpolator in the above gradientColorAt() function will give exactly the same result as in using QT.TransParent .
Рабочее решение, не совсем эффективное
Прямо сейчас единственное рабочее решение, которое я выпустил, - это использовать внутренний кэш Qimages, каждый из которых соответствует возможным промежуточным градиентам (каждая диапазон между существующими остановками), покраски на его градиент, и затем использует Qimage's Pilescolor (Feekercolor). вычисленной позиции: < /p>

Код: Выделить всё

class QColorInterpolator(QVariantAnimation):
_imageCache = {}
def _createCacheGradient(self, c1, c2):
g = QLinearGradient(0, 0, 1024, 0)
g.setStops([(0, c1), (1, c2)])
image = QImage(1024, 1, QImage.Format_ARGB32)
image.fill(Qt.transparent)
qp = QPainter(image)
qp.fillRect(image.rect(), g)
qp.end()
return image

def interpolated(self, c1, c2, pos):
if pos = 1:
return c2
if c1 == c2:
return c1
key = c1.rgba64(), c2.rgba64()
if key in self._imageCache:
gradImg = self._imageCache[key]
else:
self._imageCache[key] = gradImg = self._createCacheGradient(c1, c2)
return gradImg.pixelColor(round(1023 * pos), 0)
заменить QcolorinterPolator на новую класс работает, как и ожидалось:

/> Хотя последняя попытка работает как ожидалось, мне это не очень нравится, по следующим причинам: < /p>
  • Насколько я могу понять, QT уже создает внутренний кэш «цветовой таблицы», и, хотя он, очевидно, не может быть извне, создание разделенных Qimages не очень эффективно; предполагал один, основанный на данных пикселей Qimage;
  • Из -за всего вышеперечисленного, любые временные вычисления промежуточных цветов потребуются для создания Qvariantanimation, которую я бы предпочел избегать;
, следовательно, есть, следовательно, что (и почему (и почему) может быть (и почему) может быть (и почему) может быть (и почему) может (и почему (и почему). Предоставьте правильные значения цвета , как используется в визуально окрашенном градиенте с помощью QT? Похоже, что QGradient/Qbrush позволяет устанавливать два разных типа интерполяции (

Код: Выделить всё

ColorInterpolation
и componentinterpolation ): в чем разница? Приводит ли что -нибудь из этого к тому, что на самом деле делает линейные вычисления, используемые Qvariantanimation? Можно ли получить противоположное поведение , только после линейного вычисления?

Подробнее здесь: https://stackoverflow.com/questions/795 ... -qgradient
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»