Рисование 3D-прямоугольника/многоугольника с эффектом подъема и опускания в PyQt

В Java вы можете рисовать трехмерные прямоугольники, используя (см. https://way2java.com/awt-graphics/4891/):

void fill3DRect(int x, int y, int width, int height, boolean raised)

Здесь последний параметр «raised» используется для опускания/поднятия 3D-прямоугольника по отношению к поверхности рисования.

Как я могу добиться этого эффекта в PyQt?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
966
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Насколько мне известно, в PyQt нет встроенного виджета/функции 3D-рисования, поскольку вы можете рисовать только 2D-полигоны. Но мы можем создать собственный класс для имитации 3D-рисования. Из вашего ссылка, связанного с Java:

Java supports 3D rectangles but the effect of third dimension is not very visible. As the elevation is less, the effect is negligible. Java designers gave the effect of 3D by drawing lighter and darker lines along the rectangle border.

Мы можем подражать эффект 3D-функции рисования Java:

void fill3DRect(int x, int y, int width, int height, boolean raised)

This method draws a solid 3D rectangle with the above specified parameters. The last boolean parameter true indicates elevation above the drawing surface and false indicates etching into the surface.

Чтобы получить 3D-эффект в Python, мы можем сделать то же самое, используя два оттенка цвета, затем затемняя и освещая некоторые стороны.

Example pic

from PyQt5 import QtCore, QtGui, QtWidgets
import sys

class Rectangle3D(QtWidgets.QWidget):
    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)

        # Elevated 3D rectangle color settings
        self.elevated_border_color = QtGui.QColor(111,211,111)
        self.elevated_fill_color = QtGui.QColor(0,255,0)
        self.elevated_pen_width = 2.5

        # Lowered 3D rectangle color settings
        self.lowered_border_color = QtGui.QColor(0,235,0)
        self.lowered_fill_color = QtGui.QColor(0,178,0)
        self.lowered_pen_width = 2.5

    def draw3DRectangle(self, x, y, w, h, raised=True):
        # Specify the border/fill colors depending on raised or lowered
        if raised:
            # Line color (border)
            self.pen = QtGui.QPen(self.elevated_border_color, self.elevated_pen_width)
            # Fill color
            self.fill = QtGui.QBrush(self.elevated_fill_color)
        else:
            # Line color (border)
            self.pen = QtGui.QPen(self.lowered_border_color, self.lowered_pen_width)
            # Fill color
            self.fill = QtGui.QBrush(self.lowered_fill_color)

        painter = QtGui.QPainter(self)

        # Draw border color of rectangle
        painter.setPen(self.pen)
        painter.setBrush(self.fill)  
        painter.drawRect(x, y, w, h)

        # Cover up the top and left sides with filled color using lines
        if raised:
            painter.setPen(QtGui.QPen(self.elevated_fill_color, self.elevated_pen_width))
        else:
            painter.setPen(QtGui.QPen(self.lowered_fill_color, self.lowered_pen_width))

        painter.drawLine(x, y, x + w, y) 
        painter.drawLine(x, y, x, y + h)

    def paintEvent(self, event):
        self.draw3DRectangle(50,50,300,150,True)
        self.draw3DRectangle(50,250,300,150,False)

if __name__ == '__main__':
    app = QtWidgets.QApplication(sys.argv) 

    widget = Rectangle3D()
    widget.show()

    sys.exit(app.exec_())

Это зависит от того, какой уровень краски вы хотите использовать:

Есть 2 варианта:

  • Использование QPainter:

Этого эффекта можно добиться, нарисовав 2 смещенных прямоугольника, где цвет фонового прямоугольника темнее, чем цвет переднего:

from PyQt5 import QtCore, QtGui, QtWidgets


def draw3DRect(painter, rect, color, raised=False, offset=QtCore.QPoint(4, 4)):
    if raised:
        painter.fillRect(rect.translated(offset), color.darker())
    painter.fillRect(rect, color)


class Widget(QtWidgets.QWidget):
    def paintEvent(self, event):
        painter = QtGui.QPainter(self)
        r = QtCore.QRect(
            self.width() / 4,
            self.height() / 4,
            self.width() / 2,
            self.height() / 2,
        )
        draw3DRect(painter, r, QtGui.QColor("green"), raised=True)

    def sizeHint(self):
        return QtCore.QSize(320, 240)


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = Widget()
    w.show()
    sys.exit(app.exec_())

  • Использование QGraphicsDropShadowEffect:

В этом случае QWidget и QGraphicsItem поддерживают этот эффект:

from PyQt5 import QtCore, QtGui, QtWidgets


if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)
    w = QtWidgets.QWidget()
    lay = QtWidgets.QHBoxLayout(w)
    scene = QtWidgets.QGraphicsScene()
    view = QtWidgets.QGraphicsView(scene)
    rect_item = QtWidgets.QGraphicsRectItem(QtCore.QRectF(0, 0, 200, 100))
    rect_item.setBrush(QtGui.QColor("green"))
    effect_item = QtWidgets.QGraphicsDropShadowEffect(
        offset=QtCore.QPointF(3, 3), blurRadius=5
    )
    rect_item.setGraphicsEffect(effect_item)
    scene.addItem(rect_item)

    rect_widget = QtWidgets.QWidget()
    rect_widget.setFixedSize(320, 240)
    rect_widget.setStyleSheet("background-color:green;")
    effect_widget = QtWidgets.QGraphicsDropShadowEffect(
        offset=QtCore.QPointF(3, 3), blurRadius=5
    )
    rect_widget.setGraphicsEffect(effect_widget)

    lay.addWidget(view)
    lay.addWidget(rect_widget)
    w.resize(640, 480)
    w.show()
    sys.exit(app.exec_())

Другие вопросы по теме