表面图是数据可视化的另一种常见显示形式,本文演示如何使用交互方式控制三维表面图显示。

 

一、示例程序的基本功能

本文演示如何使用Q3Dsurface来创建一个简单的3D表面图,并使用一些控件来交互调节,以使3D达到合适的质量效果。这个实例程序演示了一下一些功能:

如何设置QSurfaceDataProxy并为其设置合适的数据;如何使用QHeightMapSurfaceDataProxy显示一个3D高度图;3D图形的三种不同的选择模式;3D图形选定部分的轴范围的用法;更改主题;如何设置自定义曲面的渐变效果。

二、示例程序分析

演示程序包括两部分,我们将曲面的交互功能部分封装在类DemoWidget中, 首先调用QWidget::createWindowContainer()创建窗口容器。然后创建水平和垂直布局管理,将图形和垂直布局添加到一个水平布局中,垂直布局中用于添加交互部件。水平布局设置为DemoWidget的布局。

创建另一个类SurfaceGraph来处理数据添加以及与图形的其他交互。

现在简要分析SurfaceGraph类的功能:

设置代理(Proxy)和数据

首先,我们创建一个QSurfaceDataProxy实例,并将其附加到一个新创建的QSurface3DSeries上:

self.sqrtSinProxy = QSurfaceDataProxy()

self.sqrtSinSeries = QSurface3DSeries(self.sqrtSinProxy)

然后我们用简单的平方根和正弦波数据填充代理。这是通过创建一个新实例并向其中添加元素。

def fillSqrtSinProxy(self):

stepX = (sampleMax - sampleMin) / float(sampleCountX - 1)

stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1)

dataArray = []

index = 0

for i in range(sampleCountZ):

z = min(sampleMax, i * stepZ + sampleMin)

x_arr = []

for j in range(sampleCountX):

x = min(sampleMax, j * stepX + sampleMin)

R = math.sqrt(z * z + x * x) + 0.01

y = (math.sin(R) / R + 0.24) * 1.61

x_arr.append(QSurfaceDataItem(QVector3D(x, y, z)))

dataArray.append(x_arr)

self.sqrtSinProxy.resetArray(dataArray)

高度映射是通过实例化一个QHeightMapSurfaceDataProxy和一个包含高度数据的QImage来创建的。QHeightMapSurfaceDataProxy::setValueRanges()方法用于定义映射的值范围。在我们的例子中,地图的假想位置为34.0°N - 40.0°N和18.0°E - 24.0°E。这些值用于显示和定位地图到轴线。

heightMapImage = QImage(':/maps/mountain')

self.heightMapProxy = QHeightMapSurfaceDataProxy(heightMapImage)

self.heightMapSeries = QSurface3DSeries(self.heightMapProxy)

self.heightMapSeries.setItemLabelFormat('(@xLabel, @zLabel): @yLabel')

self.heightMapProxy.setValueRanges(34.0, 40.0, 18.0, 24.0)

为了演示不同的Proxy,这个示例有两个单选按钮,用户可以使用它们在Serial之间切换。当用户选择”Sqrt & Sin”单选按钮时,所选Serial将使用以下代码激活。

self.sqrtSinSeries.setDrawMode(QSurface3DSeries.DrawSurfaceAndWireframe)

self.sqrtSinSeries.setFlatShadingEnabled(True)

self.graph.axisX().setLabelFormat('%.2f')

self.graph.axisZ().setLabelFormat('%.2f')

self.graph.axisX().setRange(sampleMin, sampleMax)

self.graph.axisY().setRange(0.0, 2.0)

self.graph.axisZ().setRange(sampleMin, sampleMax)

self.graph.axisX().setLabelAutoRotation(30)

self.graph.axisY().setLabelAutoRotation(90)

self.graph.axisZ().setLabelAutoRotation(30)

self.graph.removeSeries(self.heightMapSeries)

self.graph.addSeries(self.sqrtSinSeries)

当用户选择”高度地图”单选按钮时,所选Serial将使用以下代码激活。

self.heightMapSeries.setDrawMode(QSurface3DSeries.DrawSurface)

self.heightMapSeries.setFlatShadingEnabled(False)

self.graph.axisX().setLabelFormat('%.1f N')

self.graph.axisZ().setLabelFormat('%.1f E')

self.graph.axisX().setRange(34.0, 40.0)

self.graph.axisY().setAutoAdjustRange(True)

self.graph.axisZ().setRange(18.0, 24.0)

self.graph.axisX().setTitle('纬度')

self.graph.axisY().setTitle('高度')

self.graph.axisZ().setTitle('经度')

self.graph.removeSeries(self.sqrtSinSeries)

self.graph.addSeries(self.heightMapSeries)

选择模式

Q3Dsurface支持三种不同的选择模式。示例中使用单选按钮演示了这些功能,用户可以使用单选按钮激活合适的选择模式。

def toggleModeNone(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionNone)

def toggleModeItem(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionItem)

def toggleModeSliceRow(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionItemAndRow | QAbstract3DGraph.SelectionSlice)

def toggleModeSliceColumn(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionItemAndColumn | QAbstract3DGraph.SelectionSlice)

图形的坐标轴范围

示例有四个滑块控件,用于调整X和Z轴的最小值和最大值。

#为Sqrt&Sin 重新设置滑动条范围

self.rangeMinX = sampleMin

self.rangeMinZ = sampleMin

self.stepX = (sampleMax - sampleMin) / float(sampleCountX - 1)

self.stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1)

self.axisMinSliderX.setMaximum(sampleCountX - 2)

self.axisMinSliderX.setValue(0)

self.axisMaxSliderX.setMaximum(sampleCountX - 1)

self.axisMaxSliderX.setValue(sampleCountX - 1)

self.axisMinSliderZ.setMaximum(sampleCountZ - 2)

self.axisMinSliderZ.setValue(0)

self.axisMaxSliderZ.setMaximum(sampleCountZ - 1)

self.axisMaxSliderZ.setValue(sampleCountZ - 1)

主题

Q3DSurface支持所有Qt数据可视化的主题。本示例有一个用于选择主题的下拉菜单。下面的方法连接到菜单以激活所选主题。将主题类型更改为另一个预定义主题,该主题将所有主题属性覆盖为预定义值

def changeTheme(self, theme):

self.graph.activeTheme().setType(theme)

自定义表面渐变

示例程序演示了使用两个按钮的自定义表面渐变。渐变可以用QLinearGradient定义,其中所需的颜色被设置为位置。下面的代码展示了如何创建示例渐变并将其设置为系列。注意,还需要将颜色样式更改为Q3DTheme::ColorStyleRangeGradient来实际使用渐变。

gr = QLinearGradient()

gr.setColorAt(0.0, Qt.black)

gr.setColorAt(0.33, Qt.blue)

gr.setColorAt(0.67, Qt.red)

gr.setColorAt(1.0, Qt.yellow)

self.graph.seriesList()[0].setBaseGradient(gr)

self.graph.seriesList()[0].setColorStyle(Q3DTheme.ColorStyleRangeGradient)

surfacegraph.py完整代码:

import math

from PyQt5.QtCore import Qt, QObject

from PyQt5.QtGui import QVector3D, QImage, QLinearGradient

from PyQt5.QtDataVisualization import (Q3DSurface, QSurface3DSeries, QSurfaceDataProxy, QSurfaceDataItem,

QAbstract3DSeries, QValue3DAxis, QAbstract3DGraph, Q3DCamera,

Q3DTheme, QHeightMapSurfaceDataProxy)

sampleCountX = 50

sampleCountZ = 50

heightMapGridStepX = 6

heightMapGridStepZ = 6

sampleMin = -8.0

sampleMax = 8.0

class SurfaceGraph(QObject):

def __init__(self, surface):

super(SurfaceGraph, self).__init__()

self.graph = surface

self.graph.setAxisX(QValue3DAxis())

self.graph.setAxisY(QValue3DAxis())

self.graph.setAxisZ(QValue3DAxis())

self.sqrtSinProxy = QSurfaceDataProxy()

self.sqrtSinSeries = QSurface3DSeries(self.sqrtSinProxy)

self.fillSqrtSinProxy()

heightMapImage = QImage(':/maps/mountain')

self.heightMapProxy = QHeightMapSurfaceDataProxy(heightMapImage)

self.heightMapSeries = QSurface3DSeries(self.heightMapProxy)

self.heightMapSeries.setItemLabelFormat('(@xLabel, @zLabel): @yLabel')

self.heightMapProxy.setValueRanges(34.0, 40.0, 18.0, 24.0)

self.heightMapWidth = heightMapImage.width()

self.heightMapHeight = heightMapImage.height()

def toggleModeNone(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionNone)

def toggleModeItem(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionItem)

def toggleModeSliceRow(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionItemAndRow | QAbstract3DGraph.SelectionSlice)

def toggleModeSliceColumn(self):

self.graph.setSelectionMode(QAbstract3DGraph.SelectionItemAndColumn | QAbstract3DGraph.SelectionSlice)

def setAxisMinSliderX(self, slider):

self.axisMinSliderX = slider

def setAxisMaxSliderX(self, slider):

self.axisMaxSliderX = slider

def setAxisMinSliderZ(self, slider):

self.axisMinSliderZ = slider

def setAxisMaxSliderZ(self, slider):

self.axisMaxSliderZ = slider

def fillSqrtSinProxy(self):

stepX = (sampleMax - sampleMin) / float(sampleCountX - 1)

stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1)

dataArray = []

index = 0

for i in range(sampleCountZ):

z = min(sampleMax, i * stepZ + sampleMin)

x_arr = []

for j in range(sampleCountX):

x = min(sampleMax, j * stepX + sampleMin)

R = math.sqrt(z * z + x * x) + 0.01

y = (math.sin(R) / R + 0.24) * 1.61

x_arr.append(QSurfaceDataItem(QVector3D(x, y, z)))

dataArray.append(x_arr)

self.sqrtSinProxy.resetArray(dataArray)

def enableSqrtSinModel(self, enable):

if not enable:

return

self.sqrtSinSeries.setDrawMode(QSurface3DSeries.DrawSurfaceAndWireframe)

self.sqrtSinSeries.setFlatShadingEnabled(True)

self.graph.axisX().setLabelFormat('%.2f')

self.graph.axisZ().setLabelFormat('%.2f')

self.graph.axisX().setRange(sampleMin, sampleMax)

self.graph.axisY().setRange(0.0, 2.0)

self.graph.axisZ().setRange(sampleMin, sampleMax)

self.graph.axisX().setLabelAutoRotation(30)

self.graph.axisY().setLabelAutoRotation(90)

self.graph.axisZ().setLabelAutoRotation(30)

self.graph.removeSeries(self.heightMapSeries)

self.graph.addSeries(self.sqrtSinSeries)

#为Sqrt&Sin 重新设置滑动条范围

self.rangeMinX = sampleMin

self.rangeMinZ = sampleMin

self.stepX = (sampleMax - sampleMin) / float(sampleCountX - 1)

self.stepZ = (sampleMax - sampleMin) / float(sampleCountZ - 1)

self.axisMinSliderX.setMaximum(sampleCountX - 2)

self.axisMinSliderX.setValue(0)

self.axisMaxSliderX.setMaximum(sampleCountX - 1)

self.axisMaxSliderX.setValue(sampleCountX - 1)

self.axisMinSliderZ.setMaximum(sampleCountZ - 2)

self.axisMinSliderZ.setValue(0)

self.axisMaxSliderZ.setMaximum(sampleCountZ - 1)

self.axisMaxSliderZ.setValue(sampleCountZ - 1)

def enableHeightMapModel(self, enable):

if not enable:

return

self.heightMapSeries.setDrawMode(QSurface3DSeries.DrawSurface)

self.heightMapSeries.setFlatShadingEnabled(False)

self.graph.axisX().setLabelFormat('%.1f N')

self.graph.axisZ().setLabelFormat('%.1f E')

self.graph.axisX().setRange(34.0, 40.0)

self.graph.axisY().setAutoAdjustRange(True)

self.graph.axisZ().setRange(18.0, 24.0)

self.graph.axisX().setTitle('纬度')

self.graph.axisY().setTitle('高度')

self.graph.axisZ().setTitle('经度')

self.graph.removeSeries(self.sqrtSinSeries)

self.graph.addSeries(self.heightMapSeries)

#重新设置滚动条的范围

mapGridCountX = self.heightMapWidth / heightMapGridStepX

mapGridCountZ = self.heightMapHeight / heightMapGridStepZ

self.rangeMinX = 34.0

self.rangeMinZ = 18.0

self.stepX = 6.0 / float(mapGridCountX - 1)

self.stepZ = 6.0 / float(mapGridCountZ - 1)

self.axisMinSliderX.setMaximum(mapGridCountX - 2)

self.axisMinSliderX.setValue(0)

self.axisMaxSliderX.setMaximum(mapGridCountX - 1)

self.axisMaxSliderX.setValue(mapGridCountX - 1)

self.axisMinSliderZ.setMaximum(mapGridCountZ - 2)

self.axisMinSliderZ.setValue(0)

self.axisMaxSliderZ.setMaximum(mapGridCountZ - 1)

self.axisMaxSliderZ.setValue(mapGridCountZ - 1)

def adjustXMin(self, minVal):

minX = self.stepX * minVal + self.rangeMinX

maxVal = self.axisMaxSliderX.value()

if minVal >= maxVal:

maxVal = minVal + 1

self.axisMaxSliderX.setValue(maxVal)

maxX = self.stepX * maxVal + self.rangeMinX

self.setAxisXRange(minX, maxX)

def adjustXMax(self, maxVal):

maxX = self.stepX * maxVal + self.rangeMinX

minVal = self.axisMinSliderX.value()

if maxVal <= minVal:

minVal = maxVal - 1

self.axisMinSliderX.setValue(minVal)

minX = self.stepX * minVal + self.rangeMinX

self.setAxisXRange(minX, maxX)

def adjustZMin(self, minVal):

minZ = self.stepZ * minVal + self.rangeMinZ

maxVal = self.axisMaxSliderZ.value()

if minVal >= maxVal:

maxVal = minVal + 1

self.axisMaxSliderZ.setValue(maxVal)

maxZ = self.stepZ * maxVal + self.rangeMinZ

self.setAxisZRange(minZ, maxZ)

def adjustZMax(self, maxVal):

maxZ = self.stepZ * maxVal + self.rangeMinZ

minVal = self.axisMinSliderZ.value()

if maxVal <= minVal:

minVal = maxVal - 1

self.axisMinSliderZ.setValue(minVal)

minZ = self.stepZ * minVal + self.rangeMinZ

self.setAxisZRange(minZ, maxZ)

def setAxisXRange(self, minVal, maxVal):

self.graph.axisX().setRange(minVal, maxVal)

def setAxisZRange(self, minVal, maxVal):

self.graph.axisZ().setRange(minVal, maxVal)

def changeTheme(self, theme):

self.graph.activeTheme().setType(theme)

def setBlackToYellowGradient(self):

gr = QLinearGradient()

gr.setColorAt(0.0, Qt.black)

gr.setColorAt(0.33, Qt.blue)

gr.setColorAt(0.67, Qt.red)

gr.setColorAt(1.0, Qt.yellow)

self.graph.seriesList()[0].setBaseGradient(gr)

self.graph.seriesList()[0].setColorStyle(Q3DTheme.ColorStyleRangeGradient)

def setGreenToRedGradient(self):

gr = QLinearGradient()

gr.setColorAt(0.0, Qt.darkGreen)

gr.setColorAt(0.5, Qt.yellow)

gr.setColorAt(0.8, Qt.red)

gr.setColorAt(1.0, Qt.darkRed)

self.graph.seriesList()[0].setBaseGradient(gr)

self.graph.seriesList()[0].setColorStyle(Q3DTheme.ColorStyleRangeGradient)

surfacedemo.py 完整代码:

import sys

from PyQt5 import QtCore, QtGui, QtWidgets

from PyQt5.QtCore import Qt, QSize

from PyQt5.QtGui import QLinearGradient, QPixmap, QPainter, QBrush, QIcon

from PyQt5.QtWidgets import (QApplication, QWidget, QMessageBox, QSizePolicy,

QHBoxLayout, QVBoxLayout, QComboBox, QPushButton,

QCheckBox, QSlider, QGroupBox, QLabel, QRadioButton)

from PyQt5.QtDataVisualization import (Q3DSurface, QAbstract3DSeries, QAbstract3DGraph)

from surfacegraph import SurfaceGraph

import surface_rc

class DemoWidget(QWidget):

def __init__(self, parent=None):

super(DemoWidget, self).__init__(parent)

# 设置窗口标题

self.setWindowTitle('实战 Qt for Python: 三维表面图演示')

# 设置窗口大小

self.resize(640, 480)

self.initUi()

def initUi(self):

widgetgraph = Q3DSurface()

container = QWidget.createWindowContainer(widgetgraph)

if not widgetgraph.hasContext():

msgBox = QMessageBox()

msgBox.setText('不能初始化OpenGL上下文')

msgBox.exec()

return;

screenSize = widgetgraph.screen().size()

container.setMinimumSize(QSize(int(screenSize.width() / 2.0), int(screenSize.height() / 1.5)))

container.setMaximumSize(screenSize)

container.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

container.setFocusPolicy(Qt.StrongFocus)

hLayout = QHBoxLayout()

vLayout = QVBoxLayout()

hLayout.addWidget(container, 1) #左边绘图部分

hLayout.addLayout(vLayout) #右边控制部分

vLayout.setAlignment(Qt.AlignTop)

modelGroupBox = QGroupBox('模型')

sqrtSinModelRB = QRadioButton(self)

sqrtSinModelRB.setText('Sqrt && Sin')

sqrtSinModelRB.setChecked(False)

heightMapModelRB = QRadioButton(self)

heightMapModelRB.setText('高度地图')

heightMapModelRB.setChecked(False)

modelVBox = QVBoxLayout()

modelVBox.addWidget(sqrtSinModelRB)

modelVBox.addWidget(heightMapModelRB)

modelGroupBox.setLayout(modelVBox)

selectionGroupBox = QGroupBox('选择模式')

modeNoneRB = QRadioButton(self)

modeNoneRB.setText('无选择')

modeNoneRB.setChecked(False)

modeItemRB = QRadioButton(self)

modeItemRB.setText('条目')

modeItemRB.setChecked(False)

modeSliceRowRB = QRadioButton(self)

modeSliceRowRB.setText('Row Slice')

modeSliceRowRB.setChecked(False)

modeSliceColumnRB = QRadioButton(self)

modeSliceColumnRB.setText('Column Slice')

modeSliceColumnRB.setChecked(False)

selectionVBox = QVBoxLayout()

selectionVBox.addWidget(modeNoneRB)

selectionVBox.addWidget(modeItemRB)

selectionVBox.addWidget(modeSliceRowRB)

selectionVBox.addWidget(modeSliceColumnRB)

selectionGroupBox.setLayout(selectionVBox)

axisMinSliderX = QSlider(Qt.Horizontal, self)

axisMinSliderX.setMinimum(0)

axisMinSliderX.setTickInterval(1)

axisMinSliderX.setEnabled(True)

axisMaxSliderX = QSlider(Qt.Horizontal, self)

axisMaxSliderX.setMinimum(1)

axisMaxSliderX.setTickInterval(1)

axisMaxSliderX.setEnabled(True)

axisMinSliderZ = QSlider(Qt.Horizontal, self)

axisMinSliderZ.setMinimum(0)

axisMinSliderZ.setTickInterval(1)

axisMinSliderZ.setEnabled(True)

axisMaxSliderZ = QSlider(Qt.Horizontal, self)

axisMaxSliderZ.setMinimum(1)

axisMaxSliderZ.setTickInterval(1)

axisMaxSliderZ.setEnabled(True)

#图表主题控制

themeList = QComboBox(self)

themeList.addItem('Qt')

themeList.addItem('Primary Colors')

themeList.addItem('Digia')

themeList.addItem('Stone Moss')

themeList.addItem('Army Blue')

themeList.addItem('Retro')

themeList.addItem('Ebony')

themeList.addItem('Isabelle')

themeList.setCurrentIndex(6)

colorGroupBox = QGroupBox('自定义梯度')

grBtoY = QLinearGradient(0, 0, 1, 100)

grBtoY.setColorAt(1.0, Qt.black)

grBtoY.setColorAt(0.67, Qt.blue)

grBtoY.setColorAt(0.33, Qt.red)

grBtoY.setColorAt(0.0, Qt.yellow)

pm = QPixmap(24, 100)

pmp = QPainter(pm)

pmp.setBrush(QBrush(grBtoY))

pmp.setPen(Qt.NoPen)

pmp.drawRect(0, 0, 24, 100)

gradientBtoYPB = QPushButton(self)

gradientBtoYPB.setIcon(QIcon(pm))

gradientBtoYPB.setIconSize(QSize(24, 100))

grGtoR = QLinearGradient(0, 0, 1, 100)

grGtoR.setColorAt(1.0, Qt.darkGreen)

grGtoR.setColorAt(0.67, Qt.yellow)

grGtoR.setColorAt(0.33, Qt.red)

grGtoR.setColorAt(0.0, Qt.darkRed)

pmp.setBrush(QBrush(grGtoR))

pmp.setPen(Qt.NoPen)

pmp.drawRect(0, 0, 24, 100)

gradientGtoRPB = QPushButton(self)

gradientGtoRPB.setIcon(QIcon(pm))

gradientGtoRPB.setIconSize(QSize(24, 100))

#必须控制先后释放顺序

del pmp

del pm

colorHBox = QHBoxLayout()

colorHBox.addWidget(gradientBtoYPB)

colorHBox.addWidget(gradientGtoRPB)

colorGroupBox.setLayout(colorHBox)

vLayout.addWidget(modelGroupBox)

vLayout.addWidget(selectionGroupBox)

vLayout.addWidget(QLabel('列范围'))

vLayout.addWidget(axisMinSliderX)

vLayout.addWidget(axisMaxSliderX)

vLayout.addWidget(QLabel('行范围'))

vLayout.addWidget(axisMinSliderZ)

vLayout.addWidget(axisMaxSliderZ)

vLayout.addWidget(QLabel('主题'))

vLayout.addWidget(themeList)

vLayout.addWidget(colorGroupBox)

self.modifier = SurfaceGraph(widgetgraph)

heightMapModelRB.toggled.connect(self.modifier.enableHeightMapModel)

sqrtSinModelRB.toggled.connect(self.modifier.enableSqrtSinModel)

modeNoneRB.toggled.connect(self.modifier.toggleModeNone)

modeItemRB.toggled.connect(self.modifier.toggleModeItem)

modeSliceRowRB.toggled.connect(self.modifier.toggleModeSliceRow)

modeSliceColumnRB.toggled.connect(self.modifier.toggleModeSliceColumn)

axisMinSliderX.valueChanged.connect(self.modifier.adjustXMin)

axisMaxSliderX.valueChanged.connect(self.modifier.adjustXMax)

axisMinSliderZ.valueChanged.connect(self.modifier.adjustZMin)

axisMaxSliderZ.valueChanged.connect(self.modifier.adjustZMax)

themeList.currentIndexChanged.connect(self.modifier.changeTheme)

gradientBtoYPB.pressed.connect(self.modifier.setBlackToYellowGradient)

gradientGtoRPB.pressed.connect(self.modifier.setGreenToRedGradient)

self.modifier.setAxisMinSliderX(axisMinSliderX)

self.modifier.setAxisMaxSliderX(axisMaxSliderX)

self.modifier.setAxisMinSliderZ(axisMinSliderZ)

self.modifier.setAxisMaxSliderZ(axisMaxSliderZ)

sqrtSinModelRB.setChecked(True)

modeItemRB.setChecked(True)

themeList.setCurrentIndex(2)

self.setLayout(hLayout)

if __name__ == '__main__':

app = QApplication(sys.argv)

window = DemoWidget()

window.show()

sys.exit(app.exec())

运行结果如下图。

 3D表面图映射效果

3D表面图交互演示 

三、本文知识点

三维表面图的不同模式(表面模式,表面加线模式等);数据可视化中的三维表面图交互控制。

前一篇:实战PyQt5:168-数据可视化之三维散点图交互演示

相关链接

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: