-
给
QGraphicsView
创建刻度轴
p>
Qt
的
Scene - Item
-View
框架功能十分强大,这也是
Qt
< br>的亮点之一,但由于
Qt
的设计出发点并不是科
学或石油程序,所以在某些方面提供的功能还不是很全面,比如
Scen
e,Item,View
框架并没有提供一套完
整的“刻度”绘
制的功能。不过也无可厚非,像
MFC
,
GDK
,
WxWidget
这类
p>
GUI
库也都不会现成的刻度轴
绘制的内容
,当一个库做的越来越优秀时,人们对她的期望和需求变得五花八门
^_^
。
由于
QGraphic
sView
中的滚动条和滚动行为都被死死的封装到了
QGra
phicsView
中,
所以试图在
V
iewPort
或者用
QGraphicsItem
来实现刻度轴的作法是十分艰难的,
比如使用
QG
raphicsItem
来实现,
当一个
Scene
和
View
都固定时,可
能我们的
会工作的很好,但当视图变化时,比如滚动,比如重<
/p>
设
SceneRect
,比如放缩,比如
旋转等等等等。这些行为我们都要考虑,所以难度可想而知。
但如果我们了解了
QGraphicsView
是派生于
QAbstractScrollArea
了,并且还知道了
QGraphicsArea
有一
个保护成员函
数
void setViewportMargins ( int
left, int top, int right, int bottom
)
,
以及一个马甲
void
setViewportMargins ( const QMargins & margins
)
的话,事情就变得容易
多了。
setViewportMargins
这个方法就是给
p>
QAbstractScrollArea
的
Viewport
留出四边的“空地儿”至于这些
“空地儿”
能做什么就根据程序员的爱好了,
QT
中最典型的使用就是
p>
QTableView
(就是绘制表格的那个
类),其中的表头就是用这种方法实现的,下面我就说说这个方法的实现思路,如果您有这个需求并且不 p>
知道怎么实现,劳烦您继续读下去,如果您在八年前都已经知道此方法了,您也别见笑。
p>
首先,实现我们自己的
Axis
窗口,派生于
QWidget
,这个类主要注意
三个问题,一个是
SizeHint
方法,
一定要重载,因为我们要在
GraphicsView
中使
用这个方法来决定
Margin
的大小,第二个注意的问题是刻
度轴中刻度的产生,可以参考《
Graphics Gem
III
》中一篇叫“Nice label”(记不太清了,好像是这个
名字)的算法。这个算法能帮助我们产生漂亮的刻度值,比如不会出现
3141
5
这样的刻度。第三个问题就
是刻度的绘制了,使用
PaintEvent
函数绘制,这时要注意的就是
Offset
,因为当用户滚动
View
时,我们
的刻度也要变化。
再一
个就是实现我们自己的
GraphicsView
了,正如之前
说的,我们要使用
setViewportMargins()
这个方
法,在哪里实现最好呢?在
reSizeEvent()
中实现最好,因为这也正好符合正常逻辑--当窗口变化时,
重
设
Margin
,
并且重设
AxisWidget
的尺寸,
让其铺满
Margin
区域。
另外我们要重载
ScrollContentBy()
,
目的是设
置
AxisWidget
的
Offse
t
。
并且滚动四边的刻度窗口,
当然我
们可以完全的
Update
这几个刻度轴,
但还有一个更高效的方法,那就是
QWidget
的
scroll
,本人分析过
scroll
p>
方法的实现,它是用的平台底
层的
Bitb
lt
方法
(Windows
环境),效
率可想而知。
最后一个要注意的问题就是,当场景大小变化时
,要通知刻度轴让其重绘,幸好
QGraphicsScene
有一个
sceneRectChanged
的信号,所以实现这
一步也比较简单--在
AxisWidget
中定义一个重设<
/p>
model
的樔,
并且在
Scene
实例化后连接这之前的那个信号和这个樔就可以了。
根据以上方法实现的带刻度的
GraphicsVi
ew
如下图:
【转】
Qt
地图浏览器:使用
QGraphicsView
2012-02-27 11:31
转载自
孤舟钓客
最终编辑
孤舟钓客
/**
mainwidget.h
*
孤舟钓客
* 2011-07-25
*/
#ifndef MAPWIDGET_H
#define MAPWIDGET_H
#include
class QPixmap;
class QLabel;
class QPointF;
class MapWidget : public QGraphicsView
{
Q_OBJECT
public:
MapWidget();
void readMap();
QPointF mapToMap(QPointF);
public slots:
void slotZoom(int);
protected:
void drawBackground(QPainter *painter,
const QRectF &rect);
void mouseMoveEvent(QMouseEvent
*event);
private:
QPixmap map;
qreal zoom;
QLabel *viewCoord;
QLabel *sceneCoord;
QLabel *mapCoord;
double x1, y1;
double x2, y2;
};
#endif //
MAPWIDGET_H
/**
*
孤舟钓客
* 2011-07-25
*/
#include
#include
#include
MapWidget::MapWidget()
{
readMap();
zoom = 50;
int width = ();
int height = ();
QGraphicsScene *scene =
new QGraphicsScene(this);
scene->setSceneRect(-width/2,
-height/2, width, height);
setScene(scene);
setCacheMode(CacheBackground);
QSlider
*slider = new QSlider;
slider->setOrientation(Qt::Vertical);
slider->setRange(1,100);
slider->setTickInterval(10);
slider->setValue(50);
connect(slider,
SIGNAL(valueChanged(int)), this,
SLOT(slotZoom(int)));
QLabel *zoominLabel = new QLabel;
zoominLabel->setScaledContents(true);
zoominLabel->setPixmap(Q
Pixmap(
QLabel *zoomoutLabel = new QLabel;
zoomoutLabel->setScaledContents(true);
zoomoutLabel->setPixmap(
QPixmap(
//
create coordiante area
QFrame *coordFrame = new QFrame;
QLabel *label1 = new
QLabel(tr(
viewCoord =
new QLabel;
QLabel
*label2 = new QLabel(tr(
sceneCoord = new QLabel;
QLabel *label3 = new
QLabel(tr(
mapCoord = new
QLabel;
QGridLayout *grid = new QGridLayout;
grid->addWidget(label1,
0, 0);
grid->addWidget(viewCoord, 0, 1);
grid->addWidget(label2,
1, 0);
grid->addWidget(sceneCoord, 1, 1);
grid->addWidget(label3,
2, 0);
grid->addWidget(mapCoord, 2, 1);
grid->setSizeConstraint(
QLayout::SetFixedSize);
coordFrame->setLayout(grid);
// zoom
layout
QVBoxLayout
*zoomLayout = new QVBoxLayout;
zoomLayout->addWidget(zoominLabel);
zoomLayout->addWidget(slider);
zoomLayout->addWidget(zoomoutLabel);