AO的Display对象简介
作者:
jialan 文章来源:
http://jialan.blog.hexun.com 点击数:675 更新时间:2007-9-19
显示设计模式
为了帮助你理解怎样和各种显示对象一起工作来解决一般的开发需求,一些应用情节和细节在他们执行被给。用这些模式作为显示对象一起工作的引点。
应用窗口
最一般的任务之一是来在支持滚动和备份存储的应用窗口的客户端区域绘制地图。这个显示对象在下面的情况可能被用。
初始化
当窗口被创建时,通过创建一个Screen Display开始。你需要创建一个或多个符号用来绘制形状。使应用句柄到pScreenDisplay.Hwnd。从它IDisplayTransformation接口的Screen Display得到和用pTransformation.Bounds和pDisplayTransform.VisibleBounds来设置全图和可视范围。可视范围决定当前空间水平。Screen Display关心更新DeviceFrame的转化显示。Screen Display管理窗口的消息和一般的事件的句柄像窗口的大小和滚动。
Private m_pScreenDisplay As IScreenDisplay
Private m_pFillSymbol As ISimpleFillSymbol
Private Sub Form_Load()
Set m_pScreenDisplay = New ScreenDisplay
m_pScreenDisplay.hWnd = Picture1.hWnd
Set m_pFillSymbol = New SimpleFillSymbol
Dim pEnv As IEnvelope
Set pEnv = New Envelope
pEnv.PutCoords 0, 0, 50, 50
m_pScreenDisplay.DisplayTransformation.bounds = pEnv
m_pScreenDisplay.DisplayTransformation.VisibleBounds = pEnv
End Sub
绘画
显示对象定义一个基本的IDraw接口,这个接口很容易对任何显示的绘制。只要你用IDraw或IDisplay来执行你的绘制代码,你不用担心你要绘制的哪一种设备。一个绘制过程用StartDrawing开始和用FinishDrawing完成。例如,创建一个程序在屏幕中心建立一个多边形并且绘制它。这个形状用默认的符号。
Private Function GetPolygon() As IPolygon
Set GetPolygon = New Polygon
Dim pPointCollection As IPointCollection
Set pPointCollection = GetPolygon
Dim pPoint As IPoint
Set pPoint = New Point
pPoint.PutCoords 20, 20
pPointCollection.AddPoint pPoint
pPoint.PutCoords 30, 20
pPointCollection.AddPoint pPoint
pPoint.PutCoords 30, 30
pPointCollection.AddPoint pPoint
pPoint.PutCoords 20, 30
pPointCollection.AddPoint pPoint
GetPolygon.Close
End Function
Private Sub MyDraw(pDisplay As IDisplay, hDC As esriSystem.OLE_HANDLE)
' Draw from Scratch
Dim pDraw As IDraw
Set pDraw = pDisplay
pDraw.StartDrawing hDC, esriNoScreenCache
Dim pPoly As IPolygon
Set pPoly = GetPolygon()
pDraw.SetSymbol m_pFillSymbol
pDraw.Draw pPoly
pDraw.FinishDrawing
End Sub
这段程序可以在任何设备中绘制多边形。不管怎么样,第一地方我们需要绘制到窗口。为了处理这个,在那些应用程序的Screen Display的指示器和PictureBox的句柄的PictureBox的Paint方法中写一些代码到MyDraw程序中去。注意这个程序接受显示指示器和窗口设备。
Private Sub Picture1_Paint()
MyDraw m_pScreenDisplay, Picture1.hDC
End Sub
增加显示缓冲区
一些绘画过程可能花一段时间才能完成。一个简单的方法来提高性能就是用运显示缓冲区。这个涉及到Screen Display的能力来记录你的绘画过程到一个位图中,然后当不论何时Paint方法被调用,就用这个位图来刷新图片的窗口。直到你的数据改变和你调用IScreenDisplay::Invalidate来指定哪个缓冲区是无效的,这个缓冲区就会被用。有两种缓冲区:一个是记录缓冲区,一个是用户联合缓冲区。用记录在应用程序的Paint方法中来执行显示缓冲区。
Private Sub Picture1_Paint()
If (m_pScreenDisplay.IsCacheDirty(esriScreenRecording)) Then
m_pScreenDisplay.StartRecording
MyDraw m_pScreenDisplay, Picture1.hDC
m_pScreenDisplay.StopRecording
Else
Dim rect As tagRECT
m_pScreenDisplay.DrawCache Picture1.hDC, esriScreenRecording, rect, rect
End If
End Sub
当你执行这个代码时,你将会看到在屏幕上什么也没有画。这个由于ScreenRecording缓冲区没有设置。为确定MyDraw函数被调用,当首先绘画消息被接收,你一定要使缓冲区无效。增加下面的一行到Form_load方法的后面。
m_pScreenDisplay.Invalidate Nothing, True, esriScreenRecording
一些应用,如ArcMap,可能需要多个显示缓冲区。为利用多个缓冲区,用到下面的步骤:
1、 用IScreenDisplay::AddCache增加新的缓冲区。返回时保存缓冲区的ID。
2、 为绘制你的缓冲区,指定缓冲区的ID开始,StartDrawing。
3、 为使缓冲区无效,指定缓冲区的ID失效,Invalidate。
4、 为了从缓冲区中绘制,指定缓冲区ID绘制,DrawCache。
为了改变应用例子支持自己的缓冲区,做下面的改变:
1)增加新变量来保持新的缓冲区
Private m_lCacheID As Long
2)在Form_load方法中创建缓冲区
m_lCacheID = m_pScreenDisplay.AddCache
3)用m_ICacheID变量和从Paint方法中移除开始和停止记录来适当的改变调用。
移动,大小变化和旋转
显示对象一个强大的特征能力就是在你绘制地图上放大和缩小。它用放大,缩小或平移工具很容易执行。滚动被自动处理。在你的地图上放在缩小,简单设置你的可视范围。例如,增加一个按键到表格上,放入下面的代码,这个通过固定的数来变化屏幕,在Click事件按键中。
Private Sub Command1_Click()
Dim pEnv As IEnvelope
Set pEnv = m_pScreenDisplay.DisplayTransformation.VisibleBounds
pEnv.Expand 0.75, 0.75, True
m_pScreenDisplay.DisplayTransformation.VisibleBounds = pEnv
m_pScreenDisplay.Invalidate Nothing, True, esriAllScreenCaches
End Sub
Screen Display执行TrackPan方法,这个调用主要是鼠标按下事件让用户平移视图。你可以通过设置DisplaytransFormation的Rotation属性值来以屏幕为中心旋转实体。Rotation指定是以度表示。Screen Display执行TrackRotate方法,这个调用是鼠标按下事件让用户相互旋转视图。
打印
打印与屏幕绘制非常相似。当绘制到打印机时,你不用担心缓冲区或者滚动,Simple Display被用。创建Simple Display对象和通过复制Screen Display的变化来初始化它的变化。设置打印机的变化的设备框架的打印页的像素边的值。最后,用Simple Display和打印机的句柄从草图绘制。
输出元文件
这个GDIDisplay对象被用来表示一个元文件。创建元文件和打印之间有少许不同。如果你指定lpbounds变量为0到CreateEnhMetaFile,这个MyDraw程序能够被用。仅仅用hPrinterDc来代替hMetafileDC。如果你想要指定CreateEnhMetafFile的范围,设置DisplayTransformation的DeviceFrame相同的矩形的像素版本。
打印结构
一些工程可能需要直接输出到输出设备的某些下一级矩形。它通过设置Displaytransformation的设备框架像素范围少于完全设备范围很容易处理这些。
过滤
非常高级的绘制效果,像颜色透明度,用显示过虑能够完成。过虑和显示缓冲区一起工作,允许你的光栅版本(rasterized version)的绘制操作。当一个过虑被指定到显示视图时(用IDisplay::putrefy_displayFilter),这个显示创建一个和用记录缓冲区提供栅格信息一起的内部过虑缓冲区。输出是直到过虑被清除就发送到过虑缓冲区(putref_displayFilter(0))。在哪一点上调用IDisplayFilter::Apply.Apply接收当前背景位图(记录缓冲区),绘制缓冲区(包含被指定过虑的哪些所有绘画)和目的地的句柄。透明过虑在这些位图上执行(alphblending)和得到颜色透明度把他们绘制到目标的句柄。新的过虑能被创建执行其他的一些效果。
例子
画点
[C#]
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
screenDisplay.StartDrawing(screenDisplay.hDC, (short) esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol(new SimpleMarkerSymbolClass());
screenDisplay.DrawPoint(mxDoc.CurrentLocation);
screenDisplay.FinishDrawing();
}
画线
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
ISimpleLineSymbol lineSymbol = new SimpleLineSymbolClass();
IRgbColor rgbColor = new RgbColorClass();
rgbColor.Red = 255;
lineSymbol.Color = rgbColor;
IRubberBand rubberLine = new RubberLineClass();
IPolyline newPolyline = (IPolyline)rubberLine.TrackNew(screenDisplay, (ISymbol)lineSymbol);
screenDisplay.StartDrawing(screenDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol((ISymbol)lineSymbol);
screenDisplay.DrawPolyline(newPolyline);
screenDisplay.FinishDrawing();
}
画面
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
ISimpleFillSymbol fillSymbol = new SimpleFillSymbolClass();
IRgbColor rgbColor = new RgbColorClass();
rgbColor.Red = 255;
fillSymbol.Color = rgbColor;
IRubberBand rubberPolygon = new RubberPolygonClass();
IPolygon newPolygon = (IPolygon)rubberPolygon.TrackNew(screenDisplay, (ISymbol)fillSymbol);
screenDisplay.StartDrawing(screenDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol((ISymbol)fillSymbol);
screenDisplay.DrawPolygon(newPolygon);
screenDisplay.FinishDrawing();
}
画矩形
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
ISimpleFillSymbol fillSymbol = new SimpleFillSymbolClass();
IRgbColor rgbColor = new RgbColorClass();
rgbColor.Red = 255;
fillSymbol.Color = rgbColor;
IRubberBand rubberEnv = new RubberEnvelopeClass();
IEnvelope newEnvelope = (IEnvelope)rubberEnv.TrackNew(screenDisplay, (ISymbol)fillSymbol);
screenDisplay.StartDrawing(screenDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol((ISymbol)fillSymbol);
screenDisplay.DrawRectangle(newEnvelope);
screenDisplay.FinishDrawing();
}
为了帮助你理解怎样和各种显示对象一起工作来解决一般的开发需求,一些应用情节和细节在他们执行被给。用这些模式作为显示对象一起工作的引点。
应用窗口
最一般的任务之一是来在支持滚动和备份存储的应用窗口的客户端区域绘制地图。这个显示对象在下面的情况可能被用。
初始化
当窗口被创建时,通过创建一个Screen Display开始。你需要创建一个或多个符号用来绘制形状。使应用句柄到pScreenDisplay.Hwnd。从它IDisplayTransformation接口的Screen Display得到和用pTransformation.Bounds和pDisplayTransform.VisibleBounds来设置全图和可视范围。可视范围决定当前空间水平。Screen Display关心更新DeviceFrame的转化显示。Screen Display管理窗口的消息和一般的事件的句柄像窗口的大小和滚动。
Private m_pScreenDisplay As IScreenDisplay
Private m_pFillSymbol As ISimpleFillSymbol
Private Sub Form_Load()
Set m_pScreenDisplay = New ScreenDisplay
m_pScreenDisplay.hWnd = Picture1.hWnd
Set m_pFillSymbol = New SimpleFillSymbol
Dim pEnv As IEnvelope
Set pEnv = New Envelope
pEnv.PutCoords 0, 0, 50, 50
m_pScreenDisplay.DisplayTransformation.bounds = pEnv
m_pScreenDisplay.DisplayTransformation.VisibleBounds = pEnv
End Sub
绘画
显示对象定义一个基本的IDraw接口,这个接口很容易对任何显示的绘制。只要你用IDraw或IDisplay来执行你的绘制代码,你不用担心你要绘制的哪一种设备。一个绘制过程用StartDrawing开始和用FinishDrawing完成。例如,创建一个程序在屏幕中心建立一个多边形并且绘制它。这个形状用默认的符号。
Private Function GetPolygon() As IPolygon
Set GetPolygon = New Polygon
Dim pPointCollection As IPointCollection
Set pPointCollection = GetPolygon
Dim pPoint As IPoint
Set pPoint = New Point
pPoint.PutCoords 20, 20
pPointCollection.AddPoint pPoint
pPoint.PutCoords 30, 20
pPointCollection.AddPoint pPoint
pPoint.PutCoords 30, 30
pPointCollection.AddPoint pPoint
pPoint.PutCoords 20, 30
pPointCollection.AddPoint pPoint
GetPolygon.Close
End Function
Private Sub MyDraw(pDisplay As IDisplay, hDC As esriSystem.OLE_HANDLE)
' Draw from Scratch
Dim pDraw As IDraw
Set pDraw = pDisplay
pDraw.StartDrawing hDC, esriNoScreenCache
Dim pPoly As IPolygon
Set pPoly = GetPolygon()
pDraw.SetSymbol m_pFillSymbol
pDraw.Draw pPoly
pDraw.FinishDrawing
End Sub
这段程序可以在任何设备中绘制多边形。不管怎么样,第一地方我们需要绘制到窗口。为了处理这个,在那些应用程序的Screen Display的指示器和PictureBox的句柄的PictureBox的Paint方法中写一些代码到MyDraw程序中去。注意这个程序接受显示指示器和窗口设备。
Private Sub Picture1_Paint()
MyDraw m_pScreenDisplay, Picture1.hDC
End Sub
增加显示缓冲区
一些绘画过程可能花一段时间才能完成。一个简单的方法来提高性能就是用运显示缓冲区。这个涉及到Screen Display的能力来记录你的绘画过程到一个位图中,然后当不论何时Paint方法被调用,就用这个位图来刷新图片的窗口。直到你的数据改变和你调用IScreenDisplay::Invalidate来指定哪个缓冲区是无效的,这个缓冲区就会被用。有两种缓冲区:一个是记录缓冲区,一个是用户联合缓冲区。用记录在应用程序的Paint方法中来执行显示缓冲区。
Private Sub Picture1_Paint()
If (m_pScreenDisplay.IsCacheDirty(esriScreenRecording)) Then
m_pScreenDisplay.StartRecording
MyDraw m_pScreenDisplay, Picture1.hDC
m_pScreenDisplay.StopRecording
Else
Dim rect As tagRECT
m_pScreenDisplay.DrawCache Picture1.hDC, esriScreenRecording, rect, rect
End If
End Sub
当你执行这个代码时,你将会看到在屏幕上什么也没有画。这个由于ScreenRecording缓冲区没有设置。为确定MyDraw函数被调用,当首先绘画消息被接收,你一定要使缓冲区无效。增加下面的一行到Form_load方法的后面。
m_pScreenDisplay.Invalidate Nothing, True, esriScreenRecording
一些应用,如ArcMap,可能需要多个显示缓冲区。为利用多个缓冲区,用到下面的步骤:
1、 用IScreenDisplay::AddCache增加新的缓冲区。返回时保存缓冲区的ID。
2、 为绘制你的缓冲区,指定缓冲区的ID开始,StartDrawing。
3、 为使缓冲区无效,指定缓冲区的ID失效,Invalidate。
4、 为了从缓冲区中绘制,指定缓冲区ID绘制,DrawCache。
为了改变应用例子支持自己的缓冲区,做下面的改变:
1)增加新变量来保持新的缓冲区
Private m_lCacheID As Long
2)在Form_load方法中创建缓冲区
m_lCacheID = m_pScreenDisplay.AddCache
3)用m_ICacheID变量和从Paint方法中移除开始和停止记录来适当的改变调用。
移动,大小变化和旋转
显示对象一个强大的特征能力就是在你绘制地图上放大和缩小。它用放大,缩小或平移工具很容易执行。滚动被自动处理。在你的地图上放在缩小,简单设置你的可视范围。例如,增加一个按键到表格上,放入下面的代码,这个通过固定的数来变化屏幕,在Click事件按键中。
Private Sub Command1_Click()
Dim pEnv As IEnvelope
Set pEnv = m_pScreenDisplay.DisplayTransformation.VisibleBounds
pEnv.Expand 0.75, 0.75, True
m_pScreenDisplay.DisplayTransformation.VisibleBounds = pEnv
m_pScreenDisplay.Invalidate Nothing, True, esriAllScreenCaches
End Sub
Screen Display执行TrackPan方法,这个调用主要是鼠标按下事件让用户平移视图。你可以通过设置DisplaytransFormation的Rotation属性值来以屏幕为中心旋转实体。Rotation指定是以度表示。Screen Display执行TrackRotate方法,这个调用是鼠标按下事件让用户相互旋转视图。
打印
打印与屏幕绘制非常相似。当绘制到打印机时,你不用担心缓冲区或者滚动,Simple Display被用。创建Simple Display对象和通过复制Screen Display的变化来初始化它的变化。设置打印机的变化的设备框架的打印页的像素边的值。最后,用Simple Display和打印机的句柄从草图绘制。
输出元文件
这个GDIDisplay对象被用来表示一个元文件。创建元文件和打印之间有少许不同。如果你指定lpbounds变量为0到CreateEnhMetaFile,这个MyDraw程序能够被用。仅仅用hPrinterDc来代替hMetafileDC。如果你想要指定CreateEnhMetafFile的范围,设置DisplayTransformation的DeviceFrame相同的矩形的像素版本。
打印结构
一些工程可能需要直接输出到输出设备的某些下一级矩形。它通过设置Displaytransformation的设备框架像素范围少于完全设备范围很容易处理这些。
过滤
非常高级的绘制效果,像颜色透明度,用显示过虑能够完成。过虑和显示缓冲区一起工作,允许你的光栅版本(rasterized version)的绘制操作。当一个过虑被指定到显示视图时(用IDisplay::putrefy_displayFilter),这个显示创建一个和用记录缓冲区提供栅格信息一起的内部过虑缓冲区。输出是直到过虑被清除就发送到过虑缓冲区(putref_displayFilter(0))。在哪一点上调用IDisplayFilter::Apply.Apply接收当前背景位图(记录缓冲区),绘制缓冲区(包含被指定过虑的哪些所有绘画)和目的地的句柄。透明过虑在这些位图上执行(alphblending)和得到颜色透明度把他们绘制到目标的句柄。新的过虑能被创建执行其他的一些效果。
例子
画点
[C#]
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
screenDisplay.StartDrawing(screenDisplay.hDC, (short) esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol(new SimpleMarkerSymbolClass());
screenDisplay.DrawPoint(mxDoc.CurrentLocation);
screenDisplay.FinishDrawing();
}
画线
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
ISimpleLineSymbol lineSymbol = new SimpleLineSymbolClass();
IRgbColor rgbColor = new RgbColorClass();
rgbColor.Red = 255;
lineSymbol.Color = rgbColor;
IRubberBand rubberLine = new RubberLineClass();
IPolyline newPolyline = (IPolyline)rubberLine.TrackNew(screenDisplay, (ISymbol)lineSymbol);
screenDisplay.StartDrawing(screenDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol((ISymbol)lineSymbol);
screenDisplay.DrawPolyline(newPolyline);
screenDisplay.FinishDrawing();
}
画面
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
ISimpleFillSymbol fillSymbol = new SimpleFillSymbolClass();
IRgbColor rgbColor = new RgbColorClass();
rgbColor.Red = 255;
fillSymbol.Color = rgbColor;
IRubberBand rubberPolygon = new RubberPolygonClass();
IPolygon newPolygon = (IPolygon)rubberPolygon.TrackNew(screenDisplay, (ISymbol)fillSymbol);
screenDisplay.StartDrawing(screenDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol((ISymbol)fillSymbol);
screenDisplay.DrawPolygon(newPolygon);
screenDisplay.FinishDrawing();
}
画矩形
public void onMouseDown(int Button, int Shift, int X, int Y)
{
IMxDocument mxDoc = m_App.Document as IMxDocument;
IActiveView activeView = mxDoc.FocusMap as IActiveView;
IScreenDisplay screenDisplay = activeView.ScreenDisplay;
ISimpleFillSymbol fillSymbol = new SimpleFillSymbolClass();
IRgbColor rgbColor = new RgbColorClass();
rgbColor.Red = 255;
fillSymbol.Color = rgbColor;
IRubberBand rubberEnv = new RubberEnvelopeClass();
IEnvelope newEnvelope = (IEnvelope)rubberEnv.TrackNew(screenDisplay, (ISymbol)fillSymbol);
screenDisplay.StartDrawing(screenDisplay.hDC, (short)esriScreenCache.esriNoScreenCache);
screenDisplay.SetSymbol((ISymbol)fillSymbol);
screenDisplay.DrawRectangle(newEnvelope);
screenDisplay.FinishDrawing();
}