В Java вы можете рисовать трехмерные прямоугольники, используя (см. https://way2java.com/awt-graphics/4891/):
void fill3DRect(int x, int y, int width, int height, boolean raised)
Здесь последний параметр «raised» используется для опускания/поднятия 3D-прямоугольника по отношению к поверхности рисования.
Как я могу добиться этого эффекта в PyQt?
Насколько мне известно, в 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, мы можем сделать то же самое, используя два оттенка цвета, затем затемняя и освещая некоторые стороны.
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 варианта:
Этого эффекта можно добиться, нарисовав 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_())
В этом случае 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_())