QGraphic学习笔记.doc_第1页
QGraphic学习笔记.doc_第2页
QGraphic学习笔记.doc_第3页
QGraphic学习笔记.doc_第4页
QGraphic学习笔记.doc_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

一个小的简单的游戏引出的心得体会分解实例1实例描述:实现一个按钮,按钮继承自QGraphicObject,头文件:class myButton : public QGraphicsObject Q_OBJECTpublic: myButton(int ,int,QString ,QString ,class MainWindow *); QRectF boundingRect() const; void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *);protected: void hoverEnterEvent ( QGraphicsSceneHoverEvent *) ; void hoverLeaveEvent ( QGraphicsSceneHoverEvent *) ; void mousePressEvent ( QGraphicsSceneMouseEvent *);private: QPixmap pix; QString img; QString hoverImg; class MainWindow * m;Phonon:MediaObject *clickMic;signals: void clickSig();源文件:myButton:myButton(int x,int y,QString img,QString hoverImg,class MainWindow * m) this-img=img; this-hoverImg=hoverImg; pix.load(img); setPos(x-pix.width()/2,y-pix.height()/2); this-m=m; setFlags(QGraphicsItem:ItemIsFocusable); setFlags(QGraphicsItem:ItemIsMovable); setAcceptHoverEvents(true); clickMic=Phonon:createPlayer(Phonon:MusicCategory, Phonon:MediaSource(:/sound/click.mp3);QRectF myButton:boundingRect() const return QRectF(0, 0, pix.width(), pix.height();void myButton:paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) painter-drawPixmap(0,0,pix.width(), pix.height(),pix);void myButton:hoverEnterEvent ( QGraphicsSceneHoverEvent *) setFocus(Qt:MouseFocusReason);pix.load(hoverImg);clickMic-play();update();void myButton:hoverLeaveEvent ( QGraphicsSceneHoverEvent *) setFocus(Qt:MouseFocusReason); pix.load(img); update();void myButton:mousePressEvent ( QGraphicsSceneMouseEvent *) emit clickSig();引用文件: cjScene = new QGraphicsScene;/新建场景指针 cjScene-clear(); myButton *sbtn=new myButton(width/2,height/2-200,:images/startBtn1.png,:images/startBtn2.png,this); connect(sbtn,SIGNAL(clickSig(),this,SLOT(guanKaScene(); cjScene-addItem(sbtn); myButton *soundBtn=new myButton(width/2,height/2,:images/soundBtn1.png,:images/soundBtn2.png,this); cjScene-addItem(soundBtn); myButton *quitBtn=new myButton(width/2,height/2+200,:images/quitBtn1.png,:images/quitBtn2.png,this); connect(quitBtn,SIGNAL(clickSig(),this,SLOT(close(); cjScene-addItem(quitBtn); cjScene-setSceneRect(0,0,width,height); cjScene-setBackgroundBrush( QPixmap(:/images/panelBg.bmp).scaled(width,height); this-setScene(cjScene);绘制动画精灵1:void ninjia:play() QTimeLine* timeline=new QTimeLine(200); timeline-setFrameRange(1, 4); connect(timeline,SIGNAL(frameChanged(int),this,SLOT(move_play(int); timeline-start();void ninjia:move_play(int i) qDebug()setFrameRange(1, maxFrame); timeline-setLoopCount(0); connect(timeline,SIGNAL(frameChanged(int),this,SLOT(move_play(int); timeline-start();void target:move_play(int i) qDebug()i; QString path=imgPath+QString:number(i)+.png; pix.load(path);精灵的碰撞检测:bool target:isColliding() QList item_list = collidingItems(); QGraphicsItem *item; foreach(item, item_list) if(item-data(1)=property) item-stackBefore(this); if(item-data(1)=ninijia|item-data(1)=target)&(this-boundingRect().y()+this-pos().y()+this-boundingRect().height()boundingRect().y()+item-pos().y()+item-boundingRect().height() this-stackBefore(item); if(item-data(1)=projectile&item-data(2)!=false) life=life-(projectile*)item)-gePower(); m-deleteItem(projectile*)item); item-setData(2,false); if(life0)return true; m-updateScore(10); this-setData(2,false); return true; return false;子弹的发射void myScene:mousePressEvent( QGraphicsSceneMouseEvent * e ) projectile *p=new projectile(x,y,m,angleValue,6,projectile,m-getAttack(); this-addItem(p); pewMic-pause(); pewMic-play(); QGraphicsScene:mousePressEvent(e);子弹的自动移动与移除:void projectile:advance(int i) moveBy(cos(angleValue)*speed,sin(angleValue)*speed); if(this-data(2)=false|pos().x()this-m-scene()-width()|pos().y()this-m-scene()-height()|pos().y()0|pos().x()setSceneRect(0,0,width,height); setScene(gameScene); game_score=new QGraphicsTextItem(0, gameScene); game_score-setHtml(分数:+QString:number(score)+); game_score-setFont(QFont(Times, 20, QFont:Bold);game_score-setPos(10, 10); game_attack=new QGraphicsTextItem(0, gameScene); game_attack-setHtml(攻击力:+QString:number(attackPower)+); game_attack-setFont(QFont(Times, 20, QFont:Bold); game_attack-setPos(10, 70); life_text =new QGraphicsTextItem(0, gameScene); life_text-setHtml(生命: +QString:number(attackPower)+); life_text-setFont(QFont(Times, 20, QFont:Bold);life_text-setPos(10, 40); bB=new bloodBar(80,50,this);gameScene-addItem(bB);Animation 动画方法一、items 继承QGraphicsObject,并联合使用QPropertyAnimation方法二、自定义item,继承QObject 和QGraphicsItem。给item 设置一个定时器,在QObject:timerEvent() 事件中控制动画。方法三、调用 QGraphicsScene:advance(), 此函数转而调用QGraphicsItem:advance()The QGraphicsObject class provides a base class for all graphics items that require signals, slots and properties.The class extends aQGraphicsItemwithQObjects signal/slot and property mechanisms. It maps many ofQGraphicsItems basic setters and getters to properties and adds notification signals for many of them.The QGraphicsScene class provides a surface for managing a large number of 2D graphical items.The class serves as a container for QGraphicsItems. It is used together withQGraphicsViewfor visualizing graphical items, such as lines, rectangles, text, or even custom items, on a 2D surface. QGraphicsScene is part of theGraphics View Framework.通过调用scene()的advance(),则item会调用advance()函数:void MainWindow:updateItems() this-scene()-advance(); scene()-update();返回item列表 QList item_list = scene()-items(); QGraphicsItem *item; foreach(item, item_list) /操作。 关卡: myScene *bscene = new myScene(this);/新建场景指针 game_text=new QGraphicsTextItem(0, bscene); game_text-setHtml(text); game_text-setZValue(1); game_text-setFont(QFont(Times, 50, QFont:Bold); game_text-setPos(100, 150); setScene(bscene);游戏结束,文本移动动画: game_text=new QGraphicsTextItem(0, scene(); game_text-setHtml(text); game_text-setZValue(1); QTimeLine *timeline=new QTimeLine(800); timeline-setFrameRange(1, 50); timeline-setLoopCount(1); connect(timeline,SIGNAL(frameChanged(int),this,SLOT(gameOverPlay(int); timeline-start();void MainWindow:gameOverPlay(int i) game_text-setFont(QFont(Times, i, QFont:Bold); game_text-setPos(10*i, 150); setRenderHint(QPainter:Antialiasing);/防锯齿 setCacheMode(QGraphicsView:CacheBackground);/双缓冲showFullScreen();/全屏/三个按钮 cjScene = new QGraphicsScene;/新建场景指针 cjScene-clear(); myButton *sbtn=new myButton(width/2,height/2-200,:images/startBtn1.png,:images/startBtn2.png,this); connect(sbtn,SIGNAL(clickSig(),this,SLOT(guanKaScene(); cjScene-addItem(sbtn); myButton *soundBtn=new myButton(width/2,height/2,:images/soundBtn1.png,:images/soundBtn2.png,this); cjScene-addItem(soundBtn); myButton *quitBtn=new myButton(width/2,height/2+200,:images/quitBtn1.png,:images/quitBtn2.png,this); connect(quitBtn,SIGNAL(clickSig(),this,SLOT(close(); cjScene-addItem(quitBtn); cjScene-setSceneRect(0,0,width,height); cjScene-setBackgroundBrush( QPixmap(:/images/panelBg.bmp).scaled(width,height);setScene(cjScene);修改后的lxExp.h文件内容:/前置声明classClxImplement;classClxExppublic:ClxExp();virtualClxExp();voidDoSomething();private:/声明一个类ClxImplement的指针,不需要知道类ClxImplement的定义ClxImplement*m_pImpl;修改后的lxExp.cpp文件内容:#include lxExp.h/在这里包含类ClxImplement的定义头文件#includelxImplement.hClxExp:ClxExp()m_pImpl=newClxImplement;ClxExp:ClxExp()if(m_pImpl)deletem_pImpl;voidClxExp:DoSomething()m_pImpl-DoSomething();对于C+中,类的定义之前声明它,如下实例代码:classB;classA/.B * ptr_B;.;classB/.;被提前声明的类在其定义之前,只能使用该类的指针或者引用 。在类的定义结束(编译器在遇到类定义的右花括号之后),用该类来声明类实例对象,或对象指针,引用都是合法的。前向声明超前引用所谓超前引用是指一个类型在定义之前就被用来定义变量和声明函数。一般情况下,C/C+要求所有的类型必须在使用前被定义,但是在一些特殊情况下,这种要求无法满足,例如,在类CMyView中保留了一个非模式对话框对象指针,该对象用于显示/修改一些信息。为了实现对话框“应用”按钮,把对话框做的修改立刻更新到view界面上,为此,需要在对话框类中需要保存view类的指针,这样定义关系就变成如下的代码:#ifndef_MYVIEW_H_#define_MYVIEW_H_/这是view类的头函数#includeMyDialog.hclassCMyView:publicCViewprotected:CMyDialog*pDlg;/这里是其他定义;#endif#ifndef_MYDIALOG_H_#define_MYDIALOG_H_/这是对话框类的定义#includeMyView.hclassCMyDialog:publicCDialogprotected:CMyView*pView;/其他定义;#endif从编译器角度看,编译MyDialog.CPP时,系统首先定义宏_MYDIALOG_H_,然后包含MyView.h,MyView.h中的#includeMyDialog.h由于_MYDIALOG_H_已经定义,所以不再起作用。在CMyView类的声明中,CMyDialog*pDlg;就会让编译器产生“CMyDialog类型没有定义之类的错误,编译MyView.CPP文件出现的错误可以类似得到。更一般的情况,类A和类B需要彼此互相引用,这样必然有一个类会先被定义,而另外一个类后被定义,这样在先被定义的类引用后被定义的类的时候,就导致了所谓的超前引用。超前引用导致的错误有以下几种处理办法:1)使用类声明在超前引用一个类之前,首先用一个特殊的语句说明该标识符是一个类名,即将被超前引用。其使用方法是:a)用classClassB;声明即将超前引用的类名b)定义classClassAc)定义classClassB;d)编制两个类的实现代码。上述方法适用于所有代码在同一个文件中,一般情况下,ClassA和ClassB分别有自己的头文件和cpp文件,这种方法需要演变成:a)分别定义ClassA和ClassB,并在cpp文件中实现之b)在两个头文件的开头分别用classClassB;和classClassA;声明对方c)在两个cpp文件中分别包含另外一个类的头文件NOTE:这种方法切记不可使用类名来定义变量和函数的变量参数,只可用来定义引用或者指针。2)使用全局变量由于全局变量可以避免超前引用,不用赘述。我的习惯是,把类对象的extern语句加在该类头文件的最后,大家喜欢怎样写那都没有什么大问题,关键是保证不要在头文件中胡乱包含。3)使用基类指针。这种方法是在引用超前引用类的地方一律用基类指针。而一般情况下,两个互相引用的类并不涉及其基类,因此不会造成超前引用。以开始的例子说:在CMyDialog类中用CView*代替CMyView*,在CMyView类中用CDialog*代替CMyDialog*,这样必然不会造成超前引用。说明:本文中,为了叙述方便,把classAClass;语句成为类AClass的声明,把classAClass开始的对AClass的类成员变量、成员函数原型等的说明称为类的定义,而把在CPP中的部分称为类的定义。如果大家对这三个词有不同的理解,请按照自己的本意把这三个词换成相应的词来理解。写自己的Item,要先了解QGraphicsItem的相关属性及操作有哪些,哪些是必须要重写的,哪些是可以选的:透明度鼠标悬浮事件鼠标双击,移动,释放的事件旋转度缩放系数截获事件滚动item void QGraphicsItem:moveBy ( qreal dx, qreal dy )向x,y方向上移动dx,dy的距离,等价于调用setPos(pos()+QpointF(dx,dy)写自己的item图形,首先应该继承QGraphicsItem,然后重写他的两个纯虚公共函数,boundingRect()和paint(),第一个函数返回绘制item大概的区域,第二个函数用来绘制item内容:void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);QRectF boundingRect() const;boundingRect()函数有很多用处,场景在boundingRect()来建立它的item的index,视图view使用它来剪切可见的item,在重新绘制item时候,来决定相互重叠的部分,此外,item的碰撞检测机制也使用的boundingRect()来提供一个高效的定点,在collidesWithItem()更好的碰撞算法建立在调用函数shape(),shape()函数以QpainterPath类型返回item的精准的轮廓。一般的,场景不希望item的boundingRect()和shape()变化,除非该item被通告,如果想通过一些方法改变item的形状,首先应该调用QgraphicsScene()来允许场景QgraphicsScene来刷新它的item记录。碰撞检测可以通过下面两种方法来完成1、重写shape()函数来返回item的精准轮廓,依靠默认的collidesWithItem()来做外形交集。如果item轮廓和复杂时候,这个消耗是很大的2、重写collidesWithItem(),提供一个自己的item和轮廓碰撞的算法Contains()函数可以调用,用来决定一个item是否包含一个点。这个函数也可以重写,contains()函数默认的方法是通过调用shape()来完成的。Items中也可以包含其他的items,也可以被别的items包含,所有的items可以有一个父亲item和一串孩子items,除非一个item没有父亲,否则它的位置是在父亲坐标中,父亲items遗传他的位置和转换给孩子item转换QgraphicsItem支持投射转换,有很多方法来改变item的转换,对于简单的转换,可以调用函数setRotation()或者setScale(),可以传递一个转换矩阵给函数setTransform(),对于一些更复杂的转换,可以通过调用函数setTransformations()来设置一系列组合的转换。Item转换从父亲到孩子进行聚集,因此如果一个父亲和孩子item都旋转90度,那么孩子就旋转了180度,相似的,如果父亲item放大了2X倍,那么孩子item就被方法4X倍,一个item的转换不影响他的外观,所有和外观有关的函数(例如contains(),update()和所有的映射mapping函数)将会在本地坐标中操作,更方便的,QgraphicsItem提供函数sceneTransform(),将会返回item所有的转换矩阵,scenePos()将会返回item在场景坐标中的位置,重新设置item的矩阵,调用函数resetTransform()一般的转换回产生一个不同的结果,这取决于转换应用的顺序,例如,如果你放大一个转换,然后再旋转它,可能和你先旋转它得到的结果不一样,你设置转换属性的顺序并不影响转换的结果,(也就是仍旧会按照你的转换命令去转换,只是最后得到的图形不一样而已),QgraphicsItem经常应用一个合适的顺序如下:绘图paintingpaint()函数被QgrapicsView类调用来绘制item的内容,item默认是没有背景或者填充颜色的。在函数中没有被绘制的所有区域都将会发亮,可以调用update()来重绘item,可以选择传递需要重绘的矩形区域(不是必须的)。取决于item在view中是否可见,item可能会也可能不会重绘,QgraphicsItem里面没有和Qwidget:repaint()函数等价的item通过view来绘制,从父items开始,然后是自items,以上升的栈的顺序,可以通过调用setZValue()设置item的栈顺序,通过zValue()来测试,具有低z-values的item比具有高z-value的item先绘制,栈顺序应用于兄弟items,父items总是比子items更早绘制。排序sort所有的items都按照一个已经声明的,稳定的顺序来绘制,这个顺序也决定了当你在场景中点击鼠标时候,哪个items最先接受鼠标的输入。一般的,你不需要担心排序问题,因为所有的items都按照一个在场景中声明的自然的顺序在一个栈中,子item在父item的上面,兄弟item按照插入场景的顺序来入栈,如果你先添加了item A ,然后是item B,然后是item C ,这样栈中的顺序从下往上就是A,B,CDrag and Drop Robot例子中展示了该robot的栈顺序,躯干顺序是根item(其他所有的item都是躯干item的子item或者后代item),然后是头item被绘制,由于它是躯干item的子item列表中的第一个item,然后是左臂膀上面的那部分item,下面那个臂膀item是上面臂膀item的子item,所以会在和3号item同等级的兄弟item绘制完后被绘制,接着就是右边上面的的臂膀item,就是5号item。可以调用setZvalue()来设置一个item的相对亦另一个向上,向下或者兄弟栈顺序。默认的Z值是0,具有同样的Z值的item会按照插入的顺序来入栈。可以调用stackBefore()来备份孩子item的列表,这可以直接更正item的顺序。如果想让孩子item在父item的后面,也就是先绘制孩子item,然后在绘制父item,怎么办呢?可以设置ItemStacksBehindParent属性给这个item,利用函数setFlag();两个兄弟item的顺序也决定了他们的子item 和后代item的顺序,如果一个父item的在两个父item的后面,那么他所有的孩子items都在另一个父item的孩子items后面。事件EventQgraphicsItem从场景中通过sceneEvent()函数来接受事件,这个函数通过一些方便的操作分散大部分事件ContextMenuEvent()函数接受上下文菜单事件FocusInEvent()和focusOutEvent()函数接受焦点进出事件hoverEnterEvent(), hoverMoveEvent(), and hoverLeaveEvent() 接受鼠标悬浮 移动和离开事件inputMethodEvent()函数处理输入法事件,keyPressEvent() and keyReleaseEvent()事件处理键盘按下和松开事件mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent(), and mouseDoubleClickEvent()处理鼠标按下,移动,松开,双击事件也可以为一些item过滤一些事件通过安装过滤器,这个和QT一般的事件过滤器不一样,一般的过滤器只工作在Qobject和它的子类,通过调用installSceneEventFilter()为item安装了过滤器后,被过滤的事件将会被虚函数sceneEventFilter().捕捉到,可以通过调用函数removeSceneEventFilter().来去除掉事件过滤器Custom Data数据有些时候为item注册一些数值很有用,做一个普通的item或者标准的item,可以调用setData()来为任一个item设置值,这个值使用key-value对,(key是整形,value是变种数据Qvarient)来得到item的数据,通过调用data(),1、QVariant QGraphicsItem:itemChange ( GraphicsItemChange change, const QVariant & value ) virtual protected这个函数被QGraphicsItem调用用来标明items的一些状态改变了,通过重载这个函数,可以对自己定义事件响应,在一些情况下,可以做一些调整。参数change是改变的那个item的改变状态参数,value是一个新的数据,他的类型取决于change,change是QGraphicsItem:GraphicsItemChange的枚举变量enum GraphicsItemChange ItemEnabledChange, ItemEnabledHasChanged,ItemMatrixChange, ItemPositionChange, ., ItemScenePositionHasChanged 例如:QVariant Component:itemChange(GraphicsItemChange change, const QVariant &value) if (change = ItemPositionChange & scene() / value is the new position. QPointF newPos = value.toPointF(); QRectF rect = scene()-sceneRect(); if (!rect.contains(newPos) / Keep the item inside the scene rect. newPos.setX(qMin(rect.right(), qMax(newPos.x(), rect.left(); newPos.setY(qMin(rect.bottom(), qMax(newPos.y(), rect.top(); return newPos; return QGraphicsItem:itemChange(change, value);默认的函数什么都不做,只返回value注意:在使用这个函数时候,在函数内部调用函数时候要小心,因为这可能导致一些意想不到的结果,例如:你不能再这个函数里面调用setPos()在change是ItemPositionChange时候,由于setPos()函数将会再次调用itemChange(ItemPositionChange),如此就一直循环下去了。2、void QGraphicsItem:setFlag ( GraphicsItemFlag flag, bool enabled = true )void QGraphicsItem:setFlags ( GraphicsItemFlags flags )把flags设置为item的属性,如果item获得了光标,但是flags没有使能ItemsFocusable,这个item将会丢失光标,同样的,当item被选择到,但是没有使能ItemsSelectable,这个item会自动的失去选择。默认的,所有的flags都是不可用的。(QGraphicsWidget 为了获得位置变化默认使能了ItemSendsGeometryChanges)相近的函数GraphicsItemFlags QGraphicsItem:flags () const返回item的所有使能的flags,例如,如果flags里面包含了ItemIsFocusable,这个item可以接受输入光标3、QPainterPath QGraphicsItem:shape () const virtual以QPainterPath返回item在local坐标中的形状,这个形状可以用来做很多事情,包括碰撞侦测,打击测试,还有用来 QGraphicsScene:items() 函数默认的函数调用boundingRect()返回一个简单的矩形形状,但是子类可以重载这个函数,为非矩形的item返回一个更加精准的形状,例如一个圆形的item可以选择返回一个椭圆形,用来获得更好的碰撞侦测效果。代码:QPainterPath RoundItem:shape() const QPainterPath path; path.addEllipse(boundingRect(); return path;形状的轮廓线可以通过绘制时候的pen来变化4、QRectF QGraphicsItem:boundingRect () const pure virtual这个纯虚函数用矩形声明了item的边界轮廓,所有的绘制都必须限定在item的矩形边框内。QGraphicsView使用这个方法来决定item是否需要重绘尽管item的形状可以是任意的,但是边框一直都是矩形,不影响items的变换如果想改变items的边框,应该首先调用prepareGeometryChange(),这将通知场景scene即将发生的变化,这样场景可以刷新item的位置下标。否则,场景将不会察觉到item的变化,结果也未知。如果要重绘item时候,重载这个函数来让QGraphicsView来决定item的边界区域,注意:由于绘制边界时候的边界轮廓线,在这个矩形区域内包含画笔pen宽度的一半很重要,不需要补偿画图走样 例如QRectF CircleItem:boundingRect() const qreal penWidth = 1; return QRectF(-radius - penWidth / 2, -radius - penWidth / 2, diameter + penWidth, diameter + penWidth);同样的一个返回item轮廓的函数QRegion QGraphicsItem:boundingRegion ( const QTransform & itemToDeviceTransform ) const返回该item的轮廓区域,返回的区域的坐标系统依赖于参数itemToDeviceTransform,如果你传递一个Qtransform对象作为参数,那么函数将返回本地坐标系统区域返回的区域是item内容可见的一个大概的轮廓,尽管计算起来很浪费空间和时间,但是比boundingRect()更精准,而且当重绘时候,它还能避免不必要的重绘。对像线或者简单的多边形来说非常有效。也可以调节轮廓区域的粒度通过调用setBoundingRegionGranularity(),默认的粒度是0,这时候item的区域和轮廓矩形一样的。itemToDeviceTransform是从item坐标系统到设备坐标系统的一个转换。如果你想让这个函数返回一个场景坐标区域,可以用函数sceneTransform()作为参数。相关函数qreal QGraphicsItem:boundingRegionGranularity () const返回item的轮廓区域粒度5、void QGraphicsIt

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论