Qt5 图形视图框架QGraphicsView

1、图形视图框架包含三大类:场景类(QGraphicsScene),视图类(QGraphicsView),图元类(QGraphicsItem); 
2、对于有很多项的场景,使用轻量级的QGraphicsItem类作为数目众多的自定义项的基础最好,仅对数目较少的项使用QGraphicsObject 
3、当一个项发生了变换(transformation),该项所有的子对象自动应用 该变换,递归应用到最深层次的子孙对象, 
变换有(拖动,移动。。。。。),通过调用QGraphicsItem::setFlag(QGraphicsItem::ItemIngnoreTransformation)可以使子项忽略父项的变换,通常使用的标志还有可移动,选中,获得焦点等 
4、通过把项设置为QGraphicsItemGroup的子项,可以将他们分组,创建项的集合。 
5、图形视图类使用三种坐标系统,但是实际应用中只是关心其中的两种。视图使用物理坐标系统,场景使用在构造函数中传入的QRectF定义的逻辑坐标系统。Qt自动进行场景坐标到视图坐标的映射,放置项时使用的是场景的坐标。项的中心是在(0,0)点的逻辑坐标系统,每个项的(0,0)点实际在该项场景中所在位置的中心(文本项除外,原点在项的左上角)。 
6、图形项:QGraphicsItem因为有两个纯虚函数而不能实例化对象,这两个纯虚函数是boundingRect()和paint() 
paint()函数必须重新实现来绘制项,boundingRect()函数在图形视图框架中为项提供一个边界矩形,用于冲突监测和保证项仅在QGraphicsView的视口(viewport)中可见时才重绘。如果要创建非矩形形状的自定义图形项,最好同时实现shape()方法,这个方法返回一个精确描述项的轮廓的QpainterPath,对于准确检测冲突和鼠标点击非常有用。 
7、如果要自定义一个形状,最简单的是使用标准的QGraphicsItem的子类之一,比如QGraphicsPathItem和QGraphicsPolygonItem,如果有定制行为,可以重新实现保护事件的处理函数,如keyPressEvent()。如果只是想要自己绘制,可以从QGraphicsItem派生,重新实现boundingRect()和paint()和shape()方法。

俄罗斯方块的实现

俄罗斯方块的逻辑

小方块的类型

效果图

 

代码的实现

onePiece.h

#ifndef ONEPIECE_H
#define ONEPIECE_H /************
*一块方块的绘制
*
*
***************/ #include <QGraphicsObject>
#include <QColor> class onePiece : public QGraphicsObject
{
public:
onePiece(const QColor &brushColor = Qt::red);
//为项提供一个外围的边界矩形
virtual QRectF boundingRect() const;
//QGraphicsView调用,在本地坐标系统中绘制项
virtual void paint(QPainter * painter, const QStyleOptionGraphicsItem * option, QWidget * widget = 0);
//重新定义项的形状,默认调用boundingRect获取项的矩形形状轮廓
virtual QPainterPath shape() const;
private:
QColor m_brushColor; }; #endif // ONEPIECE_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

onepiece.c

#include "onepiece.h"
#include <QPainter>
#include "enumHeader.h" /****
* 为了避免同一个方块组内小方块发生碰撞,
* 小方块的大小实际为19.5*19.5,但是小方块加上笔刷的宽度后为20*20
* 这样看起来是四个小方块连在一起的
* **/ onePiece::onePiece(const QColor &brushColor)
:m_brushColor(brushColor)
{
} QRectF onePiece::boundingRect() const
{
qreal penWidth = PEN_WIDTH;
return QRectF(-(PIECE_DIAMETER - penWidth)/2, -(PIECE_DIAMETER - penWidth)/2,
PIECE_DIAMETER - penWidth, PIECE_DIAMETER - penWidth);
} void onePiece::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
{
//背景贴图
painter->drawPixmap(-PIECE_DIAMETER/2,-PIECE_DIAMETER/2,PIECE_DIAMETER,PIECE_DIAMETER,QPixmap(":/piece/Image/piece/box.png"));
painter->setBrush(m_brushColor);
//将方块的边界的颜色进行透明化
QColor penColor = m_brushColor;
// 将颜色的透明度减小
penColor.setAlpha(200);
painter->setPen(penColor);
//使用当前的笔刷和笔画矩形框
painter->drawRect(-PIECE_DIAMETER/2, -PIECE_DIAMETER/2, PIECE_DIAMETER, PIECE_DIAMETER);
} QPainterPath onePiece::shape() const
{
QPainterPath path;
//去除笔刷的宽度,这样同一个方块组的方块就不会被检测出碰撞的情况
path.addRect(-(PIECE_DIAMETER-PEN_WIDTH)/2,-(PIECE_DIAMETER-PEN_WIDTH)/2,PIECE_DIAMETER-PEN_WIDTH,PIECE_DIAMETER-PEN_WIDTH);
return path;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44

pieceBox.h

#ifndef PIECEBOX_H
#define PIECEBOX_H /********
* 方块组
* 4*4
*
*
* ******/ #include <QGraphicsItemGroup>
#include <QKeyEvent>
#include <QTimer>
#include "enumHeader.h"
#include <QTransform>
#include "onepiece.h"
#include <QGraphicsItem> class pieceBox :public QObject,public QGraphicsItemGroup
{
Q_OBJECT
public:
pieceBox();
//颜色表
static QColor colorTable[7];
//绘制方块组的边框矩形
virtual QRectF boundingRect() const;
//是否发生碰撞
bool isCollding() const;
//获取当前的方块类型
BoxType getCurrentBoxType() const;
//创建方块组
void createBox(const QPointF &point = QPointF(0,0),
BoxType currentBoxType = RandomShape);
//消除方块组
void clearBoxGroup(const bool &isClear = false); protected:
virtual void keyPressEvent(QKeyEvent * event); signals:
void signal_needNewBox();
void signal_gameOver();
public slots:
void slot_moveOneStep();
void slot_startTimer(int timeSec);
void slot_stopTimer();
private:
QTimer *m_Timer;
BoxType m_currentBoxType;
QTransform m_oldTransform;
QList<onePiece *> m_pieceBoxList; //存放新方块组的四个方块
}; #endif // PIECEBOX_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56

pieceBox.c

#include "piecebox.h"
#include "enumHeader.h"
#include <QList>
#include <QDebug> QColor pieceBox::colorTable[7] = {QColor(200,0,0,100),QColor(255,200,0,100),
QColor(0,0,200,100),QColor(0,200,0,100),
QColor(0,200,255,100),QColor(200,0,255,100),
QColor(150,100,100,100)}; pieceBox::pieceBox()
{
m_pieceBoxList.clear();
//使得方块组支持键盘操作
setFlags(QGraphicsItem::ItemIsFocusable);
//保存矩阵的原状态,使得可以还原矩阵
m_oldTransform = transform();
m_Timer = new QTimer(this);
connect(m_Timer,SIGNAL(timeout()),this,SLOT(slot_moveOneStep()));
m_currentBoxType = RandomShape;
} //绘制方块组的边框矩形
QRectF pieceBox::boundingRect() const
{
qreal penWidth = PEN_WIDTH;
return QRectF(-(PIECE_DIAMETER*2 - penWidth) / 2, -(PIECE_DIAMETER*2 - penWidth) / 2,
PIECE_DIAMETER*4-penWidth, PIECE_DIAMETER*4-penWidth);
} bool pieceBox::isCollding() const
{
//依次检测方块组中的每个方块的碰撞
foreach (onePiece *piece, m_pieceBoxList) {
// qDebug() << "colliding number:" << piece->collidingItems().count();
//获取与该方块碰撞的方块的个数
if(piece->collidingItems().count() > 1)
{
return true;
}
}
return false;
} BoxType pieceBox::getCurrentBoxType() const
{
return m_currentBoxType;
} void pieceBox::createBox(const QPointF &point, BoxType currentBoxType)
{
int boxType = currentBoxType;
if(boxType == RandomShape)
{
boxType = qrand() % 7;
}
//设置该方块组的颜色
QColor boxColor = colorTable[boxType];
//准备四个小方块 //恢复方块组的变换矩阵,因为之前的方块组的变换会导致变换矩阵的位置发生变换,
//防止新的方块组因为旧的方块组变换异常
setTransform(m_oldTransform);
setRotation(0);
resetTransform(); m_pieceBoxList.clear();
for(int i = 0;i < 4;i++)
{
onePiece *piece = new onePiece(boxColor);
m_pieceBoxList.append(piece);
//将小方块添加到方块组中
addToGroup(piece);
}
//设置方块组的形状
switch (boxType) {
case IShape:
m_currentBoxType = IShape;
m_pieceBoxList.at(0)->setPos(-30,-10);
m_pieceBoxList.at(1)->setPos(-10,-10);
m_pieceBoxList.at(2)->setPos(10,-10);
m_pieceBoxList.at(3)->setPos(30,-10);
break;
case JShape:
m_currentBoxType = JShape;
m_pieceBoxList.at(0)->setPos(10,-10);
m_pieceBoxList.at(1)->setPos(10,10);
m_pieceBoxList.at(2)->setPos(10,30);
m_pieceBoxList.at(3)->setPos(-10,30);
break;
case LShape:
m_currentBoxType = LShape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(-10,10);
m_pieceBoxList.at(2)->setPos(10,30);
m_pieceBoxList.at(3)->setPos(-10,30);
break;
case OShape:
m_currentBoxType = OShape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(-10,10);
m_pieceBoxList.at(3)->setPos(10,10);
break;
case SShape:
m_currentBoxType = SShape;
m_pieceBoxList.at(0)->setPos(30,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(10,10);
m_pieceBoxList.at(3)->setPos(-10,10);
break;
case TShape:
m_currentBoxType = TShape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(30,-10);
m_pieceBoxList.at(3)->setPos(10,10);
break;
case Zshape:
m_currentBoxType = Zshape;
m_pieceBoxList.at(0)->setPos(-10,-10);
m_pieceBoxList.at(1)->setPos(10,-10);
m_pieceBoxList.at(2)->setPos(10,10);
m_pieceBoxList.at(3)->setPos(30,10);
break;
default:
break;
}
//设置方块组的位置
setPos(point);
//检测是否发生碰撞,发生碰撞,游戏结束
if(isCollding())
{
slot_stopTimer();
emit signal_gameOver();
}
} //删除方块组中的小方块到情景中
void pieceBox::clearBoxGroup(const bool &isClear)
{
QList<QGraphicsItem *> itemList = childItems();
foreach (QGraphicsItem *piece, itemList) {
removeFromGroup(piece);
// qDebug() << "clear box group" << isClear;
if(isClear)
{
//销毁小方块
((onePiece *)piece)->deleteLater();
}
}
m_pieceBoxList.clear();
} void pieceBox::keyPressEvent(QKeyEvent *event)
{
switch (event->key()) {
case Qt::Key_Down:
moveBy(0,20);
//检测是否碰撞
if(isCollding())
{
moveBy(0,-20);
clearBoxGroup();
//需要新的方块
emit signal_needNewBox();
}
break;
case Qt::Key_Left:
moveBy(-20,0);
if(isCollding())
{
moveBy(20,0);
} break;
case Qt::Key_Right:
moveBy(20,0);
if(isCollding())
{
moveBy(-20,0);
}
break;
case Qt::Key_Up:
setRotation(rotation()+90);
if(isCollding())
{
setRotation(rotation()-90);
}
break;
case Qt::Key_Space: //快速下落
moveBy(0,20);
while (!isCollding()) {
moveBy(0,20);
}
moveBy(0,-20);
clearBoxGroup();
//需要新的方块
emit signal_needNewBox();
break;
default:
break;
}
} void pieceBox::slot_moveOneStep()
{
moveBy(0,20);
// qDebug() << "move one step";
if(isCollding())
{
moveBy(0,-20);
// 将小方块从方块组中移除到场景中
clearBoxGroup();
//需要新的方块
emit signal_needNewBox();
}
} void pieceBox::slot_startTimer(int timeSec)
{
m_Timer->start(timeSec);
} void pieceBox::slot_stopTimer()
{
m_Timer->stop();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229

**界面类**panel.h

#ifndef PANEL_H
#define PANEL_H #include <QWidget>
#include <QPalette>
#include <QPixmap>
#include <QGraphicsScene>
#include <QGraphicsView>
#include "piecebox.h"
#include "onepiece.h"
#include <QGraphicsLineItem>
#include <QMediaPlayer> namespace Ui {
class Panel;
} class Panel : public QWidget
{
Q_OBJECT public:
explicit Panel(QWidget *parent = 0);
~Panel();
void setbackground(const int &Lv);
void initControlWidget();
void initGraphicsViewWidget(); /**游戏控制项***/
void startGame();
void pauseGame();
void restartGame();
void stopGame(); void updateScore(const int fullRows = 0); private slots:
void on_pbt_startGame_clicked(); void on_pbt_pauseGame_clicked(); void on_pbt_restart_clicked(); void on_pbt_stopGame_clicked(); void slot_clearFullRows(); void slot_gameOver(); void slot_moveBox();
private:
Ui::Panel *ui;
QPalette m_Palette;
QPixmap m_pixmap;
int m_currentLv;
int m_currentLVSpeed;
bool m_isPauseGame;
bool m_isGameOver;
QGraphicsScene *m_scene;
//四条边界线
QGraphicsLineItem *m_topLine;
QGraphicsLineItem *m_leftLine;
QGraphicsLineItem *m_buttomLine;
QGraphicsLineItem *m_rightLine; pieceBox *m_currentBox;
pieceBox *m_nextBox; QList<int> m_rowList;
QMediaPlayer *m_mediaPlayer;
}; #endif // PANEL_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

panel.c

#include "panel.h"
#include "ui_panel.h"
#include "enumHeader.h"
#include <QDebug>
#include <QGraphicsBlurEffect>
#include <QPropertyAnimation>
#include <QMessageBox>
#include <QMediaContent> Panel::Panel(QWidget *parent) :
QWidget(parent),
ui(new Ui::Panel)
{
ui->setupUi(this);
m_isPauseGame = false;
m_isGameOver = false; m_mediaPlayer = new QMediaPlayer;
m_mediaPlayer->setMedia(QUrl::fromLocalFile(QString("clearRow.mp3")));
m_mediaPlayer->setVolume(100);
//设置背景
setbackground(LV0);
initControlWidget(); initGraphicsViewWidget();
} Panel::~Panel()
{
delete ui;
} void Panel::setbackground(const int &Lv)
{
setAutoFillBackground(true);
switch (Lv) {
case LV0:
m_currentLv = LV0;
m_currentLVSpeed = LV0_SPEED;
ui->label_gameLevel->setText("俄罗斯方块");
m_pixmap.load(":/background/Image/background/background.png");
break;
case LV1:
m_currentLv = LV1;
m_currentLVSpeed = LV1_SPEED;
ui->label_gameLevel->setText("第一关");
m_pixmap.load(":/background/Image/background/background01.png");
break;
case LV2:
m_currentLv = LV2;
m_currentLVSpeed = LV2_SPEED;
ui->label_gameLevel->setText("第二关");
m_pixmap.load(":/background/Image/background/background02.png");
break;
case LV3:
m_currentLv = LV3;
m_currentLVSpeed = LV3_SPEED;
ui->label_gameLevel->setText("第三关");
m_pixmap.load(":/background/Image/background/background03.png");
break;
case LV4:
m_currentLv = LV4;
m_currentLVSpeed = LV4_SPEED;
ui->label_gameLevel->setText("第四关");
m_pixmap.load(":/background/Image/background/background04.png");
break;
case LV5:
m_currentLv = LV5;
m_currentLVSpeed = LV5_SPEED;
ui->label_gameLevel->setText("第五关");
m_pixmap.load(":/background/Image/background/background05.png");
break;
default:
break;
}
m_Palette.setBrush(QPalette::Window, QBrush(m_pixmap.scaled(size(), Qt::IgnoreAspectRatio, Qt::SmoothTransformation)));
setPalette(m_Palette);
} void Panel::initControlWidget()
{
switch (m_currentLv) {
case LV0:
ui->pbt_startGame->setEnabled(true);
ui->pbt_pauseGame->setEnabled(false);
ui->pbt_restart->setEnabled(false);
ui->pbt_stopGame->setEnabled(false);
break;
case LV1:
case LV2:
case LV3:
case LV4:
case LV5:
ui->pbt_startGame->setEnabled(false);
ui->pbt_pauseGame->setEnabled(true);
ui->pbt_restart->setEnabled(true);
ui->pbt_stopGame->setEnabled(true);
break;
default:
break;
}
} void Panel::initGraphicsViewWidget()
{
//使用抗锯齿渲染
ui->GraphicsView->setRenderHint(QPainter::Antialiasing);
//设置缓冲背景,加速渲染
ui->GraphicsView->setCacheMode(QGraphicsView::CacheBackground); m_scene = new QGraphicsScene(this);
m_scene->setSceneRect(30,30,310,410);
ui->GraphicsView->setScene(m_scene); //方块可移动的四条线
//向外扩展3像素,这样可以使方块组到达边界的时候再移动就会发生碰撞
m_topLine = m_scene->addLine(32,32,238,32);
m_leftLine = m_scene->addLine(32,32,32,438);
m_buttomLine = m_scene->addLine(32,438,238,438);
m_rightLine = m_scene->addLine(238,32,238,438); m_topLine->setPen(QPen(QColor(255,255,255)));
m_leftLine->setPen(QPen(QColor(255,255,255)));
m_buttomLine->setPen(QPen(QColor(255,255,255)));
m_rightLine->setPen(QPen(QColor(255,255,255))); m_currentBox = new pieceBox;
m_nextBox = new pieceBox;
connect(m_currentBox,SIGNAL(signal_needNewBox()),this,SLOT(slot_clearFullRows()));
connect(m_currentBox,SIGNAL(signal_gameOver()),this,SLOT(slot_gameOver()));
m_scene->addItem(m_currentBox);
m_scene->addItem(m_nextBox);
} void Panel::startGame()
{
m_currentBox->createBox(QPointF(135,55));
m_nextBox->createBox(QPointF(290,55));
//将键盘焦点给当前的方块组
m_currentBox->setFocus();
m_currentBox->slot_startTimer(m_currentLVSpeed);
} void Panel::updateScore(const int fullRows)
{
int score = ui->LCDNum_Score->value() + fullRows*ROWSCORE; ui->LCDNum_Score->display(score);
if(score < 1000) //第一关
{ }else if(score < 2000) //第二关
{
setbackground(LV2);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else if(score < 4000) //第三关
{
setbackground(LV3);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else if(score < 8000) //第四关
{
setbackground(LV4);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else if(score < 16000) //第五关
{
setbackground(LV5);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}else //从第一关重新开始
{
setbackground(LV1);
initControlWidget();
m_currentBox->slot_stopTimer();
m_currentBox->slot_startTimer(m_currentLVSpeed);
}
} /**
* 开始游戏
* @brief Panel::on_pbt_startGame_clicked
*/ void Panel::on_pbt_startGame_clicked()
{
m_isGameOver = false;
if(m_isPauseGame)
{
ui->pbt_startGame->setEnabled(false);
m_isPauseGame = false;
m_currentBox->slot_startTimer(m_currentLVSpeed);
return;
}
//默认等级为LV1
setbackground(LV1);
initControlWidget(); startGame();
} /**
* 暂停游戏
* @brief Panel::on_pbt_pauseGame_clicked
*/
void Panel::on_pbt_pauseGame_clicked()
{
if(m_isPauseGame)
{
return;
}
m_isPauseGame = true;
m_currentBox->slot_stopTimer();
ui->pbt_startGame->setEnabled(true);
QMessageBox::information(this,"提示","暂停游戏!",QMessageBox::Yes);
} /**
* 重新开始游戏
* @brief Panel::on_pbt_restart_clicked
*/
void Panel::on_pbt_restart_clicked()
{ m_currentBox->slot_stopTimer();
m_currentBox->clearBoxGroup();
m_nextBox->clearBoxGroup(true);
//先将当前的小正方形组移出游戏框,防止下面的清除item将该方块组清除了
m_currentBox->setPos(290,55);
ui->LCDNum_Score->display(0); //清空视图中所有的小方块
foreach (QGraphicsItem *item, m_scene->items(34, 34, 204, 404, Qt::ContainsItemShape,Qt::AscendingOrder)) {
// 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
// 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
m_scene->removeItem(item);
onePiece *piece = (onePiece*) item;
piece->deleteLater();
}
m_isPauseGame = false;
on_pbt_startGame_clicked();
} /**
* 停止游戏
* @brief Panel::on_pbt_stopGame_clicked
*/
void Panel::on_pbt_stopGame_clicked()
{
m_currentBox->slot_stopTimer();
slot_gameOver();
} /**清除满行的小方块
* @brief Panel::slot_clearFullRows
*/
void Panel::slot_clearFullRows()
{
m_rowList.clear();
//获取比一行方格多行的所有小方块,不包含最高的一行
for(int i = 414;i > 35; i-=20)
{
//返回可视区域(202*22)内所有的完全可视的item
QList<QGraphicsItem *> itemList = m_scene->items(34,i,204,22,Qt::ContainsItemShape,Qt::AscendingOrder);
// qDebug() << "可是区域内的item数:" << itemList.count();
//已满
if(itemList.count() == 10)
{
//遍历列表删除小方块
foreach (QGraphicsItem *item, itemList) {
onePiece *piece = (onePiece *)item; //模糊效果,先放大再缩小
QGraphicsBlurEffect *blurEffect = new QGraphicsBlurEffect;
piece->setGraphicsEffect(blurEffect);
QPropertyAnimation *animation = new QPropertyAnimation(piece,"scale");
animation->setDuration(250);
animation->setEasingCurve(QEasingCurve::OutBounce);
animation->setStartValue(4);
animation->setEndValue(0.25);
animation->start(QAbstractAnimation::DeleteWhenStopped);
connect(animation,SIGNAL(finished()),piece,SLOT(deleteLater()));
}
m_mediaPlayer->play();
//记录满行的行地址
m_rowList.append(i);
}
}
// qDebug() << "满行的行数:" << m_rowList.size();
//存在满行,删除后将上面的方块下移
if(!m_rowList.isEmpty())
{
//等待所有的小正方形都销毁后再将上方的小正方形向下移动
QTimer::singleShot(300,this,SLOT(slot_moveBox()));
}else //直接创建新的方块组
{
m_currentBox->createBox(QPointF(135,55), m_nextBox->getCurrentBoxType());
// 清空并销毁提示方块组中的所有小方块
m_nextBox->clearBoxGroup(true);
if(!m_isGameOver)
{
m_nextBox->createBox(QPointF(290,55));
}
}
} void Panel::slot_gameOver()
{
// qDebug() << "game over";
m_isGameOver = true;
QMessageBox::information(this,"提示",QString("您的游戏得分为%1!").arg(ui->LCDNum_Score->value()),QMessageBox::Yes);
ui->LCDNum_Score->display(0);
m_currentBox->clearFocus(); setbackground(LV0);
initControlWidget();
m_isPauseGame = false;
//初始化界面
m_currentBox->clearBoxGroup(true);
m_nextBox->clearBoxGroup(true);
//先将当前的小正方形组移出游戏框,防止下面的清除item将该方块组清除了
m_currentBox->setPos(290,55);
//清空视图中所有的小方块
foreach (QGraphicsItem *item, m_scene->items(34, 34, 204, 404, Qt::ContainsItemShape,Qt::AscendingOrder)) {
// 先从场景中移除小方块,因为使用deleteLater()是在返回主事件循环后才销毁
// 小方块的,为了在出现新的方块组时不发生碰撞,所以需要先从场景中移除小方块
m_scene->removeItem(item);
onePiece *piece = (onePiece*) item;
piece->deleteLater();
}
} /**清空满行的小方块后向下移动上面的小方块
* @brief Panel::slot_moveBox
*/
void Panel::slot_moveBox()
{
// 从位置最靠上的满行开始
for (int i = m_rowList.count(); i > 0; i--)
{
foreach (QGraphicsItem *item, m_scene->items(34, 34, 206, m_rowList.at(i-1) - 32, Qt::ContainsItemShape,Qt::AscendingOrder)) {
item->moveBy(0, 20);
}
}
// 更新分数
updateScore(m_rowList.count());
// 将满行列表清空为0
m_rowList.clear(); // 等所有行下移以后再出现新的方块组
m_currentBox->createBox(QPointF(135,55), m_nextBox->getCurrentBoxType());
// 清空并销毁提示方块组中的所有小方块
m_nextBox->clearBoxGroup(true);
m_nextBox->createBox(QPointF(290,55)); }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362

http://blog.csdn.net/sxpsxp12/article/details/50607224

Qt5图形视图框架的“俄罗斯方块”(使用了QGraphicsView)的更多相关文章

  1. Qt图形视图框架公开课资料

    接受CSDN学院的邀请,讲一次公开课,主题是Qt图形视图框架,报名链接在这里:http://edu.csdn.net/huiyiCourse/detail/228. 内容有两部分:自定义Item和拖放 ...

  2. Qt之图形视图框架

    简述 图形视图(Graphics View)提供了一个平台,用于大量自定义2D图元的管理与交互,并提供了一个视图部件(view widget)来显示可以缩放和旋转的图元. 框架包括一个事件传播架构,支 ...

  3. 用Qt图形视图框架开发拼图游戏

    用Qt的图形视图框架(Graphics View Framework)做了一个拼图游戏DEMO,演示了: QGraphicsView.QGraphicsScene.QGraphicsItem的基本用法 ...

  4. Qt-MVC图形视图框架分解

    前面在<Qt-MVC图形视图框架出识>中我们了解了Qt图形视图框架中三个最基本的类,弄清他们的关系,本片小文,我们将对QGraphicsView,QGraphiceScene,QGraph ...

  5. Qt-MVC图形视图框架初识

    使用QPushButton.QLabel.QCheckBox等构成GUI的控件或自定义图形时,开发应用程序会变得很简单.但是如果想在GUI中使用数十个或者数百个图形对象,向用户完美展示控制场景,则会受 ...

  6. Qt 2D绘图之六:图形视图框架的事件处理与传播

    一.简介 图形视图框架中的事件都是首先由视图进行接收,然后传递给场景,再由场景传递给相应的图形项.而对于键盘事件,它会传递给获得焦点的图形项,可以使用QGraphicsScene类的setFocusI ...

  7. Qt 2D绘图之五:图形视图框架的结构和坐标系统

    一.图形视图框架的结构 在前面讲的基本绘图中,我们可以自己绘制各种图形,并且控制它们.但是,如果需要同时绘制很多个相同或不同的图形,并且要控制它们的移动.检测它们的碰撞和叠加:或者我们想让自己绘制的图 ...

  8. QT 图形视图框架

    https://blog.csdn.net/qq769651718/article/details/79357936 使用QPushButton.QLabel.QCheckBox等构成GUI的控件或自 ...

  9. Qt开发技术:图形视图框架(一)基本介绍

    前话   使用到Qt的视图框架.   Qt视图框架介绍 简介   图形视图框架(The Graphic View Framework)用于管理和与大量定制的二维图形项目交互,以及用于可视化项目的视图小 ...

随机推荐

  1. Atititjs javascript异常处理机制java异常转换.js exception process

    Atititjs javascript异常处理机制java异常的转换.js exception process 1. javascript异常处理机制 Throw str Not throw erro ...

  2. Eclipse使用技巧总结(四)——代码重构专题

    二十四.重命名 这样重命名就方便多了,不需要一个一个去改了 二十五.移动类和方法 二十六.改变方法 二十七.转换匿名内部类到外部 二十八.提取接口 二十九.抽取成单独方法: Refactor--> ...

  3. HashMap工作原理的介绍!

    HashMap的工作原理是近年来常见的Java面试题.几乎每个Java程序员都知道HashMap,都知道哪里要用HashMap,知道HashTable和HashMap之间的区别,那么为何这道面试题如此 ...

  4. Mybatis 入门到理解篇

    MyBatis         MyBatis 本是apache的一个开源项目iBatis, 2010年这个项目由apache software foundation 迁移到了google code, ...

  5. 贝叶斯方法(Bayesian approach) —— 一种概率解释(probabilistic interpretation)

    1. Bayesian approach 对于多项式拟合问题,我们可通过最小二乘(least squares)的方式计算得到模型的参数,最小二乘法又可视为最大似然(maximum likelihood ...

  6. 从FrameworkElement对象创建Cursor对象

    原文:从FrameworkElement对象创建Cursor对象 Normal 0 false false false EN-US ZH-CN X-NONE MicrosoftInternetExpl ...

  7. 对XAML进行编辑的辅助类(XamlHelper)

    原文:对XAML进行编辑的辅助类(XamlHelper) // XamlHelper.cs// --------------------------------------------// 对XAML ...

  8. 新浪微博Python客户端接口OAuth2

    Keyword: Python Oauth2 微博 sina weibo #!/usr/bin/env python # -*- coding: utf-8 -*- __version__ = '1. ...

  9. 【C语言学习】C语言功能

    代码,功能为了更好地实现模块化编程.那么,什么是函数的性质?在函数中定义的变量(全局变量.局部变量.静态变量)如何存储?为什么范围和全局变量和局部变量的寿命是不一样的?只是有一个更深入的了解的功能.能 ...

  10. XMLHttpRequest 请求java部署的webservice 跨域问题

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <html> <hea ...