搜档网
当前位置:搜档网 › Qt学习笔记--图形视图框架

Qt学习笔记--图形视图框架

Qt学习笔记--图形视图框架
Qt学习笔记--图形视图框架

Qt学习笔记--图形视图框架(一)

2010-07-11 07:40

优点:处理多个图元,单击,拖动,选择图元

架构:一个场景,多个图元位于其中,通过视图显示

主要应用: 绘图软件,显示地图软件

当使用没有变换的视图观察场景时,场景中的一个单元对应屏幕上的一个像素

图元坐标通常以图元中心为原点,X轴正方向为向右,Y轴正方向为向下

场景坐标的原点在场景中心,X轴正方向为向右,Y轴正方向为向下

视图坐标以左上角为原点,X轴正方向为向右,Y轴正方向为向下

所有的鼠标事件最开始都是使用视图坐标

场景:图元的容器

1.提供管理很多图元的接口

2.传播事件到图元中

3.管理图元状态,例如选择和焦点处理

4.提供非转换的绘制功能,主要用于打印

QGraphicsScene scene;

QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100)); // 添加图元QGraphicsItem *item = scene.itemAt(50, 50); // 查询图元

// item == rect;

通过QGraphicsScene::setSelectionArea()可以选择场景的任一个图元,QGraphicsScene::setSelectedItems()返回被选择的图元

设置焦点图元QGraphicsScene::setFocusItem(), setFocus(), QGraphicsScene::focusItem(), 返回焦点图元

视图:

一个可视的子部件,可视化场景的内容

多个视图可以显示同一个场景

坐标转换:QGraphicsView::mapToScene(), QGraphicsView::mapFromScene()

图元:

支持鼠标事件,滚轮事件,上下文菜单事件

支持键盘输入焦点,按键事件

支持拖放

支持分组

冲突探测

提供坐标转换,图元与场景,图元与图元之间

利用QGraphicsItem::shape()和QGraphicsItem::collidesWith()

实现冲突探测,这2个函数都是虚函数

相关类:QGraphicsScene, QGraphicsItem, QGraphicsView

QGraphicsItem子类:

QGraphicsEllipseItem provides an ellipse item

QGraphicsLineItem provides a line item

QGraphicsPathItem provides an arbitrary path item QGraphicsPixmapItem provides a pixmap item

QGraphicsPolygonItem provides a polygon item

QGraphicsRectItem provides a rectangular item QGraphicsSimpleTextItem provides a simple text label item

QGraphicsTextItem provides an advanced text browser item QGraphicsSvgItem provides a SVG file item

QGraphicsScene:

拥有多个图元,包含三层:背景层,图元层,前景层

背景层和前景层可以使用QBrush绘制,也可以使用drawBackground(),drawForeground()实现

如果使用图片作为背景,可以用texture QBrush(pixmap)实现

前景层brush可以使用半透明的白色实现褪色效果,或者使用交叉模式实现网格重叠

场景可以告诉我们,哪些图元发生冲突,哪些图元被选择,哪些图元位于一个特定的点或者区域

每个图元可以是:1.顶级图元,场景是它的父亲;2.孩子,它的父亲是另一个图元,任何作用于父图元的转换

都将自动应用于它的孩子

2种分组方式:1.一个图元成为另一个图元的孩子;2.使用QGraphicsItemGroup。使用分组,可以使位于同一个

组的所有图元的操作都相同

QGraphicsView:

是一个Widget,用于显示一个场景,提供滚动条功能和转换功能,可以缩放和旋转场景。

默认使用内建的2D画图引擎,可以使用OpenGL:在构造后,调用setViewport()

坐标系统:

使用3种坐标系统:viewport, scene, item

viewport: 位于QGraphicsView内部

scene: 逻辑坐标用于定位顶级图元

item: 与图元相关,以图元的(0,0)为中心,移动图元时,它的坐标不会改变

实践中,主要关注场景坐标(定位顶级图元)和图元坐标(定位子图元和绘制图元)

在图元自己的坐标系统里面绘图意味着我们不用担心它在场景中的位置和应用于它的坐标转换

Demo:

// 主要特点:

// 上下文菜单, 右键菜单

// copy->paste方法

//diagram.pro

TEMPLATE = app

HEADERS = diagramwindow.h \

link.h \

node.h \

propertiesdialog.h

SOURCES = diagramwindow.cpp \

link.cpp \

main.cpp \

node.cpp \

propertiesdialog.cpp

FORMS = propertiesdialog.ui

RESOURCES = resources.qrc

//link.h

#ifndef LINK_H

#define LINK_H

#include

class Node;

class Link : public QGraphicsLineItem // 如果使用信号和槽,采用多继承public QObject

{

public:

Link(Node *fromNode, Node *toNode);

~Link();

Node *fromNode() const;

Node *toNode() const;

void setColor(const QColor &color);

QColor color() const;

void trackNodes(); // 节点移动时,跟踪节点

private:

Node *myFromNode; // 连线的2个节点

Node *myToNode;

};

#endif

//link.cpp

#include

#include "link.h"

#include "node.h"

Link::Link(Node *fromNode, Node *toNode)

{

myFromNode = fromNode;

myToNode = toNode;

myFromNode->addLink(this); // 节点增加连线,每个节点有任意多个连线myToNode->addLink(this);

setFlags(QGraphicsItem::ItemIsSelectable); // 连线可以被选择,然后删除setZValue(-1); // 在场景中显示的前后层次,因为连线是两个节点的中心,-1表示位于最后面,

// 节点覆盖了部分连线

setColor(Qt::darkRed); // 设置线的颜色

trackNodes();

}

Link::~Link()

{

myFromNode->removeLink(this); // 删除连线时,将删除它在节点中的记录myToNode->removeLink(this);

}

Node *Link::fromNode() const

{

return myFromNode;

}

Node *Link::toNode() const

{

return myToNode;

}

void Link::setColor(const QColor &color)

{

setPen(QPen(color, 1.0));

}

QColor Link::color() const

{

return pen().color();

}

void Link::trackNodes()

{

// pos()返回节点在场景中或者父图元中的位置

setLine(QLineF(myFromNode->pos(), myToNode->pos()));

}

//node.h

#ifndef NODE_H

#define NODE_H

#include

#include

#include

#include

class Link;

class Node : public QGraphicsItem

{

Q_DECLARE_TR_FUNCTIONS(Node) // 在此类中增加tr()功能,直接使用,而不需要QObject::tr()了

public:

Node();

~Node();

void setText(const QString &text);

QString text() const;

void setTextColor(const QColor &color);

QColor textColor() const;

void setOutlineColor(const QColor &color);

QColor outlineColor() const;

void setBackgroundColor(const QColor &color);

QColor backgroundColor() const;

void addLink(Link *link);

void removeLink(Link *link);

QRectF boundingRect() const; // 重新实现,决定一个图元是否需要绘制,必须的

QPainterPath shape() const; // 重新实现,返回图元的精确形状,

// 决定一个点是否在图元内,或者2个图元是否发生冲突

void paint(QPainter *painter, // 重新实现,画图,必须的

const QStyleOptionGraphicsItem *option, QWidget *widget);

protected:

void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); // 双击事件,修改节点的文本

QVariant itemChange(GraphicsItemChange change, // 重新实现,图元变化时,相关的连线发生变化

const QVariant &value); // 没有使用mouseMoveEvent(),

// 是因为程序可以改变节点位置

private:

QRectF outlineRect() const;

int roundness(double size) const;

QSet myLinks;

QString myText;

QColor myTextColor;

QColor myBackgroundColor;

QColor myOutlineColor;

};

#endif

//link.cpp

#include

#include "link.h"

#include "node.h"

Node::Node()

{

myTextColor = Qt::darkGreen;

myOutlineColor = Qt::darkBlue;

myBackgroundColor = Qt::white;

setFlags(ItemIsMovable | ItemIsSelectable); // 节点可以移动,被选择

}

Node::~Node()

{

foreach (Link *link, myLinks) // 删除所有的连线,防止边界效应,不使用aDeleteAll()

delete link;

}

void Node::setText(const QString &text)

{

prepareGeometryChange(); // 改变节点内的文本时,矩形可能会发生变化myText = text;

update();

}

QString Node::text() const

{

return myText;

}

void Node::setTextColor(const QColor &color)

{

myTextColor = color;

update();

}

QColor Node::textColor() const

{

return myTextColor;

}

void Node::setOutlineColor(const QColor &color)

{

myOutlineColor = color;

update();

}

QColor Node::outlineColor() const

{

return myOutlineColor;

}

void Node::setBackgroundColor(const QColor &color)

{

myBackgroundColor = color;

update();

}

QColor Node::backgroundColor() const

{

return myBackgroundColor;

}

void Node::addLink(Link *link)

{

myLinks.insert(link); // 增加连线时,记录连线

}

void Node::removeLink(Link *link)

{

myLinks.remove(link);

}

QRectF Node::boundingRect() const // View决定是否绘制矩形{

const int Margin = 1;

return outlineRect().adjusted(-Margin, -Margin, +Margin, +Margin); }

QPainterPath Node::shape() const // View用于冲突探测

{

QRectF rect = outlineRect();

QPainterPath path;

path.addRoundRect(rect, roundness(rect.width()),

roundness(rect.height()));

return path;

}

// 绘制图元

void Node::paint(QPainter *painter,

const QStyleOptionGraphicsItem *option,

QWidget * /* widget */)

{

QPen pen(myOutlineColor);

if (option->state & QStyle::State_Selected) { // 图元被选择

pen.setStyle(Qt::DotLine);

pen.setWidth(2);

}

painter->setPen(pen);

painter->setBrush(myBackgroundColor);

QRectF rect = outlineRect();

painter->drawRoundRect(rect, roundness(rect.width()),

roundness(rect.height()));

painter->setPen(myTextColor);

painter->drawText(rect, Qt::AlignCenter, myText);

}

// 双击节点,弹出标准输入对话框

void Node::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {

QString text = QInputDialog::getText(event->widget(),

tr("Edit Text"), tr("Enter new text:"),

QLineEdit::Normal, myText);

if (!text.isEmpty())

setText(text);

}

// 拖动节点时,调用此函数

QVariant Node::itemChange(GraphicsItemChange change,

const QVariant &value)

{

if (change == ItemPositionHasChanged) {

foreach (Link *link, myLinks)

link->trackNodes();

}

return QGraphicsItem::itemChange(change, value);

}

QRectF Node::outlineRect() const

{

const int Padding = 8;

QFontMetricsF metrics = qApp->font();

QRectF rect = metrics.boundingRect(myText); rect.adjust(-Padding, -Padding, +Padding, +Padding); rect.translate(-rect.center());

return rect;

}

int Node::roundness(double size) const

{

const int Diameter = 12;

return 100 * Diameter / int(size);

}

// diagramwindow.h

#ifndef DIAGRAMWINDOW_H

#define DIAGRAMWINDOW_H

#include

#include

class QAction;

class QGraphicsItem;

class QGraphicsScene;

class QGraphicsView;

class Link;

class Node;

class DiagramWindow : public QMainWindow

{

Q_OBJECT

public:

DiagramWindow();

private slots:

void addNode();

void addLink();

void del();

void cut();

void copy();

void paste();

void bringToFront();

void sendToBack();

void properties(); // 弹出属性设置对话框

void updateActions(); // 更新菜单栏和工具栏的动作,哪些可用,哪些不可用private:

typedef QPair NodePair;

void createActions();

void createMenus();

void createToolBars();

void setZValue(int z);

void setupNode(Node *node);

Node *selectedNode() const;

Link *selectedLink() const;

NodePair selectedNodePair() const;

QMenu *fileMenu;

QMenu *editMenu;

QToolBar *editToolBar;

QAction *exitAction;

QAction *addNodeAction;

QAction *addLinkAction;

QAction *deleteAction;

QAction *cutAction;

QAction *copyAction;

QAction *pasteAction;

QAction *bringToFrontAction;

QAction *sendToBackAction;

QAction *propertiesAction;

QGraphicsScene *scene;

QGraphicsView *view;

int minZ; // sendToBack(), bringToFront()使用

int maxZ;

int seqNumber; // 唯一标示一个节点的文本

};

#endif

//digramwindow.cpp

#include

#include "diagramwindow.h"

#include "link.h"

#include "node.h"

#include "propertiesdialog.h"

DiagramWindow::DiagramWindow()

{

scene = new QGraphicsScene(0, 0, 600, 500); // 创建场景,起始点为(0,0), 宽600,高500

view = new QGraphicsView;

view->setScene(scene); // 显示场景

view->setDragMode(QGraphicsView::RubberBandDrag); // 选择多个节点方式:1.按ctrl;2.设置橡皮筋方式

view->setRenderHints(QPainter::Antialiasing

| QPainter::TextAntialiasing);

view->setContextMenuPolicy(Qt::ActionsContextMenu); // 右键菜单setCentralWidget(view);

minZ = 0;

maxZ = 0;

seqNumber = 0;

createActions();

createMenus();

createToolBars();

connect(scene, SIGNAL(selectionChanged()),

this, SLOT(updateActions()));

setWindowTitle(tr("Diagram"));

updateActions();

}

// 增加一个节点

void DiagramWindow::addNode()

{

Node *node = new Node;

node->setText(tr("Node %1").arg(seqNumber + 1));

setupNode(node);

}

void DiagramWindow::addLink()

{

NodePair nodes = selectedNodePair();

if (nodes == NodePair())

return;

Link *link = new Link(nodes.first, nodes.second);

scene->addItem(link);

}

// 删除选择的图元:首先删除连线,然后删除节点,以防止多次删除同一个连线void DiagramWindow::del()

{

QList items = scene->selectedItems();

QMutableListIterator it(items);

while (it.hasNext()) {

Link *link = dynamic_cast(it.next());

if (link) {

delete link;

it.remove();

}

}

qDeleteAll(items);

}

// 剪切操作:先复制,后删除

void DiagramWindow::cut()

{

Node *node = selectedNode();

if (!node)

return;

copy();

delete node;

}

// 拷贝操作:值得研究!!!

void DiagramWindow::copy()

{

Node *node = selectedNode();

if (!node)

return;

QString str = QString("Node %1 %2 %3 %4")

.arg(node->textColor().name())

.arg(node->outlineColor().name())

.arg(node->backgroundColor().name())

.arg(node->text());

QApplication::clipboard()->setText(str);

}

void DiagramWindow::paste()

{

QString str = QApplication::clipboard()->text();

QStringList parts = str.split(" ");

if (parts.count() >= 5 && parts.first() == "Node") {

Node *node = new Node;

node->setText(QStringList(parts.mid(4)).join(" ")); // 连接字符串列表

node->setTextColor(QColor(parts[1]));

node->setOutlineColor(QColor(parts[2]));

node->setBackgroundColor(QColor(parts[3]));

setupNode(node);

}

}

void DiagramWindow::bringToFront()

{

++maxZ;

setZValue(maxZ); // 改变绘图顺序,首先绘制父图元,然后是子图元,根据子图元Z值的大小,

// 值最小,最先绘制,值最大,最后绘制

}

void DiagramWindow::sendToBack()

{

--minZ;

setZValue(minZ);

}

void DiagramWindow::properties()

{

Node *node = selectedNode();

Link *link = selectedLink();

if (node) {

PropertiesDialog dialog(node, this);

dialog.exec();

} else if (link) {

QColor color = QColorDialog::getColor(link->color(), this);

if (color.isValid())

link->setColor(color);

}

}

// 更新动作使能

void DiagramWindow::updateActions()

{

bool hasSelection = !scene->selectedItems().isEmpty();

bool isNode = (selectedNode() != 0);

bool isNodePair = (selectedNodePair() != NodePair());

cutAction->setEnabled(isNode);

copyAction->setEnabled(isNode);

addLinkAction->setEnabled(isNodePair);

deleteAction->setEnabled(hasSelection);

bringToFrontAction->setEnabled(isNode);

sendToBackAction->setEnabled(isNode);

propertiesAction->setEnabled(isNode);

foreach (QAction *action, view->actions())

view->removeAction(action); // 删除右键菜单

foreach (QAction *action, editMenu->actions()) {

if (action->isEnabled())

view->addAction(action); // 增加右键菜单

}

}

void DiagramWindow::createActions()

{

exitAction = new QAction(tr("E&xit"), this);

exitAction->setShortcut(tr("Ctrl+Q"));

connect(exitAction, SIGNAL(triggered()), this, SLOT(close())); addNodeAction = new QAction(tr("Add &Node"), this); addNodeAction->setIcon(QIcon(":/images/node.png")); addNodeAction->setShortcut(tr("Ctrl+N"));

connect(addNodeAction, SIGNAL(triggered()), this, SLOT(addNode()));

addLinkAction = new QAction(tr("Add &Link"), this); addLinkAction->setIcon(QIcon(":/images/link.png")); addLinkAction->setShortcut(tr("Ctrl+L"));

connect(addLinkAction, SIGNAL(triggered()), this, SLOT(addLink())); deleteAction = new QAction(tr("&Delete"), this);

deleteAction->setIcon(QIcon(":/images/delete.png"));

deleteAction->setShortcut(tr("Del"));

connect(deleteAction, SIGNAL(triggered()), this, SLOT(del())); cutAction = new QAction(tr("Cu&t"), this);

cutAction->setIcon(QIcon(":/images/cut.png"));

cutAction->setShortcut(tr("Ctrl+X"));

connect(cutAction, SIGNAL(triggered()), this, SLOT(cut())); copyAction = new QAction(tr("&Copy"), this);

copyAction->setIcon(QIcon(":/images/copy.png"));

copyAction->setShortcut(tr("Ctrl+C"));

connect(copyAction, SIGNAL(triggered()), this, SLOT(copy())); pasteAction = new QAction(tr("&Paste"), this);

pasteAction->setIcon(QIcon(":/images/paste.png"));

pasteAction->setShortcut(tr("Ctrl+V"));

connect(pasteAction, SIGNAL(triggered()), this, SLOT(paste())); bringToFrontAction = new QAction(tr("Bring to &Front"), this); bringToFrontAction->setIcon(QIcon(":/images/bringtofront.png")); connect(bringToFrontAction, SIGNAL(triggered()),

this, SLOT(bringToFront()));

sendToBackAction = new QAction(tr("&Send to Back"), this); sendToBackAction->setIcon(QIcon(":/images/sendtoback.png")); connect(sendToBackAction, SIGNAL(triggered()),

this, SLOT(sendToBack()));

propertiesAction = new QAction(tr("P&roperties..."), this);

connect(propertiesAction, SIGNAL(triggered()),

this, SLOT(properties()));

}

void DiagramWindow::createMenus()

{

fileMenu = menuBar()->addMenu(tr("&File"));

fileMenu->addAction(exitAction);

editMenu = menuBar()->addMenu(tr("&Edit")); editMenu->addAction(addNodeAction);

editMenu->addAction(addLinkAction);

editMenu->addAction(deleteAction);

editMenu->addSeparator();

editMenu->addAction(cutAction);

editMenu->addAction(copyAction);

editMenu->addAction(pasteAction);

editMenu->addSeparator();

editMenu->addAction(bringToFrontAction); editMenu->addAction(sendToBackAction); editMenu->addSeparator();

editMenu->addAction(propertiesAction);

}

void DiagramWindow::createToolBars()

{

editToolBar = addToolBar(tr("Edit"));

editToolBar->addAction(addNodeAction); editToolBar->addAction(addLinkAction); editToolBar->addAction(deleteAction); editToolBar->addSeparator();

editToolBar->addAction(cutAction);

editToolBar->addAction(copyAction); editToolBar->addAction(pasteAction); editToolBar->addSeparator();

editToolBar->addAction(bringToFrontAction); editToolBar->addAction(sendToBackAction);

}

void DiagramWindow::setZValue(int z)

{

Node *node = selectedNode();

if (node)

node->setZValue(z);

}

void DiagramWindow::setupNode(Node *node) {

node->setPos(QPoint(80 + (100 * (seqNumber % 5)), 80 + (50 * ((seqNumber / 5) % 7))));

scene->addItem(node);

++seqNumber;

scene->clearSelection();

node->setSelected(true);

bringToFront();

}

// 返回一个选择的节点

Node *DiagramWindow::selectedNode() const

{

QList items = scene->selectedItems(); // 全部选择的节点if (items.count() == 1) {

return dynamic_cast(items.first());

} else {

return 0;

}

}

Link *DiagramWindow::selectedLink() const

{

QList items = scene->selectedItems();

if (items.count() == 1) {

return dynamic_cast(items.first());

} else {

return 0;

}

}

// 返回选择的节点对

DiagramWindow::NodePair DiagramWindow::selectedNodePair() const

{

QList items = scene->selectedItems();

if (items.count() == 2) {

Node *first = dynamic_cast(items.first());

Node *second = dynamic_cast(https://www.sodocs.net/doc/0412580842.html,st());

if (first && second)

return NodePair(first, second);

}

return NodePair();

}

// propertiesdialog.h

#ifndef PROPERTIESDIALOG_H

#define PROPERTIESDIALOG_H

#include "ui_propertiesdialog.h"

class Node;

class PropertiesDialog : public QDialog, private Ui::PropertiesDialog {

Q_OBJECT

public:

PropertiesDialog(Node *node, QWidget *parent = 0);

private slots:

void on_buttonBox_accepted(); // 快速信号连接

void on_textColorButton_clicked();

void on_outlineColorButton_clicked();

void on_backgroundColorButton_clicked();

private:

void updateColorLabel(QLabel *label, const QColor &color);

void chooseColor(QLabel *label, QColor *color);

Node *node;

QColor textColor;

QColor outlineColor;

QColor backgroundColor;

};

#endif

//propertiesdialog.cpp

#include

#include "node.h"

#include "propertiesdialog.h"

PropertiesDialog::PropertiesDialog(Node *node, QWidget *parent) : QDialog(parent)

{

setupUi(this);

this->node = node;

xSpinBox->setValue(int(node->x()));

ySpinBox->setValue(int(node->y()));

textLineEdit->setText(node->text());

textColor = node->textColor();

outlineColor = node->outlineColor();

backgroundColor = node->backgroundColor(); updateColorLabel(outlineColorLabel, outlineColor); updateColorLabel(backgroundColorLabel, backgroundColor); updateColorLabel(textColorLabel, textColor);

}

void PropertiesDialog::on_buttonBox_accepted()

{

node->setPos(xSpinBox->value(), ySpinBox->value());

node->setText(textLineEdit->text());

node->setOutlineColor(outlineColor);

node->setBackgroundColor(backgroundColor);

node->setTextColor(textColor);

node->update();

QDialog::accept();

}

void PropertiesDialog::on_textColorButton_clicked()

{

chooseColor(textColorLabel, &textColor);

}

void PropertiesDialog::on_outlineColorButton_clicked()

{

chooseColor(outlineColorLabel, &outlineColor);

}

void PropertiesDialog::on_backgroundColorButton_clicked()

{

chooseColor(backgroundColorLabel, &backgroundColor);

}

void PropertiesDialog::updateColorLabel(QLabel *label,

const QColor &color)

{

QPixmap pixmap(16, 16);

pixmap.fill(color);

label->setPixmap(pixmap);

}

void PropertiesDialog::chooseColor(QLabel *label, QColor *color)

软件架构 4+1 视图模型

RUP 4+1架构 软件需求分析的复杂性 图1 软件需求分类的复杂性

RUP 4+1架构 RUP4+1架构方法采用用例驱动,在软件生命周期的各个阶段对软件进行建模,从不同视角对系统进行解读,从而形成统一软件过程架构描述. 用例视图(Use Cases View),最初称为场景视图,关注最终用户需求, 为整个技术架构的上线文环境.通常用UML用例图和活动图描述。 逻辑视图(Logical view),主要是整个系统的抽象结构表述,关注系统提 供最终用户的功能,不涉及具体的编译即输出和部署,通常在UML中用类图, 交互图,时序图来表述,类似与我们采用OOA的对象模型。 开发视图(Development View),描述软件在开发环境下的静态组织,从程 序实现人员的角度透视系统,也叫做实现视图(implementation view)。开发 视图关注程序包,不仅包括要编写的源程序,还包括可以直接使用的第三方SDK 和现成框架、类库,以及开发的系统将运行于其上的系统软件或中间件, 在UML

中用组件图,包图来表述。开发视图和逻辑视图之间可能存在一定的映射关系:比如逻辑层一般会映射到多个程序包等。 处理视图(Process view)处理视图关注系统动态运行时,主要是进程以及相关的并发、同步、通信等问题。处理视图和开发视图的关系:开发视图一般偏重程序包在编译时期的静态依赖关系,而这些程序运行起来之后会表现为对象、线程、进程,处理视图比较关注的正是这些运行时单元的交互问题,在UML中通常用活动图表述。 物理视图(Physical view )物理视图通常也叫做部署视图(deployment view),是从系统工程师解读系统,关注软件的物流拓扑结,以及如何部署机器和网络来配合软件系统的可靠性、可伸缩性等要求。物理视图和处理视图的关系:处理视图特别关注目标程序的动态执行情况,而物理视图重视目标程序的静态位置问题;物理视图是综合考虑软件系统和整个IT系统相互影响的架构视图。 RUP4+1架构方法从1995年提出后在业界获得广泛应用,并得以发展完善,在具体应用的时候结合公司环境和项目实际进行适当裁剪。 【参考资料】: 1.IBM developerwork 运用RUP 4+1视图方法进行软件架构设计 https://www.sodocs.net/doc/0412580842.html,/developerworks/cn/rational/06/r-wenyu/index.html 架构蓝图--软件架构"4+1" 视图模型 https://https://www.sodocs.net/doc/0412580842.html,/developerworks/cn/rational/r-4p1-view/ RUP4+1架构方法 https://www.sodocs.net/doc/0412580842.html,/Leo_wl/archive/2010/12/09/1901715.html 2.

《计算机图形学实验报告》

一、实验目的 1、掌握中点Bresenham直线扫描转换算法的思想。 2掌握边标志算法或有效边表算法进行多边形填充的基本设计思想。 3掌握透视投影变换的数学原理和三维坐标系中几何图形到二维图形的观察流程。 4掌握三维形体在计算机中的构造及表示方法 二、实验环境 Windows系统, VC6.0。 三、实验步骤 1、给定两个点的坐标P0(x0,y0),P1(x1,y1),使用中点Bresenham直线扫描转换算法画出连接两点的直线。 实验基本步骤 首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。 其次、使用中点Bresenham直线扫描转换算法实现自己的画线函数,函数原型可表示如下: void DrawLine(CDC *pDC, int p0x, int p0y, int p1x, int p1y); 在函数中,可通过调用CDC成员函数SetPixel来画出扫描转换过程中的每个点。 COLORREF SetPixel(int x, int y, COLORREF crColor ); 再次、找到文档视图程序框架视图类的OnDraw成员函数,调用DrawLine 函数画出不同斜率情况的直线,如下图:

最后、调试程序直至正确画出直线。 2、给定多边形的顶点的坐标P0(x0,y0),P1(x1,y1),P2(x2,y2),P3(x3,y3),P4(x4,y4)…使用边标志算法或有效边表算法进行多边形填充。 实验基本步骤 首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。 其次、实现边标志算法或有效边表算法函数,如下: void FillPolygon(CDC *pDC, int px[], int py[], int ptnumb); px:该数组用来表示每个顶点的x坐标 py :该数组用来表示每个顶点的y坐标 ptnumb:表示顶点个数 注意实现函数FillPolygon可以直接通过窗口的DC(设备描述符)来进行多边形填充,不需要使用帧缓冲存储。(边标志算法)首先用画线函数勾画出多边形,再针对每条扫描线,从左至右依次判断当前像素的颜色是否勾画的边界色,是就开始填充后面的像素直至再碰到边界像素。注意对顶点要做特殊处理。 通过调用GDI画点函数SetPixel来画出填充过程中的每个点。需要画线可以使用CDC的画线函数MoveTo和LineTo进行绘制,也可以使用实验一实现的画直线函数。 CPoint MoveTo(int x, int y ); BOOL LineTo(int x, int y ); 实现边标志算法算法需要获取某个点的当前颜色值,可以使用CDC的成员函数 COLORREF GetPixel(int x, int y ); 再次、找到文档视图程序框架视图类的OnDraw成员函数,调用FillPolygon 函数画出填充的多边形,如下: void CTestView::OnDraw(CDC* pDC) { CTestcoodtransDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc);

--软件架构+__4+1__+视图模型

架构蓝图--软件架构"4+1" 视图模型 级别:初级 Philippe Kruchten, 高级技术专员 2005 年1 月01 日 本文基于多个并发视图的使用情况来说明描述软件密集型系统架构的模型。使用多重视图允 许独立地处理各"风险承担人":最终用户、开发人员、系统工程师、项目经理等所关注的问 题,并且能够独立地处理功能性和非功能性需求。本文分别对五种视图进行了描述,并同时 给出了捕获每种视图的表示方法。这些视图使用以架构为中心的、场景驱动以及迭代开发过 程来进行设计。 引言 我们已经看到在许多文章和书籍中,作者欲使用单张视图来捕捉所有的系统架构要点。通过仔细地观察这些图例中的方框和箭头,不难发现作者努力地在单一视图中表达超过其表达限度的蓝图。方框是代表运行的程序吗?或者是代表源代码的程序块吗?或是物理计算机吗?或仅仅是逻辑功能的分组吗?箭头是表示编译时的依赖关系吗?或者是控制流吗?或是数据流吗?通常它代表了许多事物。是否架构只需要单个的架构样式?有时软件架构的缺陷源于过早地划分软件或过分的强调软件开发的单个方面:数据工程、运行效率、开发策略和团队组织等。有时架构并不能解决所有"客户"(或者说"风险承担人",USC 的命名)所关注的问题。许多作者都提及了这个问题:Garlan & Shaw 1、CMU 的Abowd & Allen、SEI 的Clements。作为补充,我们建议使用多个并发的视图来组织软件架构的描述,每个视图仅用来描述一个特定的所关注的方面的集合。 回 架构模型 软件架构用来处理软件高层次结构的设计和实施。它以精心选择的形式将若干结构元素进行装配,从而满足系统主要功能和性能需求,并满足其他非功能性需求,如可靠性、可伸缩性、可移植性和可用性。Perry 和Wolfe 使用一个精确的公式来表达,该公式由Boehm 做了进一步修改: 软件架构={元素,形式,关系/约束} 软件架构涉及到抽象、分解和组合、风格和美学。我们用由多个视图或视角组成的模型来描述它。为了最终处理大型的、富有挑战性的架构,该模型包含五个主要的视图(请对照图1):?逻辑视图(Logical View),设计的对象模型(使用面向对象的设计方法时)。 ?过程视图(Process View),捕捉设计的并发和同步特征。 ?物理视图(Physical View),描述了软件到硬件的映射,反映了分布式特性。 ?开发视图(Development View),描述了在开发环境中软件的静态组织结构。 架构的描述,即所做的各种决定,可以围绕着这四个视图来组织,然后由一些用例(use cases)或场景(scenarios)来说明,从而形成了第五个视图。正如将看到的,实际上软件架构部分从这些场景演进而来,将在下文中讨论。 图1 -"4+1"视图模型

利用“4+1”视图建模方法进行“网上选课系统”软件体系结构设计

利用“4+1”视图建模方法进行“网上选课系统”软件体系结构设计 所学专业:软件工程 年级班级: 2010级软工-2 班 所属小组:第六组 组负责人:耿奇云 组内成员:耿奇云郜振南杨建威 成员学号: 1010107041 1010107040 1010107054 河南农业大学信息与管理科学学院 2012年12月19日

一、引言 (一)运用4+1视图方法:针对不同需求进行架构设计 要开发出用户满意的软件并不是件容易的事,软件架构师必须全面把握各种各样的需求、权衡需求之间有可能的矛盾之处,分门别类地将不同需求一一满足。Philippe Kruchten提出的4+1视图方法为软件架构师"一一征服需求"提供了良好基础,如图1示。 图1运用4+1视图方法针对不同需求进行架构设计场景视图:场景视图关注案例描述,即对案软件需求的功能描述和非功能描述;对应于UML建模中的用例建模。 逻辑视图:逻辑视图关注功能,不仅包括用户可见的功能,还包括为实现用户功能而必须提供的"辅助功能模块";它们可能是逻辑层、功能模块等。 开发视图:开发视图关注程序包,不仅包括要编写的源程序,还包括可以直接使用的第三方SDK和现成框架、类库,以及开发的系统将运行于其上的系统软件或中间件。开发视图和逻辑视图之间可能存在一定的映射关系:比如逻辑层一般会映射到多个程序包等。 处理视图:处理视图关注进程、线程、对象等运行时概念,以及相关的并发、同步、通信等问题。处理视图和开发视图的关系:开发视图一般偏重程序包在编译时期的静态依赖关系,而这些程序运行起来之后会表现为对象、线程、进程,处理视图比较关注的正是这些运行时单元的交互问题。

体系结构蓝图—软件体系结构的+视图(中文版)

体系结构蓝图—软件体系结构的+视图(中文版)

————————————————————————————————作者:————————————————————————————————日期:

本文基于多个并发视图的使用情况来说明描述软件密集型系统架构的模型。使用多重视图允许独立地处理各"风险承担人":最终用户、开发人员、系统工程师、项目经理等所关注的问题,并且能够独立地处理功能性和非功能性需求。本文分别对五种视图进行了描述,并同时给出了捕获每种视图的表示方法。这些视图使用以架构为中心的、场景驱动以及迭代开发过程来进行设计。 引言 我们已经看到在许多文章和书籍中,作者欲使用单张视图来捕捉所有的系统架构要点。通过仔细地观察这些图例中的方框和箭头,不难发现作者努力地在单一视图中表达超过其表达限度的蓝图。方框是代表运行的程序吗?或者是代表源代码的程序块吗?或是物理计算机吗?或仅仅是逻辑功能的分组吗?箭头是表示编译时的依赖关系吗?或者是控制流吗?或是数据流吗?通常它代表了许多事物。是否架构只需要单个的架构样式?有时软件架构的缺陷源于过早地划分软件或过分的强调软件开发的单个方面:数据工程、运行效率、开发策略和团队组织等。有时架构并不能解决所有"客户"(或者说"风险承担人",USC 的命名)所关注的问题。许多作者都提及了这个问题:Garlan & Shaw 1、CMU 的Abowd & Allen、SEI 的Clements。作为补充,我们建议使用多个并发的视图来组织软件架构的描述,每个视图仅用来描述一个特定的所关注的方面的集合。 架构模型 软件架构用来处理软件高层次结构的设计和实施。它以精心选择的形式将若干结构元素进行装配,从而满足系统主要功能和性能需求,并满足其他非功能性需求,如可靠性、可伸缩性、可移植性和可用性。Perry 和Wolfe 使用一个精确的公式来表达,该公式由Boehm 做了进一步修改: 软件架构={元素,形式,关系/约束} 软件架构涉及到抽象、分解和组合、风格和美学。我们用由多个视图或视角组成的模型来描述它。为了最终处理大型的、富有挑战性的架构,该模型包含五个主要的视图(请对照图1): ?逻辑视图(Logical View),设计的对象模型(使用面向对象的设计方法时)。 ?过程视图(Process View),捕捉设计的并发和同步特征。 ?物理视图(Physical View),描述了软件到硬件的映射,反映了分布式特性。 ?开发视图(Development View),描述了在开发环境中软件的静态组织结构。 架构的描述,即所做的各种决定,可以围绕着这四个视图来组织,然后由一些用例(use cases)或场景(scenarios)来说明,从而形成了第五个视图。正如将看到的,实际上软件架

CATIA V5R19工程 图详细制作教程

[第五章工程制图] 5.1 用户设置 5.1 用户设置 下拉菜单Tools->Option->Mechanica-> Drafting打开工程图的环境参数设定界面,用来设定不同的参数。草绘设置界面如下: 常规(General) 5.11 常规(General) 1:标尺(Ruler) 1)显示标尺(Show ruler)

2:网格显示参数 (Grid) 1)网格显示(Display):选上该选项,可以在草绘环境里显示网格线。 2)网格捕捉(Snap to point):选上该选项,可以智能捕捉到网格的交点与曲线的端点。 3)允许变形 (Allow Distortions):定义网格H间距和V间距是否保持同样的数值。 4)H 间距 (H Primary spacing):如果不勾选 (Allow Distortions)选项时,H 间距跟V间距将保持相同的数据,勾选的话可以设置不一样的距离。 5)H 刻度 (H Graduations):默认值是10,在每一个H V间距里,再分10个刻度。 6)当勾选允许变形(Allow Distortions)选项时,V值选项激活,可以输入不同的V值间距与V值刻度数值。如果不激活,V值间距与刻度数相等于H值。 3:工程图背景颜色(这里修改只对R14以前的版本有效) 4:模型树显示(Tree) 1)显示参数 (Display parameters) 2)显示关系式 (Display relations) 3)显示视图特征(Display features under views) 5:视图轴 (View axis)

1) 在当前视图中显示视图轴 (Display in the current view) 2)可缩放 (Zoomable) 3)参考尺寸 (Reference size) :修改显示大小 6:启动工作台 (Start Workbench) 1)启动工作台时隐藏新建对话框 (Hide new dialog box when starting workbench) :选上时,将隐藏新建工程图对话框。 7:图纸单位(Paper Unit) 1)单位(Unit):修改图纸创建时的尺寸单位。 布局(Layout) 5.12 布局(Layout) 1:视图创建 (View Creation) 1)视图名称 (View name):勾选选项,创建视图时自动创建视图名称。 2)缩放系数 (Scaling factor):勾选选项,创建视图时自动创建视图比例注释。3)视图框架 (View frame):勾选选项,创建视图时自动创建视图框架。 4)拓展局部和剖面规格 (Propagation of broken and breakout specifications) 5)根据轮廓定向辅助视图和剖视图 (Auxiliary and section views orientation according to profile): 6)视图轴系基于 3D 轴系 (View axis system based on 3D axis system):勾选选项后,视图坐标方向将保持一样。默认不勾选,视图方向可以基于特征方向来定位。 2:新建图纸(New Sheet)

MFC中文档视图框架和文档模板之间的关系 四个类常用的成员函数

文档对象:是用来保存数据的。 视图对象:是用来显示和编辑数据的。 应用程序框架:框架是用来管理不同文档显示界面的。例如你有一个数据网格显示界面,还有一个图形显示界面,它们的数据可能都来自你的文档,但是视图不同,怎么办用框架。为什么不用视图?为的是把界面管理独立的拿出来。 文档模板:MFC把文档/视图/框架视为一体,只要你创建文档/视图框架结构的程序,必定会为你创建这三个类。这个工作在在应用程序初始化时完成,如下: [cpp]view plaincopy 1.BOOL CMyHtmlApp::InitInstance() 2.{ 3. CSingleDocTemplate* pDocTemplate; 4. pDocTemplate = new CSingleDocTemplate( 5. IDR_MAINFRAME, 6. RUNTIME_CLASS(CMyHtmlDoc), 7. RUNTIME_CLASS(CMainFrame), // main SDI frame window 8. RUNTIME_CLASS(CMyHtmlView)); 9. AddDocTemplate(pDocTemplate); 10. } 单文档:就是一次只能打开一个文件,和你的文档类型支持的多少无关。你完全可 以做一个单文档的支持所有图象格式的程序,只不过它一次只能打开一个文档罢了。 多文档:就是你可以打开多个文件,和文档类型也无关。你也可以作一个可以同时 打开多个文档的程序,但它只支持一种文档类型。 何时需要文档/视图框架结构?

首先你可以不使用文档视图这种框架结构,即便是在MFC中。你可以在你需要的时候选择使用这种方式。你可以完成一个只有视图没有文档的程序,例如一个基于对话框的应用。 哪什么时候需要呢? 当你想将你的数据层和界面层分开的时候。 通常我们对数据的操作放在文档类中,例如存取,打开,关闭。在这里你可以尽情的对你的数据进行操作,如果你需要,在对数据进行了改变后,对视图做一下更新,那么程序会将你对数据所做的改变呈现给你的程序的用户。由此可见视图的作用就是提供一个用户和数据之间进行数据交换的界面,它的作用就是在需要的时候显示数据,并在需要的时候提供输入界面。当用户输入后实际的数据操作工作是由文档类来做的。 那框架类有在做什么呢? 框架类是为了便于管理你的文档类和视图类而存在的。通常我们的操作都是通过视图窗口完成,消息由视图进行接收并且进行处理。所以消息映射定义一般在视图中。 但如果一个应用同时拥有多个视而当前活动视没有对消息进行处理则消息会发往框架窗口。另外框架窗口可以方便的处理非窗口消息。 再来说一边典型的单文档程序的生成过程(不完整,只挑有用的) ? ?1、CwinApp对象被建立,这个对象是全局的且只能有一个,名字叫theApp。 这时你可以完成一些工作,例如对注册表的操作,(如果你想写一个不修改注册表的软件,需要在这里做写工作) 2、在InitInstance()函数中创建文档模板,文档模板以CruntimClass静态成员 指针做构造参数。 3、执行MFC框架默认的命令行参数。命令行参数有很多其中之一是,Cmd1 它会创建一个新文件。(如果没有命令行参数则执行默认的ID_FILE_NEW) 4、文档模板的实例根据三个类的动态创建信息创建出文档、视图、框架。 5、对文档、视图、框架进行初始化。

计算机图形学实验指导(一、二)

计算机图形学实验指导(一、二)

计算机图形学实验指导

实验一、直线的扫描转换算法实验 实验目的 掌握中点Bresenham直线扫描转换算法的思想。 实验环境 Windows系统, VC6.0 实验内容 问题描述:给定两个点的坐标P0(x0,y0),P1(x1,y1),使用中点Bresenham直线扫描转换算法画出连接两点的直线。 中点Bresenham直线扫描转换算法原理见课本。 实验基本步骤 首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。 其次、使用中点Bresenham直线扫描转换算法实现自己的画线函数,函数原型可表示如下: void DrawLine(CDC *pDC, int p0x, int p0y, int p1x, int p1y); 在函数中,可通过调用CDC成员函数SetPixel来画出扫描转换过程中的每个点。 COLORREF SetPixel(int x, int y, COLORREF crColor ); 再次、找到文档视图程序框架视图类的OnDraw成员函数,调用DrawLine函数画出不同斜率情况的直线,如下图:

最后、调试程序直至正确画出直线。 实验要求 1写出中点Bresenham直线扫描转换算法的程序并在vc6下编译和调试通过,画出具有各种斜率范围的直线(仅使用GDI函数SetPixel函数)。 2按规定的实验格式写出实验报告,包含实验代码(自己写的画线函数),结果(截图)。

实验二、多边形填充算法实验 实验目的 掌握边标志算法或有效边表算法进行多边形填充的基本设计思想。 实验环境 Windows系统, VC6.0 实验内容 问题描述:给定多边形的顶点的坐标P0(x0,y0),P1(x1,y1),P2(x2,y2),P3(x3,y3),P4(x4,y4)…使用边标志算法或有效边表算法进行多边形填充。 边标志算法或有效边表算法原理见课本。 实验基本步骤 首先、使用MFC AppWizard(exe)向导生成一个单文档视图程序框架。 其次、实现边标志算法或有效边表算法函数,如下: void FillPolygon(CDC *pDC, int px[], int py[], int ptnumb); px:该数组用来表示每个顶点的x坐标 py :该数组用来表示每个顶点的y坐标 ptnumb:表示顶点个数 注意实现函数FillPolygon可以直接通过窗口的DC(设备描述符)来进行多边形填充,不需要使用帧缓冲存储。(边标志算法)首先用画线函数勾画出多边形,再针对每条扫描线,从左至右依次判断当前像素的颜色是否勾画的边界色,是就开始填充后面的像素直至再碰到边界像素。注意对顶点要做特殊处理。 通过调用GDI画点函数SetPixel来画出填充过程中的每个点。需要画线可以使用CDC 的画线函数MoveTo和LineTo进行绘制,也可以使用实验一实现的画直线函数。 CPoint MoveTo(int x, int y ); BOOL LineTo(int x, int y ); 实现边标志算法算法需要获取某个点的当前颜色值,可以使用CDC的成员函数 COLORREF GetPixel(int x, int y ); 再次、找到文档视图程序框架视图类的OnDraw成员函数,调用FillPolygon函数画出填充的多边形,如下: void CTestView::OnDraw(CDC* pDC) { CTestcoodtransDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here //绘制之前先把整个窗口涂上背景色(白色)以便于下面的填充 RECT Rt;

QT动画框架

动画框架(The Animation Framework) QT的动画框架也是引入至QT4.6,很有可能是配合图形系统框架为了下一代UI 做的铺垫 动画框架的类: QAbstractAnimation The base of all animations QAnimationGroup Abstract base class for groups of animations QEasingCurve Easing curves for controlling animation QParallelAnimationGroup Parallel group of animations QPauseAnimation Pause for QSequentialAnimationGroup QPropertyAnimation Animates Qt properties QSequentialAnimationGroup Sequential group of animations QTimeLine Timeline for controlling animations QVariantAnimation Abstract base class for animations 类别 狭义的来说,Animation Framework指的是以QAbstractAnimation为基类的几个相关的Animation类,主要用途是用于动画QWidget/QObject的属性(property) 稍微放宽一点来说,还包括QTimeLine,顾名思义,它并不直接绑定并修改某个对象属性,而是根据设定的时间轴,发送信号,用于绑定特定slot,执行相关操作,所以应该不止动画,也不限于属性,你可以用它来做任何你想做的和时间轴相关的事。 其次,还有专用于QGraphicsItem的QGraphicsItemAnimation类,它主要和QTimeLine配合,控制QGraphicsItem的坐标变换矩阵 再广义一点,QT状态机在状态转换时可以绑定设置控件属性,你也可以认为这是一种动画效果,当然,如果不和一个Animation类配合的话,属性值的改变是瞬间完成的,没有中间动画过程。 特性 动画曲线 标准的Animation类,通过设置关联属性的起始和结束值,使用线性插值计算中间过程的属性值。QTimeline类也可以设置中间任意点的参数值。这样的动画效果可能不一定是你所需要的:比如模拟一个球的落地弹跳过程。通过设置动画曲线(Easing Curve),你可以制定参数的变化过程符合特定的曲线规律。

图形视图框架

图形视图框架(The QGraphics View Framework)(转) 图形视图提供了一个外表(surface)来实现大量的客户所做的2D图形项的管理和相互的结合;一个视图窗口部件来使这些项可视化,并支持缩放和旋转。 该框架包括一个事件传播体系,可以使得场景中的项的交叉可以达到双精度的精确控制。其中的项可以处理事件、鼠标按压、移动、释放和双击事件,它们也可以追踪鼠标的移动。 图形视图使用一个BSP(二进制空间分区Binary Space Partitioning)树来提供快速的项发现,正因为如此,它可以使巨大的场景实时地可视化,即便它有上百万个项(item)。 图形视图是在Qt4.2中引入的,取代了以前的QCanvas,如果需要从QCanvas移植,参见“Porting to Graphics View” 主题: ●图形视图的体系架构 ?场景(Scene) ?视图(View) ?项(Item) ●图形视图的坐标系统 ?项坐标 ?场景坐标 ?视图坐标 ?坐标映射 ●主要的特性 ?缩放和旋转 ?打印 ?拖放 ?光标和提示

?动画 ?OpenGL展示 ?项的成组 ?窗口部件和布局 ?嵌入式窗口部件支持 图形视图体系架构 图形视图提供了基于项的模型—视图编程方式,很象交互视图(InterView)的方便的类如QTableWidget,QTreeWidget,QListWidget。多个视图可以用来观察一个场景,场景包含了变化的几何形状的项。 场景(Scene) QGraphicsScene提供了图形视图的场景,场景承担下列的责任: ?提供一个快速的接口用来管理大量的项。 ?向每个项传递事件。 ?管理项的状态,如选中、焦点处理。 ?提供无变形的展示功能,主要为了打印。 场景作为QGraphicsItem对象的容器,项可以调用QGraphicsScene::addItem()加入场景。QGraphicsScene::items()和它的重载可以返回所有的项,包括点、长方形、多边形、通用矢量路径。QGraphicsScene::itemAt()返回在特定点上最上边的项。所有项发现函数可以依次返回在堆栈中的项(最先返回的是最上边的,最后返回的是最下边的)。

基于SA的UML4+1模型分析

基于SA基本特性与核心属性的UML4+1模 型分析报告 摘要:由于软件体系结构的描述方法多种多样.各种工具不仅涉及不同领域,而且描进方法不尽相同。给系统选择一种合适工具描述体系站构带来了难度。统一建模语言UML是一种 被广泛采纳的可视化建模语言。它将系统结构的共同特征用相关语义、符号、图形加以描述。Kruchten 提出了一个"4+1"视图模型,从5个不同的视角包括包括逻辑试图、进程视图、部署视图、开发视图、用例视图来描述软件体系结构。每一个视图只关心系统的一个侧面,5个试图结合在一起反映系统的软件体系结构的全部内容。 关键字:软件架构,UML,4+1模型,建模 1、引言 软件体系结构建模是工业化生产软件开发的基本工作。复杂的系统难以被人们完全理解,通过建立良好的模型,帮助我们掌握复杂的体系结构也为开发成功的软件系统打下基础。随着复杂系统的日益增加,好的建模技术也日益其重要性。在UML统一建模语言出现以前.没有一种占统治地位的建模语言。各种语言各有特色,用户必须选择几种类似的建模语言,以完成复杂的体系结构描述。大部分建模语言都有一些主要的、共同的概念,而在描述和表达方面却又有所不同.缺乏一种强大的具有扩展能力的建模语言,给使用者带来许多麻烦,不利于软件的推广和重用。”4+1’模型采用UML作为各视图的表达和解释环境,统一各部分的建模描述语言,有利于合作开发以及各层次、各环节开发人员之间的沟通,建立切合实际的模型,平衡软件质量与开发周期间的矛盾,加速软件开发和推广。 2、UML 4+1模型概述 UML的“4+1视图”是指从某个角度观察系统构成的4+1个视图,每个视图都是系统描述的一个投影,说明了系统某个侧面的特征。其包含如下的几个视图: (1)用例视图(场景视图) (2)逻辑视图 (3)开发视图 (4)进程视图 (5)部署视图(物理视图)

(完整版)体系结构蓝图—软件体系结构的4+1视图(中文版)

本文基于多个并发视图的使用情况来说明描述软件密集型系统架构的模型。使用多重视图允许独立地处理各"风险承担人":最终用户、开发人员、系统工程师、项目经理等所关注的问题,并且能够独立地处理功能性和非功能性需求。本文分别对五种视图进行了描述,并同时给出了捕获每种视图的表示方法。这些视图使用以架构为中心的、场景驱动以及迭代开发过程来进行设计。 引言 我们已经看到在许多文章和书籍中,作者欲使用单张视图来捕捉所有的系统架构要点。通过仔细地观察这些图例中的方框和箭头,不难发现作者努力地在单一视图中表达超过其表达限度的蓝图。方框是代表运行的程序吗?或者是代表源代码的程序块吗?或是物理计算机吗?或仅仅是逻辑功能的分组吗?箭头是表示编译时的依赖关系吗?或者是控制流吗?或是数据流吗?通常它代表了许多事物。是否架构只需要单个的架构样式?有时软件架构的缺陷源于过早地划分软件或过分的强调软件开发的单个方面:数据工程、运行效率、开发策略和团队组织等。有时架构并不能解决所有"客户"(或者说"风险承担人",USC 的命名)所关注的问题。许多作者都提及了这个问题:Garlan & Shaw 1、CMU 的Abowd & Allen、SEI 的Clements。作为补充,我们建议使用多个并发的视图来组织软件架构的描述,每个视图仅用来描述一个特定的所关注的方面的集合。 架构模型 软件架构用来处理软件高层次结构的设计和实施。它以精心选择的形式将若干结构元素进行装配,从而满足系统主要功能和性能需求,并满足其他非功能性需求,如可靠性、可伸缩性、可移植性和可用性。Perry 和Wolfe 使用一个精确的公式来表达,该公式由Boehm 做了进一步修改: 软件架构={元素,形式,关系/约束} 软件架构涉及到抽象、分解和组合、风格和美学。我们用由多个视图或视角组成的模型来描述它。为了最终处理大型的、富有挑战性的架构,该模型包含五个主要的视图(请对照图1): ?逻辑视图(Logical View),设计的对象模型(使用面向对象的设计方法时)。 ?过程视图(Process View),捕捉设计的并发和同步特征。 ?物理视图(Physical View),描述了软件到硬件的映射,反映了分布式特性。 ?开发视图(Development View),描述了在开发环境中软件的静态组织结构。 架构的描述,即所做的各种决定,可以围绕着这四个视图来组织,然后由一些用例(use cases)或场景(scenarios)来说明,从而形成了第五个视图。正如将看到的,实际上软件架

软件架构视图案例

软件架构视图案例 设备调试系统案例概述 本文的以下部分,将研究一个案例:某型号设备调试系统。 设备调试员通过使用该系统,可以察看设备状态(设备的状态信息由专用的数据采集器实时采集)、发送调试命令。该系统的用例图如图1所示。 图1 设备调试系统的用例图 经过研制方和委托方的紧密配合,最终确定的需求可以总括地用表1来表示。 表2 设备调试系统的需求 下面从不同视图进行架构设计,来分门别类地将不同需求一一满足。

逻辑视图:设计满足功能需求的架构 首先根据功能需求进行初步设计,进行大粒度的职责划分。如图2所示。 ?应用层负责设备状态的显示,并提供模拟控制台供用户发送调试命令。 ?应用层使用通讯层和嵌入层进行交互,但应用层不知道通讯的细节。 ?通讯层负责在RS232协议之上实现一套专用的"应用协议"。 ?当应用层发送来包含调试指令的协议包,由通讯层负责按RS232协议将之传递给嵌入层。 ?当嵌入层发送来原始数据,由通讯层将之解释成应用协议包发送给应用层。 ?嵌入层负责对调试设备的具体控制,以及高频度地从数据采集器读取设备状态数据。 ?设备控制指令的物理规格被封装在嵌入层内部,读取数采器的具体细节也被封装在嵌入层内部。 图2 设备调试系统架构的逻辑视图 开发视图:设计满足开发期质量属性的架构 软件架构的开发视图应当为开发人员提供切实的指导。任何影响全局的设计决策都应由架构设计来完成,这些决策如果"漏"到了后边,最终到了大规模并行开发阶段才发现,可能造成"程序员碰头儿临时决定"的情况大量出现,软件质量必然将下降甚至导致项目失败。 其中,采用哪些现成框架、哪些第三方SDK、乃至哪些中间件平台,都应该考虑是否由软件架构的开发视图确定下来。图6展示了设备调试系统的(一部分)软件架构开发视图:应用层将基于MFC设计实现,而通讯层采用了某串口通讯的第三方SDK。

软件架构4+1视图模型

Paper published in IEEE Software 12 (6) November 1995, pp. 42-50 架构蓝图——软件架构“4+1”视图模型 Philippe Kruchten Rational Software Corp. 摘要 本文基于多个并发视图的使用情况来说明描述软件密集型系统架构的模型。使用多重视图允许独立地处理各"风险承担人":最终用户、开发人员、系统工程师、项目经理等所关注的问题,并且能够独立地处理功能性和非功能性需求。本文分别对五种视图进行了描述,并同时给出了捕获每种视图的表示方法。这些视图使用以架构为中心的、场景驱动以及迭代开发过程来进行设计。 关键字:software architecture, view, object-oriented design, software development process 引言 我们已经看到在许多文章和书籍中,作者欲使用单张视图来捕捉所有的系统架构要点。通过仔细地观察这些图例中的方框和箭头,不难发现作者努力地在单一视图中表达超过其表达限度的蓝图。方框是代表运行的程序吗?或者是代表源代码的程序块吗?或是物理计算机吗?或仅仅是逻辑功能的分组吗?箭头是表示编译时的依赖关系吗?或者是控制流吗?或是数据流吗?通常它代表了许多事物。是否架构只需要单个的架构样式?有时软件架构的缺陷源于过早地划分软件或过分的强调软件开发的单个方面:数据工程、运行效率、开发策略和团队组织等。有时架构并不能解决所有“客户”(或者说“风险承担人”,USC的命名)所关注的问题。许多作者都提及了这个问题:Garlan&Shaw1、CMU的Abowd&Allen、SEI的Clements。作为补充,我们建议使用多个并发的视图来组织软件架构的描述,每个视图仅用来描述一个特定的所关注的方面的集合。 架构模型 软件架构用来处理软件高层次结构的设计和实施。它以精心选择的形式将若干结构元素进行装配,从而满足系统主要功能和性能需求,并满足其他非功能性需求,如可靠性、可伸缩性、可移植性和可用性。Perry和Wolfe使用一个精确的公式来表达,该公式由Boehm做了进一步修改: 软件架构= {元素,形式,关系/约束} 软件架构涉及到抽象、分解和组合、风格和美学。我们由多个视图或视角组成的模型来描述它。为了最终处理大型的、富有挑战性的架构,该模型包含五个主要的视图(请对照图1): ●逻辑视图(Logical View),设计的对象模型(使用面向对象的设计方法时)。 ●过程视图(Process View),捕捉设计的并发和同步特征。

软件架构的5视图法

软件架构的5视图法 下面内容来自《软件架构设计》一书的第五章。 5视图法可以帮助软件架构师以不同的视角对软件的各个方面的属性:功能需求,约束,运行期质量属性,开发期质量属性。 1、逻辑架构:逻辑架构关注功能,不仅包括用户可见的功能,还包括为实现用户功能而必须提供的“辅助功能模块”——。 2、开发架构:开发架构关注程序包,不仅包括要编写的源程序,还包括可以直接使用的第三方SDK 和现场框架、类库,以及开发的系统将运行于其上的系统软件或中间件。关注编译时刻的静态依赖关系。 3、运行架构:运行架构关注进程、线程、对象等运行时概念,以及相关的并发,同步,通信等问题。运行架构关注运行期间各个单元的交互。

4、物理架构:物理架构关注“目标程序及其依赖的运行库和系统软件”最终如何安装或部署到物理机器,以及如何部署机器和网络来配合软件系统的可靠性,可伸缩性等要求。 5、数据架构:数据架构关注持久化数据的存储方案,不仅包括实体及实体关系的存储格式、还包括数据传递,数据复制,数据同步等策略。 开发的策略。 1、逻辑架构的设计着重考虑功能需求——系统应该向用户提供什么样的服务。 架构视图 着重考虑 关注点 工具 逻辑架构 功能需求——系统应答向用户提供什么样的服务

行为和职责的划分 UML :静态——包图,类图,对象图;动态——序列图,协作图,状态图,活动图。 开发架构 开发期的质量属性——可扩展性,可重用性,可移植性,易理解性,易测试性 软件开发环境中软件模块实际组织方式——具体涉及源程序文件,配置文件,源程序包,编译后的目标文件和第三方库文件 UML:包图,类图,组件图 运行架构 运行期质量属性——性能,可伸缩性,持续可用性,安全性 系统的并发和同步,涉及进程和线程技术 UML:包图类图对象图来说明运行时的关键的概念;序列图,协作图等来描述交互机制。 物理架构 安装和部署的需求——包括计算机,网络,硬件设施情况,以及如何部署 软件单元如何映射到硬件,以及硬件相关的可靠性,可伸缩性,性能和安全性等

Qt学习笔记图形视图框架

Qt学习笔记--图形视图框架(一) 2010-07-11 07:40 优点:处理多个图元,单击,拖动,选择图元 架构:一个场景,多个图元位于其中,通过视图显示 主要应用: 绘图软件,显示地图软件 当使用没有变换的视图观察场景时,场景中的一个单元对应屏幕上的一个像素 图元坐标通常以图元中心为原点,X轴正方向为向右,Y轴正方向为向下 场景坐标的原点在场景中心,X轴正方向为向右,Y轴正方向为向下 视图坐标以左上角为原点,X轴正方向为向右,Y轴正方向为向下 所有的鼠标事件最开始都是使用视图坐标 场景:图元的容器 1.提供管理很多图元的接口 2.传播事件到图元中 3.管理图元状态,例如选择和焦点处理 4.提供非转换的绘制功能,主要用于打印 QGraphicsScene scene; QGraphicsRectItem *rect = scene.addRect(QRectF(0, 0, 100, 100)); // 添加图元QGraphicsItem *item = scene.itemAt(50, 50); // 查询图元 // item == rect; 通过QGraphicsScene::setSelectionArea()可以选择场景的任一个图元,QGraphicsScene::setSelectedItems()返回被选择的图元 设置焦点图元QGraphicsScene::setFocusItem(), setFocus(), QGraphicsScene::focusItem(), 返回焦点图元 视图: 一个可视的子部件,可视化场景的内容 多个视图可以显示同一个场景 坐标转换:QGraphicsView::mapToScene(), QGraphicsView::mapFromScene() 图元: 支持鼠标事件,滚轮事件,上下文菜单事件 支持键盘输入焦点,按键事件 支持拖放 支持分组 冲突探测 提供坐标转换,图元与场景,图元与图元之间

相关主题