可以建立一个Document/View结构。然后在View结构中画图。具体实现方法,就从sin(x)中取数,当然了数要取得密一些,即划分的区间要多。利用
lineto ,moveto等画直线语句进行连线。划分的区间越多,得到的曲线将越平滑
1 几何对象的结构和类
为了使用绘图函数,应该先了解绘图所用到的几种表示几何对象的结构和类。这些结构和类分别定义在头文件windef.h和afxwin.h中。
1.点
1)点结构POINT
点数据结构POINT用来表示一点的x、y坐标:
typedef struct tagPOINT {
LONG x;
LONG y;
} POINT;
2)点类CPoint
点类CPoint为一个没有基类的独立类,封装了POINT结构,有成员变量x和y,其构造函数有5种:
CPoint( );
CPoint( int initX, int initY );
CPoint( POINT initPt );
CPoint( SIZE initSize );
CPoint( LPARAM dwPoint ); // 低字设为x、高字设为y
CPoint类还定义了4个平移和设置函数:
void Offset(int xOffset, int yOffset);
void Offset(POINT point);
void Offset(SIZE size);
void SetPoint(int X, int Y);
CPoint类还重载了+、-、+=、-=、==、!=等运算符来支持CPoint对象和CPoint、POINT、SIZE对象之间的运算。
2.大小
1)大小结构SIZE
大小(size尺寸)结构SIZE用来表示矩形的宽cx和高cy:
typedef struct tagSIZE {
LONG cx;
LONG cy;
} SIZE;
2)大小类CSize
大小类CSize也为一个没有基类的独立类,封装了SIZE结构,有成员变量cx和cy,其构造函数也有5种:
CSize( );
CSize( int initCX, int initCY );
CSize( SIZE initSize );
CSize( POINT initPt );
CSize( DWORD dwSize ); // 低字设为cx、高字设为cy
CSizet类也重载了+、-、+=、-=、==、!=等运算符来支持CSize对象和CSize、POINT、SIZE、RECT对象之间的运算。
3.矩形
1)矩形结构RECT
矩形结构RECT定义了矩形的左上角与右下角的坐标:
typedef struct tagRECT {
LONG left;
LONG top;
LONG right;
LONG bottom;
} RECT;
2)矩形类CRect
矩形类CRect也为一个没有基类的独立类,封装了RECT结构,有成员变量left、top、right和bottom,其构造函数有6种:
CRect( );
CRect( int l, int t, int r, int b );
CRect( const RECT& srcRect );
CRect( LPCRECT lpSrcRect );
CRect( POINT point, SIZE size );
CRect( POINT topLeft, POINT bottomRight );
CRect类重载了=,+、-,+=、-=,==、!=,&、|,&=、|=等运算符来支持CRect对象和CRect、POINT、SIZE、RECT对象之间的运算。还定义了转换符LPCRECT和LPRECT来自动完成CRect对象到矩形结构和类指针LPCRECT和LPRECT的转换。
CRect类中常用的属性和成员函数有:
int Width( ) const;
int Height( ) const;
CSize Size( ) const;
CPoint& TopLeft( );
CPoint& BottomRight( );
CPoint CenterPoint( ) const;
void SwapLeftRight();
BOOL IsRectEmpty( ) const;
BOOL PtInRect( POINT point ) const;
void SetRect( int x1, int y1, int x2, int y2 );
void SetRect(POINT topLeft, POINT bottomRight);
void OffsetRect(int x, int y);
void MoveToXY(int x, int y);
3) 判断点是否在矩形中
有时需要判断某点(如鼠标位置)是否在某一矩形区域中,这可以调用CRect类的PtInRect函数来做:
BOOL PtInRect( POINT point ) const;
该函数当点point在其矩形区域内时,返回真。注意,该矩形区域不包括矩形的右边界和底边界。例如:
CRect rect( 10, 10, 371, 267 );
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if ( rect.PtInRect( point ) ) {
… …
}
… …
CView::OnLButtonUp(nFlags, point);
}
2 客户区大小和DC
在绘图前,必须先得到客户区大小和设备上下文DC。
1.获得客户区
绘图一般都是在视图窗口的客户区进行,而客户区的大小在运行时可由用户改变,为了使绘制的图形能随窗口大小自动改变,必须先得到当前客户区大小的数据(宽w和高h)。
获取客户区大小的方法有如下两种:
1)在消息响应函数OnSize中获得
利用属性窗口的信息页,在视图类中添加WM_SIZE消息的响应函数OnSize。该函数在窗口第一次显示或窗口大小被改变时会被Windows系统调用。其输入参数中的cx和cy就是客户区大小的宽和高,可将它们赋值给类变量(如m_iW和m_iH)供绘图时使用。例如
void CDrawView::OnSize(UINT nType, int cx, int cy) {
CView::OnSize(nType, cx, cy);
// TODO: 在此处添加消息处理程序代码
m_iW = cx; m_iH = cy;
}
其中,nType的值为:
l SIZE_MAXIMIZED(窗口已被最大化)
l SIZE_MINIMIZED(窗口已被最小化)
l SIZE_RESTORED(窗口已被改变大小)
l SIZE_MAXHIDE(其他窗口被最大化)
l SIZE_MAXSHOW(其他窗口从最大化还原)
2)调用成员函数GetClientRect得到
可在绘图前,定义一个矩形变量rect,然后再调用CWnd类的成员函数GetClientRect:
void GetClientRect( LPRECT lpRect ) const;
得到当前客户区矩形的数据,其中的右(right)与底(bottom)就是客户区的宽与高(其左left与顶top都为0)。例如:
RECT rect;
GetClientRect(&rect);
int w = rect.right, h = rect.bottom;
2.DC
在Windows中,绘图使用的是MFC的DC(Device-Context, 设备上下文)类CDC中各种绘图函数。
0)CDC类
CDC是CObject的直接派生类,CDC类自己也有若干派生类,其中包括窗口客户区DC所对应的CClientDC类、OnPaint和OnDraw消息响应函数的输入参数中使用的CPaintDC类、图元文件对应的CMetaFileDC类和整个窗口所对应的CWindowDC类。
CDC类中有许多成员函数,可以用来设置各种绘图环境、属性和参数,以及绘制各种图形和图像等,将在后面陆续加以介绍。
1)获得DC
可以从OnDraw函数的输入参数pDC或调用CWnd的成员函数GetDC:
CDC* GetDC( );
来获得DC的指针。
2)释放DC
因为Windows限制可用DC的数量,所以DC属于稀缺的公用资源。因此,对每次获得的DC,在使用完成后必须立即释放。
从OnDraw函数的输入参数pDC获得的DC,在该函数运行结束后,系统会自动释放。但由GetDC所获得的DC,必须自己来释放,这可以通过调用CWnd的成员函数ReleaseDC来完成:
int ReleaseDC( CDC* pDC ); // 成功返回非0
例如:
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point)
{
ReleaseCapture();
if (m_bLButtonDown) {
CDC* pDC = GetDC();
pDC->SelectObject(new CPen(PS_SOLID, 0, RGB(255, 0, 0)));
pDC->SelectStockObject(NULL_BRUSH);
pDC-> Ellipse (rect);
ReleaseDC(pDC);
m_bLButtonDown = FALSE;
}
CView::OnLButtonUp(nFlags, point);
}
3)类DC
每次从OnDraw函数的输入参数或调用GetDC所获得的DC,都是一个全新的临时缺省DC。它不能用类变量来长期保存,而且原来选入的各种GDI对象全都被作废,必须从头再来。
为了使选入的各种GDI对象一直有效,必须在视图类的PreCreateWindow函数中调用CWnd类的成员函数AfxRegisterWndClass:
LPCTSTR AFXAPI AfxRegisterWndClass( UINT nClassStyle, HCURSOR hCursor = 0,
HBRUSH hbrBackground = 0, HICON hIcon = 0 );
来修改窗口类的风格属性中的DC为类DC:CS_CLASSDC。如
BOOL CDrawView::PreCreateWindow(CREATESTRUCT& cs) {
cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS | CS_HREDRAW |
CS_VREDRAW | CS_CLASSDC, 0,
::CreateSolidBrush(RGB(255, 255, 255)));
return CView::PreCreateWindow(cs);
}
4)安全DC句柄
也可以用CDC类的成员函数:
HDC GetSafeHdc();
来获取CD所对应窗口(如客户区)的安全DC句柄,该句柄在窗口存在期间一直是有效的。例如,可先定义类变量HDC m_hDC;,再在适当的地方给它赋值m_hDC = GetDC()->GetSafeHdc();,然后就可以放心地使用了。例如,可以使用CDC类的成员函数
BOOL Attach(HDC hDC); // 成功返回非0
来将CDC对象与DC句柄连接在一起。
3 设置绘图颜色
1.颜色
Windows中的颜色一般用4个字节表示(0BGR(整数) = R G B 0(字节序) [Intel CPU低位字节在前]),Win32 API中定义了一个专门表示颜色索引值的变量类型COLORREF:(windef.h)
typedef DWORD COLORREF; // 0x00bbggrr
和一个由红绿蓝三原色构造颜色值的宏RGB:(wingdi.h)
#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))
其中,r、g、b为字节变量,取值范围为0~255。其函数说明为:
COLORREF RGB(
BYTE bRed, // red component of color
BYTE bGreen, // green component of color
BYTE bBlue // blue component of color
);
例如:
COLORREF red, gray;
red = RGB(255, 0, 0);
gray = RGB(128, 128,128);
在API中还定义了由COLORREF变量获取各个颜色分量的宏Get?Value:(wingdi.h)
#define GetRValue(rgb) (LOBYTE(rgb))
#define GetGValue(rgb) (LOBYTE(((WORD)(rgb)) >> 8))
#define GetBValue(rgb) (LOBYTE((rgb)>>16))
其中:
typedef unsigned long ULONG_PTR;
typedef ULONG_PTR DWORD_PTR;
#define LOBYTE(w) ((BYTE)((DWORD_PTR)(w) & 0xff))
它们对应的函数说明为:
BYTE GetRValue(DWORD rgb); // DWORD rgb ~ COLORREF col
BYTE GetGValue(DWORD rgb);
BYTE GetBValue(DWORD rgb);
2.点色(像素)
在Windows中,像素(pixel)的颜色是直接由设备上下文类CDC的成员函数SetPixel来设置的,该函数的原型为:
COLORREF SetPixel( int x, int y, COLORREF crColor );
COLORREF SetPixel( POINT point, COLORREF crColor );
其中,x与y分别为像素点的横坐标与纵坐标,crColor为像素的颜色值。例如:
pDC->SetPixel(10, 10, RGB(0, 255, 0));
另外,也可以用CDC的成员函数
COLORREF GetPixel( int x, int y ) const;
COLORREF GetPixel( POINT point ) const;
来获得指定点(x, y)或point的颜色。例如:
COLORREF col;
col = pDC->GetPixel(10, 10);
3.线色(笔)
在Windows中,线状图必须用笔(pen)来画,所以线的颜色就由笔色来确定。在MFC中,笔的属性和功能由CPen类提供(CPen是CGDIObject的派生类)。
笔的创建与使用的步骤为:
l 创建笔对象:创建笔类CPen对象的方法有如下两种:
n 使用构造函数CPen
CPen( int nPenStyle, int nWidth, COLORREF crColor );
其中:
u nPenStyle为笔的风格,可取值:
PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PSDASHDOTDOT
注意:1~4号笔风格只是在笔宽=0或1时有效,笔宽>1时总为实心的。
u nWidth为笔宽,与映射模式有关,使用缺省映射时为像素数,若nWidth = 0,则不论什么映射模式,笔宽都为一个像素;
u crColor为笔的颜色值。
例如
CPen* pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128));
CPen grayPen(PS_SOLID, 0, RGB(128, 128, 128));
n 使用成员函数CreatePen
BOOL CreatePen( int nPenStyle, int nWidth, COLORREF crColor );
如:
CPen grayPen;
grayPen.CreatePen(PS_SOLID, 0, RGB(128, 128, 128));
n 缺省的笔为单像素宽的实心黑色笔
l 将笔对象选入设备上下文:为了能使用我们所创建的笔对象,必须先将它选入设备上下文,这可以调用设备上下文类CDC的成员函数SelectObject来完成:
CPen* SelectObject( CPen* pPen );
返回值为指向原来笔对象的指针(一般将其保存下来,供下次再装入时使用)。如
pOldPen = pDC->SelectObject(&pen);
另外,Windows中有一些预定义的笔对象,可用CDC的另一成员函数SelectStockObject将其选入DC,其函数原型为:
virtual CGdiObject* SelectStockObject( int nIndex );
预定义的笔对象有BLACK_PEN(黑色笔)、WHITE_PEN (白色笔)、NULL_PEN(空笔/无色笔)。例如:
pDC->SelectStockObject(BLACK_PEN);
l 使用设备上下文画线状图:画线状图以及面状图的边线,所使用的是当前设备上下文中的笔对象。线状图有直线、折线、矩形、(椭)圆(弧)等,详见4)(2)
l 将笔对象从设备上下文中放出:为了能删除使用过的笔对象,必须先将它从设备上下文中释放出来后,然后才能删除。释放的方法是装入其他的笔对象(一般是重新装入原来的笔对象)。例如
pDC->SelectObject(pOldPen);
l 删除笔对象:为了能删除笔对象,必须先将其从设备上下文中释放。删除方法有如下几种:
n 调用笔类CDC的成员函数DeleteObject删除笔的当前内容(但是未删除笔对象,以后可再用成员函数CreatePen在笔对象中继续创建新的笔内容)。如
pen.DeleteObject();
n 使用删除运算符delete将笔对象彻底删除,如delete pen;
n 自动删除:若笔对象为局部变量,则在离开其作用域时,会被系统自动删除
下面为一段较完整地创建与使用笔的例子代码:
CPen pen, *pOldPen;
for (int j = 0; j <= 255; j++) {
HSLtoRGB(m_hue, m_sat, 255 - j, r, g, b); // 自定义的函数
pen.CreatePen(PS_SOLID, 0, RGB(r, g, b));
pOldPen = pDC->SelectObject(&pen);
pDC->MoveTo(0, j); pDC->LineTo(40, j);
pDC->SelectObject(pOldPen);
pen.DeleteObject();
}
4.面色(刷)
在Windows中,面状图必须用刷(brush)来填充,所以面色是由刷色来确定的。MFC中的刷类为CBrush(它也是CGDIObject的派生类),刷的创建与使用的步骤与笔的相似。
l 构造函数有4个:
n CBrush( ); // 创建一个刷的空对象
n CBrush( COLORREF crColor ); // 创建颜色为crColor的实心刷
n CBrush( int nIndex, COLORREF crColor ); // 创建风格由nIndex指定且颜色为crColor的条纹(hatch孵化)刷,其中nIndex可取条纹风格(Hatch Styles)值:
符号常量
数字常量
风格
HS_HORIZONTAL
0
水平线
HS_VERTICAL
1
垂直线
HS_FDIAGONAL
2
正斜线
HS_BDIAGONAL
3
反斜线
HS_CROSS
4
十字线(正网格)
HS_DIAGCROSS
5
斜十字线(斜网格)
n CBrush( CBitmap* pBitmap ); // 创建位图为pBitmap的图案刷
如:pDC->FillRect( &rect, new CBrush( RGB(r, g, b) ) );
l 与构造函数相对应,有多个创建不同类型刷的成员函数:
n BOOL CreateSolidBrush( COLORREF crColor );
n BOOL CreateHatchBrush( int nIndex, COLORREF crColor );
n BOOL CreatePatternBrush( CBitmap* pBitmap );
n BOOL CreateDIBPatternBrush( HGLOBAL hPackedDIB, UINT nUsage );
n BOOL CreateDIBPatternBrush( const void* lpPackedDIB, UINT nUsage );
n BOOL CreateBrushIndirect( const LOGBRUSH* lpLogBrush );
n BOOL CreateSysColorBrush( int nIndex );
l 预定义的刷对象有BLACK_BRUSH(黑刷)、DKGRAY_BRUSH(暗灰刷)、GRAY_BRUSH(灰刷)、HOLLOW_BRUSH(空刷)、LTGRAY_BRUSH(亮灰刷)、NULL_BRUSH(空刷)、WHITE_BRUSH(白刷)
l 缺省的刷为空刷
l 与笔一样,可以用函数SelectObject或SelectStockObject将自定义的刷或预定义的刷选入DC中,供绘面状图时使用。
5.文本色
可使用CDC类的成员函数SetTextColor和SetBkColor来分别设置输出文本的前景色和背景色:(缺省的前景色为黑色,背景色空)
COLORREF GetTextColor( ) const;
virtual COLORREF SetTextColor( COLORREF crColor );
COLORREF GetBkColor( ) const;
virtual COLORREF SetBkColor( COLORREF crColor );
例如:
pDC->TextOut(10, 10, "Test text");
pDC->SetTextColor(RGB(0, 128, 0)); pDC->TextOut(10, 30, "Test text");
pDC->SetBkColor(RGB(0, 0, 128)); pDC->TextOut(10, 50, "Test text");
6.绘图工具
1)GDI对象
Windows的图形设备接口(GDI = graphics device interface)对象指各种绘图工具,如笔、刷、位图、字体、调色板、区域等,对应的MFC类为CPen、CBrush、CBitmap、CFont等。这些图形绘制对象类都是CGDIObject的派生类,而CGDIObject则是直接从CObject类派生的抽象基类。其中,Windws CE不支持调色板类CPalette;CRgn为区域类,对应于窗口中的一个矩形、多边形或(椭)圆区域(region),可用于移动、拷贝、合并、判断和裁剪。
2)选入
可用设备上下文类CDC的多态成员函数SelectObject,来将绘图工具对象选入设备上下文,以供绘图时使用:
CPen* SelectObject( CPen* pPen );
CBrush* SelectObject( CBrush* pBrush );
virtual CFont* SelectObject( CFont* pFont );
CBitmap* SelectObject( CBitmap* pBitmap );
int SelectObject( CRgn* pRgn );
CGdiObject* SelectObject( CGdiObject* pObject );
3)获取
可用API函数GetCurrentObject来获得当前在DC中的指定类型的绘图对象:
HGDIOBJ GetCurrentObject(
HDC hdc, // handle to device context
UINT uObjectType // specifies the object-type
);
其中,参数uObjectType可取值:
OBJ_PEN // Returns the current selected pen.
OBJ_BRUSH // Returns the current selected brush.
OBJ_PAL // Returns the current selected palette.
OBJ_FONT // Returns the current selected font.
OBJ_BITMAP // Returns the current selected bitmap.
也可分别调用CDC类的下列成员函数来做同样的事:
CPen* GetCurrentPen( ) const;
CBrush* GetCurrentBrush( ) const;
CFont* GetCurrentFont( ) const;
CBitmap* GetCurrentBitmap( ) const;
CPalette* GetCurrentPalette( ) const;
如:
HPEN hPen = (HPEN)GetCurrentObject(pDC->m_hDC, OBJ_PEN);
CPen* pPen = CPen::FromHandle(hPen);
等价于:
CPen* pPen = pDC-> GetCurrentPen( );
4 画图
在Windows中,绘图一般在视图窗口的客户区进行,使用的是设备上下文类CDC中各种绘图函数。
1. 映射模式与坐标系
1)默认映射模式
映射模式(map mode)影响所有的图形和文本绘制函数,它定义(将逻辑单位转换为设备单位所使用的)度量单位和坐标方向,Windows总是用逻辑单位来绘图。
缺省情况下,绘图的默认映射模式为MM_TEXT,其绘图单位为像素(只要不打印输出,屏幕绘图使用该模式就够了)。若窗口客户区的宽和高分别为w和h像素,则其x坐标是从左到右,范围为0 ~ w-1;y坐标是从上到下,范围为0 ~ h-1。
2)设置映射模式
可以使用CDC类的成员函数GetMapMode和SetMapMode来获得和设置当前的映射模式:
int GetMapMode( ) const; // 返回当前的映射模式
virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式
映射模式的nMapMode取值与含义
符号常量
数字常量
x方向
y方向
逻辑单位的大小
MM_TEXT
1
向右
向下
像素
MM_LOMETRIC
2
向右
向上
0.1 mm
MM_HIMETRIC
3
向右
向上
0.01 mm
MM_LOENGLISH
4
向右
向上
0.01 in
MM_HIENGLISH
5
向右
向上
0.001 in
MM_TWIPS
6
向右
向上
1/1440 in
MM_ISOTROPIC
7
自定义
自定义
自定义
MM_ANISOTROPIC
8
自定义
自定义
自定义
可见,除了两种自定义映射模式外,x方向都是向右,y方向也只有MM_TEXT的向下,其余的都是向上,与数学上一致。除了MM_ANISOTROPIC外,其他所有映射模式的x与y方向的单位都是相同的。所有映射模式的逻辑坐标的原点(0, 0)最初都是在窗口的左上角,但在CScrollView的派生类中,MFC会随用户滚动文档而自动调整逻辑原点的相对位置(改变视点的原点属性)。
3)自定义映射模式
自定义映射模式MM_ISOTROPIC(各向同性,x与y方向的单位必须相同)和MM_ANISOTROPIC(各向异性,x与y方向的单位可以不同)的单位和方向,可以通过用CDC类的成员函数G/SetWindowExt和G/SetViewportExt来获取/设置窗口和视口的大小来确定:
CSize GetWindowExt( ) const;
virtual CSize SetWindowExt( int cx, int cy );
virtual CSize SetWindowExt( SIZE size );
CSize GetViewportExt( ) const;
virtual CSize SetViewportExt( int cx, int cy );
virtual CSize SetViewportExt( SIZE size );
其中,cx或size.cx和cy或size.cy分别为窗口/视口的宽度与高度(逻辑单位)。
还可以用CDC类的成员函数SetViewportOrg来设置坐标原点的位置:
virtual CPoint SetViewportOrg( int x, int y );
CPoint SetViewportOrg( POINT point );
例如
void CDrawView::OnDraw(CDC* pDC) {
CRect rect;
GetClientRect(rect);
pDC->SetMapMode(MM_ANISOTROPIC);
pDC->SetWindowExt(1000,1000);
pDC->SetViewportExt(rect.right, -rect.bottom);
pDC->SetViewportOrg(rect.right / 2, rect.bottom /2);
pDC->Ellipse(CRect(-500, -500, 500, 500));
}
将当前的映射模式设置为各向异性自定义映射模式,窗口大小为1000个逻辑单位宽和1000个逻辑单位高,视口大小同当前客户区,视口的坐标原点设置在当前客户区的中央。由于使用了负数作为SetViewportExt函数的第2个参数,所以y轴方向是向上的。
可见,圆被画成了椭圆,x与y方向上的逻辑单位不相同。
4)单位转换
对所有非MM_TEXT映射模式,有如下重要规则:
l CDC的成员函数(如各种绘图函数)具有逻辑坐标参数
l CWnd的成员函数(如各种响应函数)具有设备坐标参数(如鼠标位置point)
l 位置的测试操作(如CRect的PtInRect函数)只有使用设备坐标时才有效
l 长期使用的值应该用逻辑坐标保存(如窗口滚动后保存的设备坐标就无效了)
因此,为了使应用程序能够正确工作,除MM_TEXT映射模式外,其他映射模式都需要进行单位转换。下面是逻辑单位到设备单位(如像素)的转换公式:
x比例因子 = 视口宽度 / 窗口宽度
y比例因子 = 视口高度 / 窗口高度
设备x = 逻辑x * x比例因子 + x原点偏移量
设备y = 逻辑y * y比例因子 + y原点偏移量
Windows的GDI负责逻辑坐标和设备坐标之间的转换,这可以调用CDC类的成员函数LPtoDP和DPtoLP来进行:
void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;
void LPtoDP( LPRECT lpRect ) const;
void LPtoDP( LPSIZE lpSize ) const;
void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;
void DPtoLP( LPRECT lpRect ) const;
void DPtoLP( LPSIZE lpSize ) const;
例如:
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {
CRect rect = m_rect; // 逻辑坐标
CClientDC dc(this);
dc.SetMapMode(MM_LOENGLISH);
dc.LPtoDP(rect); // 转化成设备坐标
if (rect.PtInRect(point)) // 位置的测试操作只有使用设备坐标时才有效
……
}
void CDrawView:: OnMouseMove (UINT nFlags, CPoint point) {
float t,y;
char buf[40];
CDC* pDC = GetDC();
pDC->SetMapMode(MM_HIMETRIC);
pDC->DPtoLP(&point); // 转化成逻辑坐标
t = t1 + (point.x * dt) / w; sprintf(buf, "%.4fs", t); pSB->SetPaneText(xV, buf);
y = (y0 – point.y) / dy; sprintf(buf, "%.4f", y); pSB->SetPaneText(yV, buf);
……
}
2. 画像素点
画像素点就是设置像素点的颜色,从前面3)(2)已知道这可由CDC的成员函数SetPixel来做,该函数的原型为:
COLORREF SetPixel( int x, int y, COLORREF crColor ); 或
COLORREF SetPixel( POINT point, COLORREF crColor );
其中,x与y分别为像素点的横坐标与纵坐标,crColor为像素的颜色值。例如
pDC->SetPixel(i, j, RGB(r, g, b));
3.画线状图
在Windows中,线状图必须用笔来画(笔的创建与使用见前面的3)(3)),下面是CDC类中可以绘制线状图的常用成员函数:
l 当前位置:设置当前位置为(x, y)或point:(返回值为原当前位置的坐标)
CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point );
l 画线:使用DC中的笔从当前位置画线到点(x, y)或point:(若成功返回非0值):
BOOL LineTo( int x, int y ); 或BOOL LineTo( POINT point );
l 画折线:使用DC中的笔,依次将点数组lpPoints中的nCount(≥2)个点连接起来,形成一条折线:
BOOL Polyline( LPPOINT lpPoints, int nCount );
l 画多边形:似画折线,但还会将最后的点与第一个点相连形成多边形,并用DC中的刷填充其内部区域:
BOOL Polygon( LPPOINT lpPoints, int nCount );
l 画矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形的边线,并用DC中的刷填充其内部区域:
BOOL Rectangle( int x1, int y1, int x2, int y2 ); 或
BOOL Rectangle( LPCRECT lpRect );
有时需要根据用户给定的两个任意点来重新构造左上角和右下角的点,例如:
rect = CRect(min(p0.x, point.x), min(p0.y, point.y), max(p0.x, point.x), max(p0.y, point.y));
l 画圆角矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形的边线,并用宽x3或point.x高y3或point.y矩形的内接椭圆倒角,再用DC中的刷填充其内部区域:
BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 );
BOOL RoundRect( LPCRECT lpRect, POINT point );
例如:
int d = min(rect.Width(), rect.Height()) / 4;
pDC-> RoundRect(rect, CPoint(d, d));
l 画(椭)圆:使用DC中的笔在左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形中画内接(椭)圆的边线,并用DC中的刷填充其内部区域:
BOOL Ellipse( int x1, int y1, int x2, int y2 );
BOOL Ellipse( LPCRECT lpRect );
注意,CDC中没有画圆的专用函数。在这里,圆是作为椭圆的(宽高相等)特例来画的。
l 画弧:(x1, y1)与(x2, y2)或lpRect的含义同画(椭)圆,(x3, y3)或ptStart为弧的起点,(x4, y4)或ptEnd为弧的终点:(逆时针方向旋转)
BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
画圆弧:(其中(x, y)为圆心、nRadius为半径、fStartAngle为起始角、fSweepAngle为弧段跨角)
BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);
l 画弓弦:参数的含义同上,只是用一根弦连接弧的起点和终点,形成一个弓形,并用DC中的刷填充其内部区域:
BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
4.画填充图
在Windows中,面状图必须用刷来填充(刷的创建与使用见前面的3)(4))。上面(2)中的Polygon、Rectangle、Ellipse和Chord等画闭合线状图的函数,只要DC中的刷不是空刷,都可以用来画对应的面状图(边线用当前笔画,内部用当前刷填充)。下面介绍的是CDC类中只能绘制面状图的其他常用成员函数:
l 画填充矩形:用指定的刷pBrush画一个以lpRect为区域的填充矩形,无边线,填充区域包括矩形的左边界和上边界,但不包括矩形的右边界和下边界:
void FillRect( LPCRECT lpRect, CBrush* pBrush );
l 画单色填充矩形:似FillRect,但只能填充单色,不能填充条纹和图案:
void FillSolidRect( LPCRECT lpRect, COLORREF clr );
void FillSolidRect( int x, int y, int cx, int cy, COLORREF clr );
l 画饼图(扇形):参数含义同Arc,但将起点和终点都与外接矩形的中心相连接,形成一个扇形区域,用DC中的刷填充整个扇形区域,无另外的边线:
BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
l 画拖动的矩形:先擦除线宽为sizeLast、填充刷为pBrushLast的原矩形lpRectLast,然后再以线宽为size、填充刷为pBrush画新矩形lpRectLast。矩形的边框用灰色的点虚线画,缺省的填充刷为空刷:
void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,
SIZE sizeLast, CBrush* pBrush = NULL, CBrush* pBrushLast = NULL );
如:pDC->DrawDragRect(rect, size, rect0, size);
l 填充区域:
n 用当前刷从点(x, y)开始向四周填充到颜色为crColor的边界:
BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0
n 用当前刷从点(x, y)开始向四周填充:
BOOL ExtFloodFill(int x, int y, COLORREF crColor,
UINT nFillType); // 成功返回非0
u nFillType = FLOODFILLBORDER:填充到颜色为crColor的边界(同FloodFill);(用于填充内部颜色不同但边界颜色相同的区域)
u nFillType = FLOODFILLSURFACE:填充所有颜色为crColor的点,直到碰到非crColor颜色的点为止。(点(x, y)的颜色也必须为crColor),(用于填充内部颜色相同但边界颜色可以不同的区域)。例如:
pDC->ExtFloodFill(point.x, point.y, pDC->GetPixel(point), FLOODFILLSURFACE);
5.清屏
Windows没有提供专门的清屏函数,可以调用CWnd的下面两个函数调用来完成该功能:
void Invalidate(BOOL bErase = TRUE);
void UpdateWindow( );
或调用CWnd的函数
BOOL RedrawWindow(
LPCRECT lpRectUpdate = NULL,
CRgn* prgnUpdate = NULL,
UINT flags = RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE
);
来完成。
例如(菜单项ID_CLEAR的事件处理函数):
CDrawView::OnClear() { // 调用OnDraw来清屏
//Invalidate();
//UpdateWindow( );
RedrawWindow( );
}
也可以用画填充背景色矩形的方法来清屏,如:
RECT rect;
GetClientRect(&rect);
pDC->FillSolidRect(&rect, RGB(255, 255, 255));
6.在控件上绘图
可以在对话框资源中放置图片控件,并对其类型属性选Frame。可在对话框的绘图消息响应函数OnPaint或其他函数中,用CWnd类的函数GetDlgItem:
CWnd* GetDlgItem( int nID ) const;
来获得图片控件的窗口对象,再用函数GetDC:
CDC* GetDC( );
由窗口对象得到DC,然后就可以用该DC在控件中画图。如(在ID为IDC_HUESAT的图片控件上画调色板)
void CColorDlg::OnPaint()
{
if (IsIconic()) {
… …
}
else {
CDialog::OnPaint();
int i, j;
BYTE r, g, b;
// get control window and DC of Hue&Saturation
CWnd *pWin = GetDlgItem(IDC_HUESAT);
CDC *pDC = pWin->GetDC();
// draw hue-saturation palette
for (i = 0; i < 360; i++)
for (j = 0; j <= 255; j++) {
HSLtoRGB(i, 255 - j, 128, r, g, b); // 自定义函数,见网络硬盘的
// res目录中的ColTrans.cpp文件
pDC->SetPixel(i, j, RGB(r, g, b));
}
… …
}
}
在非Frame类静态控件上绘图,必须先按顺序依次调用CWnd类的Invalidate和UpdateWindow函数后,再开始用DC画图。如在一个ID为IDC_COLOR的按钮上绘图:
void CComDlgDlg::DrawColor()
{
CWnd* pWnd = GetDlgItem(IDC_COLOR);
CDC* pDC = pWnd->GetDC();
CRect rect;
pWnd->GetClientRect(&rect);
pWnd->Invalidate();
pWnd->UpdateWindow();
pDC->FillRect(&rect, new CBrush(m_crCol));
}
若干说明:
l 除了基于对话框的程序外,其他对话框类都需要自己添加(重写型)消息响应函数OnInitDialog,来做一些必要的初始化对话框的工作。添加方法是:先在项目区选中“类视图”页,再选中对应的对话框类,然后在属性窗口的“重写”页中添加该函数;
l 为了使在运行时能够不断及时更新控件的显示(主要是自己加的显式代码),可以将自己绘制控件的所有代码都全部加入对话框类的消息响应函数OnPaint中。在需要时(例如在绘图参数修改后),自己调用CWnd的Invalidate和UpdateWindow函数,请求系统刷新对话框和控件的显示。因为控件也是窗口,控件类都是CWnd的派生类。所以在对话框和控件中,可以像在视图类中一样,调用各种CWnd的成员函数。
l 一般的对话框类,缺省时都没有明写出OnPaint函数。可以自己在对话框类中添加WM_PAINT消息的响应函数OnPaint来进行一些绘图工作。
l 为了在鼠标指向按钮时,让按钮上自己绘制的图形不被消去,可以设置按钮控件的“Owner Draw”属性为“True”。
l 如果希望非按钮控件(如图片控件和静态文本等),也可以响应鼠标消息(如单击、双击等),需要设置控件的“Notify”属性为“True”。
l 使用OnPaint函数在对话框客户区的空白处(无控件的地方)绘制自己的图形,必须屏蔽掉其中缺省的对对话框基类的OnPaint函数的调用:
//CDialog::OnPaint();
l 对话框的背景色,可以用CWnd类的成员函数:
DWORD GetSysColor( int nIndex);
得到,其中的nIndex取为COLOR_BTNFACE。例如:
dc.SetBkColor(GetSysColor(COLOR_BTNFACE));
下面是部分例子代码:(其中FillColor和ShowImg为自定义的成员函数)
void CSetDlg::OnBnClickedPenColor()
{
// TODO: 在此添加控件通知处理程序代码
CColorDialog colDlg(m_crLineColor);
if (colDlg.DoModal() == IDOK) {
m_crLineColor = colDlg.GetColor();
Invalidate();
UpdateWindow();
}
}
// ……
void CSetDlg::OnPaint()
{
CPaintDC dc(this); // device context for painting
// TODO: 在此处添加消息处理程序代码
// 不为绘图消息调用 CDialog::OnPaint()
FillColor(IDC_PEN_COLOR, m_crLineColor);
FillColor(IDC_BRUSH_COLOR, m_crBrushColor);
if(m_pBitmap0 != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp0);
else if(m_pBitmap != NULL) ShowImg(IDC_BRUSH_IMG, m_hBmp);
}
void CSetDlg::FillColor(UINT id, COLORREF col)
{
CWnd* pWnd = GetDlgItem(id);
CDC* pDC = pWnd->GetDC();
pDC->SelectObject(new CPen(PS_SOLID, 1, RGB(0, 0, 0)));
pDC->SelectObject(new CBrush(col));
CRect rect;
pWnd->GetClientRect(&rect);
pWnd->Invalidate();
pWnd->UpdateWindow();
pDC->RoundRect(&rect, CPoint(8, 8));
}
void CSetDlg::ShowImg(UINT ID, HBITMAP hBmp)
{
CWnd* pWnd = GetDlgItem(ID);
CDC* pDC = pWnd->GetDC();
CRect rect;
pWnd->GetClientRect(&rect);
pWnd->Invalidate();
pWnd->UpdateWindow();
BITMAP bs;
GetObject(hBmp, sizeof(bs), &bs);
CDC dc;
if(dc.CreateCompatibleDC(pDC)) {
int x0, y0, w, h;
float rx = (float)bs.bmWidth / rect.right,
ry = (float)bs.bmHeight / rect.bottom;
if (rx >= ry) {
x0 = 0; w = rect.right;
h = (int)(bs.bmHeight / rx + 0.5);
y0 = (rect.bottom – h) / 2;
}
else {
y0 = 0; h = rect.bottom;
w = (int)(bs.bmWidth / ry + 0.5);
x0 = (rect.right – w) / 2;
}
::SelectObject(dc.GetSafeHdc(), hBmp);
pDC->SetStretchBltMode(HALFTONE);
pDC->StretchBlt(x0, y0, w, h, &dc, 0, 0, bs.bmWidth, bs.bmHeight, SRCCOPY);
SetDlgItemInt(IDC_W, bs.bmWidth);
SetDlgItemInt(IDC_H, bs.bmHeight);
}
}
//……
5 设置绘图属性
除了映射模式外,还有许多绘图属性可以设置,如背景、绘图方式、多边形填充方式、画弧方向、刷原点等。
1.背景
1)背景色
当背景模式为不透明时,背景色决定线状图的空隙颜色(如虚线中的空隙、条纹刷的空隙和文字的空隙),可以使用CDC类的成员函数GetBkColor和SetBkColor来获得和设置当前的背景颜色:
COLORREF GetBkColor( ) const; // 返回当前的背景色
virtual COLORREF SetBkColor( COLORREF crColor ); // 返回先前的背景色
// 若出错返回0×80000000
2)背景模式
背景模式影响有空隙的线状图的空隙(如虚线中的空隙、条纹刷的空隙和文字的空隙)用什么办法填充。可以使用CDC类的成员函数GetBkMode和SetBkMode来获得和设置当前的背景模式:
int GetBkMode( ) const; // 返回当前背景模式
int SetBkMode( int nBkMode ); // 返回先前背景模式
背景模式的取值
nBkMode值
名称
作用
OPAQUE
不透明的(缺省值)
空隙用背景色填充
TRANSPARENT
透明的
空隙处保持原背景图不变
2. 绘图模式
绘图模式(drawing mode)指前景色的混合方式,它决定新画图的笔和刷的颜色(pbCol)如何与原有图的颜色(scCol)相结合而得到结果像素色(pixel)。
1)设置绘图模式
可使用CDC类的成员函数SetROP2 (ROP = Raster OPeration光栅操作)来设置绘图模式:
int SetROP2( int nDrawMode );
其中,nDrawMode可取值:
绘图模式nDrawMode的取值
符号常量
作用
运算结果
R2_BLACK
黑色
pixel = black
R2_WHITE
白色
pixel = white
R2_NOP
不变
pixel = scCol
R2_NOT
反色
pixel = ~scCol
R2_COPYPEN
覆盖
pixel = pbCol
R2_NOTCOPYPEN
反色覆盖
pixel = ~pbCol
R2_MERGEPENNOT
反色或
pixel = ~scCol | pbCol
R2_MERGENOTPEN
或反色
pixel = scCol | ~pbCol
R2_MASKNOTPEN
与反色
pixel = scCol & ~pbCol
R2_MERGEPEN
或
pixel = scCol | pbCol
R2_NOTMERGEPEN
或非
pixel = ~(scCol | pbCol)
R2_MASKPEN
与
pixel = scCol & pbCol
R2_NOTMASKPEN
与非
pixel = ~(scCol & pbCol)
R2_XORPEN
异或
pixel = scCol ^ pbCol
R2_NOTXORPEN
异或非
pixel = ~(scCol ^ pbCol)
其中,R2_COPYPEN(覆盖)为缺省绘图模式,R2_XORPEN(异或)较常用。
2)画移动图形
为了能画移动的位置标识(如十字、一字)和随鼠标移动画动态图形(如直线、矩形、椭圆),必须在不破坏原有背景图形的基础上移动这些图形。
移动图形采用的是异或画图方法,移动图形的过程为:异或画图、在原位置再异或化图(擦除)、在新位置异或画图、……。
如
pGrayPen = new CPen(PS_DOT, 0, RGB(128, 128, 128));
pDC->SetBkMode(TRANSPARENT);
pOldPen = pDC->SelectObject(pGrayPen);
pDC->SelectStockObject(NULL_BRUSH);
pDC->SetROP2(R2_XORPEN);
if (m_bErase) pDC->Ellipse(rect0);
pDC->Ellipse(rect);
pDC->SetROP2(R2_COPYPEN);
pDC->SelectObject(pOldPen);
rect0 = rect;
较完整的拖放动态画图的例子,可参照下面的“3. 拖放画动态直线”部分。
3)其他属性
l 多边形填充方式:可使用CDC类的成员函数GetPolyFillMode和SetPolyFillMode来确定多边形的填充方式:
int GetPolyFillMode( ) const;
int SetPolyFillMode( int nPolyFillMode );
其中nPolyFillMode 可取值ALTERNATE(交替——填充奇数边和偶数边之间的区域,缺省值)或WINDING(缠绕——根据多边形边的走向来确定是否填充一区域)
l 画弧方向:可使用CDC类的成员函数GetArcDirection和SetArcDirection来确定Arc、Chord、Pie等函数的画弧方向:
int GetArcDirection( ) const;
int SetArcDirection( int nArcDirection );
其中,nArcDirection可取值AD_COUNTERCLOCKWISE(逆时针方向,缺省值)和AD_CLOCKWISE(顺时针方向)
l 刷原点:可使用CDC类的成员函数GetBrushOrg和SetBrushOrg来确定可填充绘图函数的条纹或图案刷的起点:(缺省值为客户区左上角的坐标原点(0, 0))
CPoint GetBrushOrg( ) const;
CPoint SetBrushOrg( int x, int y );
CPoint SetBrushOrg( POINT point );
3.拖放画动态直线
下面是一个较完整的拖放动态画直线的例子:
// 类变量
class CDrawView : public CView {
//……
protected:
BOOL m_bLButtonDown, m_bErase; // 判断是否按下左鼠标键
//和是否需要擦除图形的类变量
CPoint p0, pm; // 记录直线起点和动态终点的类变量
CPen * pGrayPen, * pLinePen; // 定义灰色和直线笔
//……
}
// 构造函数
CDrawView::CDrawView() {
m_bLButtonDown = FALSE; // 设左鼠标键按下为假
m_bErase = FALSE; // 设需要擦除为假
pGrayPen = new CPen(PS_SOLID, 0, RGB(128, 128, 128));// 创建灰色笔
pLinePen = new CPen(PS_SOLID, 0, RGB(255, 0, 0));// 创建红色的直线笔
}
// 鼠标消息响应函数
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {
m_bLButtonDown = TRUE; // 设左鼠标键按下为真
SetCapture(); // 设置鼠标捕获
// SetCursor(LoadCursor(NULL, IDC_CROSS)); // 设置鼠标为十字
p0 = point; // 保存矩形左上角
pm = p0; // 让矩形右下角等于左上角
CView::OnLButtonDown(nFlags, point);
}
void CDrawView::OnMouseMove(UINT nFlags, CPoint point) {
SetCursor(LoadCursor(NULL, IDC_CROSS)); // 设置鼠标为十字
if (m_bLButtonDown) { // 左鼠标键按下为真
CDC* pDC = GetDC(); // 获取设备上下文
pDC->SelectObject(pGrayPen);// 选取灰色笔
pDC->SetROP2(R2_XORPEN);// 设置为异或绘图方式
if (m_bErase) { // 需要擦除为真
pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直线
}
else // 需要擦除为假
m_bErase = TRUE; // 设需要擦除为真
pDC->MoveTo(p0); pDC->LineTo(point); // 绘制新直线
pm = point; // 记录老终点
ReleaseDC(pDC); // 释放设备上下文
}
CView::OnMouseMove(nFlags, point);
}
void CDrawView::OnLButtonUp(UINT nFlags, CPoint point) {
ReleaseCapture(); // 释放鼠标捕获
if (m_bLButtonDown) { // 左鼠标键按下为真
CDC* pDC = GetDC(); // 获取设备上下文
pDC->SelectObject(pGrayPen);// 选取灰色笔
pDC->SetROP2(R2_XORPEN); // 设置为异或绘图方式
pDC->MoveTo(p0); pDC->LineTo(pm); // 擦除原直线
pDC->SelectObject(pLinePen); // 选择直线笔
pDC->SetROP2(R2_COPYPEN);// 设置为覆盖绘图方式
pDC->MoveTo(p0); pDC->LineTo(point); // 绘制最终的直线
m_bLButtonDown = FALSE; // 重设左鼠标键按下为假
m_bErase = FALSE; // 重需要擦除为假
ReleaseDC(pDC); // 释放设备上下文
}
CView::OnLButtonUp(nFlags, point);
}
你说繁华落尽,此生不渝,后来踏马离去,只有伊人独泣…(奇文共欣赏,出处不可考。) 来源: 吴添的日志
百句古文中惊艳的句子 来源: 王铮豪–Yoda的日志
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、人天自两空,何相忘,何笑何惊人。
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、凋谢是真实的,盛开只是一种过去