Spatial 透视视图
SpatialItem 空间项
设置 SpatialView 中单个控件的位置、旋转和缩放。
示例

用法
调整卡片姿态
SpatialView::addWidget() 返回的 SpatialItem 控制这张卡片;调整它不会影响其他卡片。
#include <FluentQt/Spatial.h>
using namespace fluent::spatial;
using namespace fluent;
// Keep the control card independent of the card it adjusts.
class WorkbenchView final : public spatial::SpatialView {
public:
using SpatialView::SpatialView;
void arrange()
{
if (itemCount() != 2)
return;
const bool stacked = width() < 720;
setFixedHeight(!isSpatialEnabled() ? 520 : (stacked ? 560 : 360));
auto* preview = items().first();
preview->setPosition(QVector3D(stacked ? 0 : -164, stacked ? -140 : 0,
preview->position().z()));
items().last()->setPosition(QVector3D(stacked ? 0 : 164, stacked ? 110 : 0, -50));
}
protected:
void resizeEvent(QResizeEvent* event) override
{
SpatialView::resizeEvent(event);
// Update the responsive height after the current layout pass.
QTimer::singleShot(0, this, [this] { arrange(); });
}
};
auto* panel = new SpatialPreviewPanel(parent);
auto* column = new QVBoxLayout(panel);
column->setContentsMargins(0, 0, 0, 0);
column->setSpacing(12);
auto* session = new spatial::SpatialSession(panel, panel);
const bool active = session->activate();
auto* view = new WorkbenchView(panel);
if (!active || !session->attachView(view)) {
view->setSpatialEnabled(false);
view->setRenderMode(spatial::SpatialView::RenderMode::Raster);
}
view->setObjectName("spatialPreviewView");
view->setCameraDistance(1400);
view->setZoom(0.92);
view->setMaximumTilt(QPointF(4, 6));
column->addWidget(view);
auto* card = new layout::Card;
card->setObjectName("spatialDemoCard");
card->setFixedSize(280, 180);
auto* content = new QVBoxLayout(card);
content->setContentsMargins(20, 16, 20, 16);
content->setSpacing(8);
auto* title = new textfields::Label("Activity", card);
title->setFluentTypography(Typography::FontRole::Subtitle);
title->setTextColorRole(textfields::Label::TextColorRole::Primary);
content->addWidget(title);
auto* chart = new charts::Sparkline(card);
chart->setAccessibleName("Activity trend, demo data");
auto* model = new charts::ChartModel(card);
model->setPoints({{0, 12}, {1, 24}, {2, 18}, {3, 38}, {4, 32}, {5, 54}});
chart->setModel(model);
content->addWidget(chart, 1);
auto* caption = new textfields::Label("Last 6 days · demo data", card);
caption->setTextColorRole(textfields::Label::TextColorRole::Secondary);
content->addWidget(caption);
spatial::SpatialItem* item = view->addWidget(card, WidgetOwnership::Owned);
item->setSurfaceIntensity(0.75);
item->setHoverLift(5);
item->setRotation(QVector3D(0, -18, 0));
// Scale, pivot and visibility retain their defaults; see SpatialItem.h.
auto* settings = new layout::Card;
settings->setObjectName("spatialParameterCard");
settings->setFixedSize(280, 260);
auto* controls = new QVBoxLayout(settings);
controls->setContentsMargins(20, 16, 20, 16);
controls->setSpacing(8);
auto* heading = new textfields::Label("Card", settings);
heading->setFluentTypography(Typography::FontRole::Subtitle);
heading->setTextColorRole(textfields::Label::TextColorRole::Primary);
controls->addWidget(heading);
const auto addSlider = [settings, controls](const QString& name, const QString& label,
const QString& unit, int minimum, int maximum,
int initial) {
auto* group = new QVBoxLayout;
group->setSpacing(4);
auto* text = new textfields::Label(settings);
text->setTextColorRole(textfields::Label::TextColorRole::Primary);
auto* slider = new basicinput::Slider(settings);
slider->setObjectName(name);
slider->setAccessibleName(label);
slider->setRange(minimum, maximum);
slider->setValue(initial);
const auto updateText = [text, label, unit](int value) {
text->setText(QString("%1: %2%3").arg(label).arg(value).arg(unit));
};
updateText(initial);
QObject::connect(slider, &basicinput::Slider::valueChanged, text, updateText);
group->addWidget(text);
group->addWidget(slider);
controls->addLayout(group);
return slider;
};
auto* finish = addSlider("spatialItemSurfaceIntensity", "Surface", "%", 0, 100, 75);
auto* angle = addSlider("spatialItemRotation", "Rotation", "°", -35, 35, -18);
auto* depth = addSlider("spatialItemDepth", "Depth", " px", -120, 120, 0);
QObject::connect(finish, &basicinput::Slider::valueChanged, item,
[item](int value) { item->setSurfaceIntensity(value / 100.0); });
QObject::connect(angle, &basicinput::Slider::valueChanged, item,
[item](int value) { item->setRotation(QVector3D(0, value, 0)); });
QObject::connect(depth, &basicinput::Slider::valueChanged, item, [item](int value) {
auto position = item->position();
position.setZ(value);
item->setPosition(position);
});
auto* controlItem = view->addWidget(settings, WidgetOwnership::Owned);
controlItem->setSurfaceIntensity(0.75);
controlItem->setRotation(QVector3D(0, -6, 0));
// No hover lift for the parameter card: keep its drag targets steady.
QObject::connect(view, &spatial::SpatialView::spatialEnabledChanged,
view, [view] { view->arrange(); });
view->arrange();import fluentqt
from PySide6.QtCore import QEvent, QPointF, QTimer
from PySide6.QtGui import QVector3D
from PySide6.QtWidgets import QGridLayout, QVBoxLayout, QWidget
from fluentqt.spatial import SpatialSession, SpatialView
class SpatialPreviewPanel(QWidget):
def stop_spatial(self):
session = self.findChild(SpatialSession)
if session is not None:
session.deactivate()
def event(self, event):
# Stop before deleteLater dismantles this panel's widgets.
# Also call stop_spatial before disposing an enclosing window.
if event.type() == QEvent.DeferredDelete:
self.stop_spatial()
return super().event(event)
class WorkbenchView(SpatialView):
def __init__(self, parent=None):
super().__init__(parent)
self.arrange_timer = QTimer(self)
self.arrange_timer.setSingleShot(True)
self.arrange_timer.timeout.connect(self.arrange)
def arrange(self):
if self.itemCount() != 2:
return
stacked = self.width() < 720
self.setFixedHeight(
520 if not self.isSpatialEnabled() else (560 if stacked else 360)
)
item = self.items()[0]
item.setPosition(
QVector3D(
0 if stacked else -164,
-140 if stacked else 0,
item.position().z()
)
)
self.items()[-1].setPosition(
QVector3D(0 if stacked else 164, 110 if stacked else 0, -50)
)
def resizeEvent(self, event):
super().resizeEvent(event)
self.arrange_timer.start(0)
panel = SpatialPreviewPanel()
column = QVBoxLayout(panel)
column.setContentsMargins(0, 0, 0, 0)
column.setSpacing(12)
session = SpatialSession(panel, panel)
spatial_attached = session.activate()
view = WorkbenchView(panel)
spatial_attached = spatial_attached and session.attachView(view)
if not spatial_attached:
view.setRenderMode(SpatialView.RenderMode.Raster)
view.setSpatialEnabled(False)
view.setObjectName("spatialPreviewView")
view.setFixedHeight(360)
view.setCameraDistance(1400)
view.setMaximumTilt(QPointF(4, 6))
column.addWidget(view)
card = fluentqt.Card()
card.setFixedSize(280, 180)
content = QVBoxLayout(card)
content.setContentsMargins(20, 16, 20, 16)
content.setSpacing(8)
def add_slider(parent, layout, name, label, unit, minimum, maximum, initial):
in_grid = isinstance(layout, QGridLayout)
group = QWidget(parent) if in_grid else parent
column = QVBoxLayout(group) if in_grid else QVBoxLayout()
column.setContentsMargins(0, 0, 0, 0)
column.setSpacing(4)
text = fluentqt.Label(f"{label}: {initial}{unit}", group)
slider = fluentqt.Slider(group)
slider.setObjectName(name)
slider.setAccessibleName(label)
slider.setRange(minimum, maximum)
slider.setValue(initial)
slider.valueChanged.connect(
lambda value: text.setText(f"{label}: {value}{unit}")
)
column.addWidget(text)
column.addWidget(slider)
if isinstance(layout, QGridLayout):
layout.addWidget(group, 0, layout.count())
else:
layout.addLayout(column)
return slider
view.setZoom(0.92)
card.setObjectName("spatialDemoCard")
title = fluentqt.Label("Activity", card)
title.setFluentTypography(fluentqt.FontRole.Subtitle)
title.setTextColorRole(fluentqt.Label.TextColorRole.Primary)
content.addWidget(title)
chart = fluentqt.Sparkline(card)
chart.setAccessibleName("Activity trend, demo data")
model = fluentqt.ChartModel(card)
model.setPoints([QPointF(x, y) for x, y in enumerate([12, 24, 18, 38, 32, 54])])
chart.setModel(model)
content.addWidget(chart, 1)
caption = fluentqt.Label("Last 6 days · demo data", card)
caption.setTextColorRole(fluentqt.Label.TextColorRole.Secondary)
content.addWidget(caption)
item = view.addOwnedWidget(card)
item.setSurfaceIntensity(0.75)
item.setHoverLift(5)
item.setRotation(QVector3D(0, -18, 0))
settings = fluentqt.Card()
settings.setObjectName("spatialParameterCard")
settings.setFixedSize(280, 260)
controls = QVBoxLayout(settings)
controls.setContentsMargins(20, 16, 20, 16)
controls.setSpacing(8)
heading = fluentqt.Label("Card", settings)
heading.setFluentTypography(fluentqt.FontRole.Subtitle)
controls.addWidget(heading)
finish = add_slider(
settings,
controls,
"spatialItemSurfaceIntensity",
"Surface",
"%",
0,
100,
75
)
angle = add_slider(
settings,
controls,
"spatialItemRotation",
"Rotation",
"°",
-35,
35,
-18
)
depth = add_slider(
settings,
controls,
"spatialItemDepth",
"Depth",
" px",
-120,
120,
0
)
finish.valueChanged.connect(lambda value: item.setSurfaceIntensity(value / 100.0))
angle.valueChanged.connect(lambda value: item.setRotation(QVector3D(0, value, 0)))
def change_depth(value):
position = item.position()
position.setZ(value)
item.setPosition(position)
depth.valueChanged.connect(change_depth)
control_item = view.addOwnedWidget(settings)
control_item.setSurfaceIntensity(0.75)
control_item.setRotation(QVector3D(0, -6, 0))
view.spatialEnabledChanged.connect(view.arrange)
view.arrange()API
查看声明没有匹配的 API 成员。
fluent::spatial::SpatialItem
继承自 QObject
SpatialView 中承载真实控件的一个空间表面。
属性
QVector3D position轴心相对视图中心的位置,使用逻辑像素,默认 (0, 0, 0);X 向右、Y 向下、Z 正值朝向相机。
读取position()设置setPosition()通知positionChanged()QVector3D rotation绕轴心依次应用的 X/Y/Z 旋转角度,默认 (0, 0, 0);单位是度,不是弧度。
读取rotation()设置setRotation()通知rotationChanged()qreal scale单个表面的整体缩放倍率 [0.05, 8],默认 1。
读取scale()设置setScale()通知scaleChanged()QPointF pivot归一化的位置锚点和旋转轴心,各轴 [0, 1],默认中心 (0.5, 0.5)。
读取pivot()设置setPivot()通知pivotChanged()bool visible在 3D 和原生 2D 布局中的可见性,默认 true;使用此属性,而非直接隐藏承载的根控件。
读取isVisible()设置setVisible()通知visibleChanged()qreal surfaceIntensity圆角卡片表面的阴影和边缘高光强度,限制为 [0, 1],默认 0。 用于完整矩形 Card,不改变内容或命中区域;仅空间模式绘制。
读取surfaceIntensity()设置setSurfaceIntensity()通知surfaceIntensityChanged()qreal hoverLift悬停时临时向上抬升的逻辑像素数 [0, 16],默认 0,不修改 position。 鼠标按住时冻结位移,原生平面模式移除此效果。
读取hoverLift()设置setHoverLift()通知hoverLiftChanged()
方法
QVector3D position() const轴心相对视图中心的位置,使用逻辑像素,默认 (0, 0, 0);X 向右、Y 向下、Z 正值朝向相机。
void setPosition(const QVector3D& position)轴心相对视图中心的位置,使用逻辑像素,默认 (0, 0, 0);X 向右、Y 向下、Z 正值朝向相机。
QVector3D rotation() const绕轴心依次应用的 X/Y/Z 旋转角度,默认 (0, 0, 0);单位是度,不是弧度。
void setRotation(const QVector3D& rotation)绕轴心依次应用的 X/Y/Z 旋转角度,默认 (0, 0, 0);单位是度,不是弧度。
qreal scale() const单个表面的整体缩放倍率 [0.05, 8],默认 1。
void setScale(qreal scale)单个表面的整体缩放倍率 [0.05, 8],默认 1。
QPointF pivot() const归一化的位置锚点和旋转轴心,各轴 [0, 1],默认中心 (0.5, 0.5)。
void setPivot(const QPointF& pivot)归一化的位置锚点和旋转轴心,各轴 [0, 1],默认中心 (0.5, 0.5)。
bool isVisible() const在 3D 和原生 2D 布局中的可见性,默认 true;使用此属性,而非直接隐藏承载的根控件。
void setVisible(bool visible)在 3D 和原生 2D 布局中的可见性,默认 true;使用此属性,而非直接隐藏承载的根控件。
qreal surfaceIntensity() const圆角卡片表面的阴影和边缘高光强度,限制为 [0, 1],默认 0。 用于完整矩形 Card,不改变内容或命中区域;仅空间模式绘制。
void setSurfaceIntensity(qreal intensity)圆角卡片表面的阴影和边缘高光强度,限制为 [0, 1],默认 0。 用于完整矩形 Card,不改变内容或命中区域;仅空间模式绘制。
qreal hoverLift() const悬停时临时向上抬升的逻辑像素数 [0, 16],默认 0,不修改 position。 鼠标按住时冻结位移,原生平面模式移除此效果。
void setHoverLift(qreal pixels)悬停时临时向上抬升的逻辑像素数 [0, 16],默认 0,不修改 position。 鼠标按住时冻结位移,原生平面模式移除此效果。
QPolygonF projectedPolygon() const当前投影在 SpatialView 坐标中的四个角;无法投影时返回空。
信号
void positionChanged(const QVector3D& position)轴心相对视图中心的位置,使用逻辑像素,默认 (0, 0, 0);X 向右、Y 向下、Z 正值朝向相机。
void rotationChanged(const QVector3D& rotation)绕轴心依次应用的 X/Y/Z 旋转角度,默认 (0, 0, 0);单位是度,不是弧度。
void scaleChanged(qreal scale)单个表面的整体缩放倍率 [0.05, 8],默认 1。
void pivotChanged(const QPointF& pivot)归一化的位置锚点和旋转轴心,各轴 [0, 1],默认中心 (0.5, 0.5)。
void visibleChanged(bool visible)在 3D 和原生 2D 布局中的可见性,默认 true;使用此属性,而非直接隐藏承载的根控件。
void surfaceIntensityChanged(qreal intensity)圆角卡片表面的阴影和边缘高光强度,限制为 [0, 1],默认 0。 用于完整矩形 Card,不改变内容或命中区域;仅空间模式绘制。
void hoverLiftChanged(qreal pixels)悬停时临时向上抬升的逻辑像素数 [0, 16],默认 0,不修改 position。 鼠标按住时冻结位移,原生平面模式移除此效果。
析构函数
Qt 基类完整成员:QObject