﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-铁观音-文章分类-VC界面控件类</title><link>http://www.cppblog.com/microli/category/2562.html</link><description>C++编程宝典</description><language>zh-cn</language><lastBuildDate>Wed, 28 May 2008 07:13:13 GMT</lastBuildDate><pubDate>Wed, 28 May 2008 07:13:13 GMT</pubDate><ttl>60</ttl><item><title>ZSplitter : adding automatic splitting for dialog controls</title><link>http://www.cppblog.com/microli/articles/13664.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Sat, 14 Oct 2006 02:44:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/13664.html</guid><description><![CDATA[
		<h2>Introduction</h2>
		<p>The <code>ZSplitterDlg</code> and <code>ZSplitter </code>classes help you to add splitters to your dialog, property sheet or any other window. It splits your controls and makes them movable and resizeable. I think this way is better than "auto size" contol: it adds a "docking" opportunity. Moreover, one more control added that add "auto size" option. Finally, you can integrate the <code>ZSplitterDlg</code> with a resizable dialog (for example <code>CResizableDialog</code> by Paolo Messina).</p>
		<p>Note that you shouldn't add anything to your resources and shouldn't describe the relations between controls. Just make the corresponding size and position of your controls and use the functions:</p>
		<pre>
				<span class="cpp-keyword">void</span> addControls(<span class="cpp-keyword">int</span> count, <span class="cpp-keyword">bool</span> connectVertical, ...);
<span class="cpp-keyword">void</span> addControl(<span class="cpp-keyword">int</span> id);
</pre>
		<p>Demo project shows using these automatically added controls in <code>CDialog</code>, <code>CPropertyPage</code>, <code>CView </code>and <code>CFormView </code>classes.</p>
		<p>
				<img alt="Sample Image" src="http://www.codeproject.com/splitter/zsplitter/zsplitter2.gif" />
		</p>
		<h2>Using the class</h2>
		<p>The simplest way is to use the <code>ZSplitterDlgImpl</code> template. You should change: 
</p>
		<ul>
				<li>The parent of your dialog ot view class, 
</li>
				<li>the constructor implementation, 
</li>
				<li>the second parameter in <code>BEGIN_MESSAGE_MAP</code> macros, and 
</li>
				<li>the "on init" function of your window. </li>
		</ul>
		<pre>
				<span class="cpp-comment">// in header</span>
				<span class="cpp-keyword">class</span> CTestDlg1 : <span class="cpp-keyword">public</span> ZSplitterDlgImpl&lt;CPropertyPage&gt;

<span class="cpp-comment">// in source</span>
CTestDlg1::CTestDlg1() : <span class="cpp-comment">/*...*/</span> ZSplitterDlgImpl&lt;CPropertyPage&gt;(CTestDlg1::IDD) {}

BEGIN_MESSAGE_MAP(CTestDlg1, ZSplitterDlgImpl&lt;CPropertyPage&gt;)
	<span class="cpp-comment">//	...</span>
END_MESSAGE_MAP()

BOOL CTestDlg1::OnInitDialog() 
{
	<span class="cpp-comment">// ... and use addControl(s) function here</span>
	init();
	<span class="cpp-comment">// ...</span>
}
</pre>
		<p>The <code>ZSplitterDlgImpl</code> template has a second parameter (<code>ZSplitter2</code> by default). <code>ZSplitter2 </code>is the implementation of a spliter control. It has a virtual function <code>OnPaint()</code> - and you can change it's realisation to have different view of your control (see <code>CMyView1</code> class in demo project). </p>
		<p>The <code>ZSplitterDlgImpl</code> template helps you to implement splitter controls but you can use its base <code>ZSplitterDlg </code>class (look for <code>CTestDlg2 </code>class) in demo project. </p>
		<p>I remade a little <a href="http://www.codeproject.com/dialog/resizabledialog.asp"><code>CResizableDialog</code></a> with the permission of the author and you can use it with my splitters: use the <code>ZSplitterDlgResizable </code>class for this job. (look for <code>CDemoDlg </code>class) in the demo project. </p>
		<p>
				<img alt="resizable sample" src="http://www.codeproject.com/splitter/zsplitter/zsplitter6.gif" />
		</p>
		<p>This is a sample of your dialog in resource editor: </p>
		<p>
				<img alt="in vc++ editor" src="http://www.codeproject.com/splitter/zsplitter/zsplitter1.gif" />
		</p>
		<p>And user can change it in such way in runtime. </p>
		<p>
				<img alt="after user manipulations" src="http://www.codeproject.com/splitter/zsplitter/zsplitter5.gif" />
		</p>
		<p>You should use the <code>addControls</code> or <code>addControl</code> functions to add one control to the "splitter set" or a group of controls: they will move together. This is an example which you seen above </p>
		<pre>  addControls(<span class="cpp-literal">2</span>,<span class="cpp-keyword">false</span>,IDC_LIST6,IDC_LIST7);
  addControls(<span class="cpp-literal">2</span>,<span class="cpp-keyword">true</span>,IDC_LIST1,IDC_LIST8);
  addControl(IDC_LIST9);
  addControl(IDC_LIST2);
  addControl(IDC_LIST3);
  addControl(IDC_LIST4);
  addControl(IDC_LIST5);
</pre>
		<p>Moreover you can manually add a <code>ZSplitter</code> class (the most common splitter controls) to a page. Look at the images and in the <code>CTestDlg3</code> class of the demo project for details. </p>
		<p>
				<img alt="before moving" src="http://www.codeproject.com/splitter/zsplitter/zsplitter3.gif" />
				<img alt="after moving" src="http://www.codeproject.com/splitter/zsplitter/zsplitter4.gif" />
		</p>
		<h2>To Do list</h2>
		<p>I'd like to make the look (color, size, effects) of the splitter more presentable. So I want to get comments from you. First of all: is this technique useful to you? </p>
		<h2>Note</h2>
		<p>Make sure to check out the my web site which is more likely to have updates and betas:<br /><a href="http://www.zmike.net/">http://www.zmike.net</a><!-- Article Ends --></p>
		<script src="/script/togglePre.js" type="text/javascript">
		</script>
		<h2>About Mike Melnikov</h2>
		<div style="OVERFLOW: hidden">
				<table border="0">
						<tbody>
								<tr valign="top">
										<td class="smallText" nowrap="">
												<img src="http://www.codeproject.com/script/profile/images/{AC9D1A81-28F0-485D-B63F-BB9967103B02}.jpg" />
												<br />
										</td>
										<td class="smallText">Mike has been programming in C/C++ for 11 years and Visual C++/MFC for 4 years. His background includes pure and applied mathematics, engineering and physics, and he is currently based in Moscow, Russia. 
<p class="smallText">Click <a href="http://www.codeproject.com/script/profile/whos_who.asp?vt=arts&amp;id=157">here</a> to view Mike Melnikov's online profile.</p></td>
								</tr>
						</tbody>
				</table>
		</div>
<img src ="http://www.cppblog.com/microli/aggbug/13664.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-10-14 10:44 <a href="http://www.cppblog.com/microli/articles/13664.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CSplitterWnd in a Dialog based Application</title><link>http://www.cppblog.com/microli/articles/13663.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Sat, 14 Oct 2006 02:42:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/13663.html</guid><description><![CDATA[
		<a name="more"> 
<p>Had this problem before. I guess there are some more interested in a solution.<br /><br />It seems CSplitterWnd is designed to be used in document/view-based applications only. <br />But by overriding some virtual methods in a derived class, you can make splitter windows based on CSplitterWnd be used in dialog based application, ActiveX-Controls using MFC:<br /><br />All virtual methods that call GetParentFrame() in its implementation have to be overridden. <br />I have done this by using existing code except<br />- that I replaced the call to GetParentFrame() by a call to GetParent(). <br />- all references or pointers to CFrameWnd were changed to references or pointers to CWnd. <br /><br />I derived a class CxSplitterWnd from the class CSplitterWnd and proceeded as stated above. <br />Then I used this class in a dialog based application in the same way as any other CWnd derived class.<br />For example: </p><pre><font color="#0000ff"><span class="codeKeyword">class</span></font> CSampleDialog : <font color="#0000ff"><span class="codeKeyword">public</span></font> CDialog
{
	...
	CxSplitterWnd m_wndSplitter;
	....
}

BOOL CSampleDlg::OnInitDialog()
{
...
	<font color="#009900">// TODO: Add extra initialization here</font>
	m_wndSplitter.CreateStatic(<font color="#0000ff"><span class="codeKeyword">this</span></font>, 1, 2);
	m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CSampleView), CSize(50,0), <span class="codeKeyword">NULL</span>);
	m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CSampleView), CSize(0,0), <span class="codeKeyword">NULL</span>);

	CRect rect = ...;
	m_wndSplitter.MoveWindow(&amp;rect);
	...
}
</pre><p>The sample attached is a dialog based application and demonstrates the use of CxSplitterWnd. It does<br />nothing useful.<br /><br />This is the new class declaration:</p><pre><font color="#009900">// SplitWnd.h : implementation file</font><font color="#009900">// </font><font color="#0000ff"><span class="codeKeyword">class</span></font> CxSplitterWnd : <font color="#0000ff"><span class="codeKeyword">public</span></font> CSplitterWnd
{
	<font color="#009900">// Construction</font><font color="#0000ff"><span class="codeKeyword">public</span></font>:
	CxSplitterWnd() {};
	<font color="#0000ff"><span class="codeKeyword">virtual</span></font> ~CxSplitterWnd() {};

	<font color="#009900">// Operations</font><font color="#0000ff"><span class="codeKeyword">public</span></font>:
	<font color="#009900">// Overrides</font><font color="#009900">// ClassWizard generated <span class="codeKeyword">virtual</span> function overrides</font><font color="#009900">//{{AFX_VIRTUAL(CxSplitterWnd)</font><font color="#009900">//}}AFX_VIRTUAL </font><font color="#009900">// Implementation</font><font color="#0000ff"><span class="codeKeyword">public</span></font>:
	<font color="#009900">// These are the methods to be overridden</font><font color="#0000ff"><span class="codeKeyword">virtual</span></font><font color="#0000ff"><span class="codeKeyword">void</span></font> StartTracking(<font color="#0000ff"><span class="codeKeyword">int</span></font> ht);
	<font color="#0000ff"><span class="codeKeyword">virtual</span></font> CWnd* GetActivePane(<font color="#0000ff"><span class="codeKeyword">int</span></font>* pRow = <span class="codeKeyword">NULL</span>, <font color="#0000ff"><span class="codeKeyword">int</span></font>* pCol = <span class="codeKeyword">NULL</span>);
	<font color="#0000ff"><span class="codeKeyword">virtual</span></font><font color="#0000ff"><span class="codeKeyword">void</span></font> SetActivePane( <font color="#0000ff"><span class="codeKeyword">int</span></font> row, <font color="#0000ff"><span class="codeKeyword">int</span></font> col, CWnd* pWnd = <span class="codeKeyword">NULL</span> );
	<font color="#0000ff"><span class="codeKeyword">virtual</span></font> BOOL OnCommand(WPARAM wParam, LPARAM lParam);
	<font color="#0000ff"><span class="codeKeyword">virtual</span></font> BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult );
	<font color="#0000ff"><span class="codeKeyword">virtual</span></font> BOOL OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult );

	<font color="#009900">// Generated message map functions</font><font color="#0000ff"><span class="codeKeyword">protected</span></font>:
	<font color="#009900">//{{AFX_MSG(CxSplitterWnd)</font><font color="#009900">// NOTE - the ClassWizard will add and remove member functions here.</font><font color="#009900">//}}AFX_MSG</font>
	DECLARE_MESSAGE_MAP()
};

</pre>And here the implementation file: <pre><font color="#009900">// SplitWnd.cpp : implementation file</font><font color="#009900">// </font><span class="codeKeyword">#include</span> "stdafx.h"
<span class="codeKeyword">#include</span> "SplitWnd.h"

#ifdef _DEBUG
<span class="codeKeyword">#define</span><font color="#0000ff"><span class="codeKeyword">new</span></font> DEBUG_NEW
#undef THIS_FILE
<font color="#0000ff"><span class="codeKeyword">static</span></font><font color="#0000ff"><span class="codeKeyword">char</span></font> THIS_FILE[] = __FILE__;
#endif

<font color="#009900">// HitTest <span class="codeKeyword">return</span> values (values and spacing between values <span class="codeKeyword">is</span> important)</font><font color="#009900">// Had to adopt <span class="codeKeyword">this</span> because it has module scope </font><font color="#0000ff"><span class="codeKeyword">enum</span></font> HitTestValue
{
	noHit = 0,
	vSplitterBox = 1,
	hSplitterBox = 2,
	bothSplitterBox = 3, <font color="#009900">// just <span class="codeKeyword">for</span> keyboard</font>
	vSplitterBar1 = 101,
	vSplitterBar15 = 115,
	hSplitterBar1 = 201,
	hSplitterBar15 = 215,
	splitterIntersection1 = 301,
	splitterIntersection225 = 525
};

<font color="#009900">/////////////////////////////////////////////////////////////////////////////</font><font color="#009900">// CxSplitterWnd </font>

BEGIN_MESSAGE_MAP(CxSplitterWnd, CSplitterWnd)
<font color="#009900">//{{AFX_MSG_MAP(CxSplitterWnd)</font><font color="#009900">// NOTE - the ClassWizard will add and remove mapping macros here.</font><font color="#009900">//}}AFX_MSG_MAP</font>
END_MESSAGE_MAP()

CWnd* CxSplitterWnd::GetActivePane(<font color="#0000ff"><span class="codeKeyword">int</span></font>* pRow, <font color="#0000ff"><span class="codeKeyword">int</span></font>* pCol)
{
	ASSERT_VALID(<font color="#0000ff"><span class="codeKeyword">this</span></font>);
	CWnd* pView = GetFocus();
	<font color="#009900">// make sure the pane <span class="codeKeyword">is</span> a child pane of the splitter</font><font color="#0000ff"><span class="codeKeyword">if</span></font> (pView != <span class="codeKeyword">NULL</span> &amp;&amp; !IsChildPane(pView, pRow, pCol))
	pView = <span class="codeKeyword">NULL</span>;
	<font color="#0000ff"><span class="codeKeyword">return</span></font> pView;
}

<font color="#0000ff"><span class="codeKeyword">void</span></font> CxSplitterWnd::SetActivePane( <font color="#0000ff"><span class="codeKeyword">int</span></font> row, <font color="#0000ff"><span class="codeKeyword">int</span></font> col, CWnd* pWnd)
{
	<font color="#009900">// set the focus to the pane</font>
	CWnd* pPane = pWnd == <span class="codeKeyword">NULL</span> ? GetPane(row, col) : pWnd;
	pPane-&gt;SetFocus();
}

<font color="#0000ff"><span class="codeKeyword">void</span></font> CxSplitterWnd::StartTracking(<font color="#0000ff"><span class="codeKeyword">int</span></font> ht)
{
ASSERT_VALID(<font color="#0000ff"><span class="codeKeyword">this</span></font>);
	<font color="#0000ff"><span class="codeKeyword">if</span></font> (ht == noHit)
		<font color="#0000ff"><span class="codeKeyword">return</span></font>;
	<font color="#009900">// GetHitRect will restrict 'm_rectLimit' <span class="codeKeyword">as</span> appropriate</font>
	GetInsideRect(m_rectLimit);
	<font color="#0000ff"><span class="codeKeyword">if</span></font> (ht &gt;= splitterIntersection1 &amp;&amp; ht &lt;= splitterIntersection225)
	{
		<font color="#009900">// split two directions (two tracking rectangles)</font><font color="#0000ff"><span class="codeKeyword">int</span></font> row = (ht - splitterIntersection1) / 15;
		<font color="#0000ff"><span class="codeKeyword">int</span></font> col = (ht - splitterIntersection1) % 15;
		GetHitRect(row + vSplitterBar1, m_rectTracker);
		<font color="#0000ff"><span class="codeKeyword">int</span></font> yTrackOffset = m_ptTrackOffset.y;
		m_bTracking2 = TRUE;
		GetHitRect(col + hSplitterBar1, m_rectTracker2);
		m_ptTrackOffset.y = yTrackOffset;
	}
	<font color="#0000ff"><span class="codeKeyword">else</span></font><font color="#0000ff"><span class="codeKeyword">if</span></font> (ht == bothSplitterBox)
	{
		<font color="#009900">// hit on splitter boxes (<span class="codeKeyword">for</span> keyboard)</font>
		GetHitRect(vSplitterBox, m_rectTracker);
		<font color="#0000ff"><span class="codeKeyword">int</span></font> yTrackOffset = m_ptTrackOffset.y;
		m_bTracking2 = TRUE;
		GetHitRect(hSplitterBox, m_rectTracker2);
		m_ptTrackOffset.y = yTrackOffset;
		<font color="#009900">// center it</font>
		m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2);
		m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0);
	}
	<font color="#0000ff"><span class="codeKeyword">else</span></font>
	{
		<font color="#009900">// only hit one bar</font>
		GetHitRect(ht, m_rectTracker);
	}

	<font color="#009900">// steal focus and capture</font>
	SetCapture();
	SetFocus();
	<font color="#009900">// make sure no updates are pending</font>
	RedrawWindow(<span class="codeKeyword">NULL</span>, <span class="codeKeyword">NULL</span>, RDW_ALLCHILDREN | RDW_UPDATENOW);
	<font color="#009900">// set tracking state and appropriate cursor</font>
	m_bTracking = TRUE;
	OnInvertTracker(m_rectTracker);
	<font color="#0000ff"><span class="codeKeyword">if</span></font> (m_bTracking2)
	OnInvertTracker(m_rectTracker2);
	m_htTrack = ht;
	SetSplitCursor(ht);
}

<font color="#009900">/////////////////////////////////////////////////////////////////////////////</font><font color="#009900">// CSplitterWnd command routing </font>
BOOL CxSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam)
{
	<font color="#0000ff"><span class="codeKeyword">if</span></font> (CWnd::OnCommand(wParam, lParam))
	<font color="#0000ff"><span class="codeKeyword">return</span></font> TRUE;
	<font color="#009900">// route commands to the splitter to the parent frame window</font><font color="#0000ff"><span class="codeKeyword">return</span></font> GetParent()-&gt;SendMessage(WM_COMMAND, wParam, lParam);
}

BOOL CxSplitterWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
	<font color="#0000ff"><span class="codeKeyword">if</span></font> (CWnd::OnNotify(wParam, lParam, pResult))
	<font color="#0000ff"><span class="codeKeyword">return</span></font> TRUE;
	<font color="#009900">// route commands to the splitter to the parent frame window</font>
	*pResult = GetParent()-&gt;SendMessage(WM_NOTIFY, wParam, lParam);
	<font color="#0000ff"><span class="codeKeyword">return</span></font> TRUE;
}

BOOL CxSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
{
	<font color="#009900">// The code line below <span class="codeKeyword">is</span> necessary <span class="codeKeyword">if</span><span class="codeKeyword">using</span> CxSplitterWnd <span class="codeKeyword">in</span> a regular dll</font><font color="#009900">// AFX_MANAGE_STATE(AfxGetStaticModuleState()); </font><font color="#0000ff"><span class="codeKeyword">return</span></font> CWnd::OnWndMsg(message, wParam, lParam, pResult);
}
</pre></a>
<img src ="http://www.cppblog.com/microli/aggbug/13663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-10-14 10:42 <a href="http://www.cppblog.com/microli/articles/13663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC设计分割视图通用创建框架</title><link>http://www.cppblog.com/microli/articles/11914.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Fri, 01 Sep 2006 02:08:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/11914.html</guid><description><![CDATA[
		<font color="#dc6900">简 介】<br /></font>　　目前基于分割视图的应用开发十分流行，分割视图技术是在同一个框架窗口下同时显示多个视图的一项技术。运用分割视图，可以在较短时间内给用户更多的信息量，从而使得用户界面更加的友好，增强了软件的可操作性。本文提出一个分割视图的通用创建框架。 <br /><br />目前基于分割视图的应用开发十分流行，分割视图技术是在同一个框架窗口下同时显示多个视图的一项技术。运用分割视图，可以在较短时间内给用户更多的信息量，从而使得用户界面更加的友好，增强了软件的可操作性。本文提出一个分割视图的通用创建框架。　　 <br /><br />　　1．分割视图创建框架 <br /><br />　　分割视图的创建大体上分为两个步骤：其一是创建分割窗体；然后就是处理鼠标和键盘等消息。 <br /><br />　　1) 创建分割窗体 <br /><br />　　MFC提供分割窗体类CsplitterWnd，它提供了很多对于分割窗体操作的成员函数，每一个分割窗体都是一个CsplitterWnd的对象。本文提出的框架由于需要对定制的分割窗体进行扩充处理，所以首先从CsplitterWnd继承一个子类CFixSplitterWnd，然后每个分割窗体是一个CfixSplitterWnd的对象，这样以后只需要对CfixSplitterWnd进行改写后就可以增强分割窗体的功能。（后面将提出这种改写） <br /><br />　　创建分割窗体最重要的函数是主框架类的OnCreateClient函数，它将在主框架创建的时候调用，本文将创建一个如下显示的分割窗体： <br /><br /><center><img alt="VC设计分割视图通用创建框架" src="http://myarticle.enet.com.cn/images/2006/0704/1151970239931.gif" border="0" /></center>　　 <br /><br />　　则可以如下实现：　　 <br /><br />　　//成员变量声明 <br /><br />　　CFixSplitterWnd m_wndSplitterH; //用于横向切割 <br /><br />　　CFixSplitterWnd m_wndSplitterV; //用于纵向切割 <br /><br />　　BOOL m_bCreateSplitter;　　 <br /><br />　　//分割窗体的实现 <br /><br />　　BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext) <br /><br />　　{ <br /><br />　　//对整个主框架进行混合分割视图 <br /><br />　　BOOL bResult=m_wndSplitterV.CreateStatic(this,1,2); <br /><br />　　ASSERT(bResult); <br /><br />　　m_wndSplitterH.CreateStatic(&amp;m_wndSplitterV,4,1,WS_CHILD 　 WS_VISIBLE,m_wndSplitterV.IdFromRowCol(0,1)); <br /><br />//创建各自子窗片的对应的视图 <br /><br />　　m_wndSplitterV.CreateView(0,0,RUNTIME_CLASS(CSceneView),CSize(600,600),pContext); <br /><br />　　m_wndSplitterH.CreateView(0,0,RUNTIME_CLASS(CPitchView),CSize(100,100),pContext); <br /><br />　　m_wndSplitterH.CreateView(1,0,RUNTIME_CLASS(CYawView),CSize(100,100),pContext); <br /><br />　　m_wndSplitterH.CreateView(2,0,RUNTIME_CLASS(CRollView),CSize(100,100),pContext); <br /><br />　　m_wndSplitterH.CreateView(3,0,RUNTIME_CLASS(CControlView),CSize(100,100),pContext); <br /><br />　　//设置窗格的初始化的大小 <br /><br />　　m_wndSplitterV.SetRowInfo(0,IDEAL_RAWHEIGHT,0); <br /><br />　　m_bCreateSplitter=TRUE; <br /><br />　　//激活sceneview使得其可以接受命令消息 <br /><br />　　m_wndSplitterV.SetActivePane(0,0,NULL); <br /><br />　　return bResult; <br /><br />　　} <br /><br />　　//主框架窗体大小发生变化，调节相应的窗体大小 <br /><br />　　void CMainFrame::OnSize(UINT nType, int cx, int cy) <br /><br />　　{ <br /><br />　　CMDIFrameWnd::OnSize(nType, cx, cy); <br /><br />　　CRect rect; <br /><br />　　GetClientRect(rect); <br /><br />　　if (m_bCreateSplitter) <br />      { <br /><br />　　m_wndSplitterV.SetColumnInfo(0,rect.Width() *3/4,10); <br /><br />　　m_wndSplitterV.SetColumnInfo(1,rect.Width() *1/4,10); <br /><br />　　m_wndSplitterH.SetRowInfo(0,rect.Height() /6,10); <br /><br />　　m_wndSplitterH.SetRowInfo(1,rect.Height() /6,10); <br /><br />　　m_wndSplitterH.SetRowInfo(2,rect.Height() /6,10); <br /><br />　　m_wndSplitterH.SetRowInfo(3,rect.Height()/2,10); <br /><br />　　} <br /><br />　　m_wndSplitterV.RecalcLayout(); <br /><br />　　m_wndSplitterH.RecalcLayout(); <br /><br />　　} <br /><br />　　注意m_wndSplitterH.CreateView 中的第二个参数，这个参数将分割窗体和相应的视图类相对应。 <br /><br />　　通过上述的程序代码即可创建图1所示的分割窗体，那么由于这里每个分割窗体都是一个CfixSplitterWnd对象，所以可以通过改写CfixSplitterWnd类的虚函数或消息处理函数来完成自己特定的应用实现。（注意，如果需要对定制有特定属性的分割窗体，一定要派生自己的分割窗体类而不能是MFC的CsplitterWnd类）这里我们需要分割窗体不能随鼠标拖动而改变其大小，即所有窗格的大小都是一定的，不能在运行时刻改变。所以必须在CfixSplitterWnd类的实现中加入如下代码：　　 <br /><br />　　void CFixSplitterWnd::OnMouseMove(UINT nFlags, CPoint point) <br /><br />　　{ <br /><br />　　CWnd::OnMouseMove(nFlags, point); //防止鼠标出现拖动状 <br /><br />　　// CSplitterWnd::OnMouseMove(nFlags, point); //鼠标会在窗体边界出现拖动状 <br /><br />　　} <br /><br />　　至此，分割窗体已经创建完毕，下面需要在分割窗体里处理消息。 <br /><br />　　2) 分割窗体处理消息 <br /><br />　　在分割窗体里处理消息和一般的文档视图模型处理消息大致一样，但它也有其特殊之处。具体来说,由于各个分割窗体已经与具体的视图类相联系了，所以在需要处理各个分割窗体中的消息时，可以直接到相应的视图类中进行处理；另外，多视图之间的切换会导致目标焦点之间的变更，这样会影响菜单中与视图有关的命令的执行。比如在图1中所示的分割窗体中，有一个“开始”命令必须是焦点在CsceneView视图上时才能执行，否则就应该让该命令不能执行（即该菜单呈现灰色），则实现时可以首先对鼠标进行点击测试，判断是否在CsceneView视图范围内，如果是的话就允许执行，否则就不允许执行。 <br /><br />　　2．结论 <br /><br />　　通过本文提出的分割视图创建框架，可以满足对视图进行复杂控制的需求，希望本文可以给大家一个启发，从而能够创建更为完美的分割视图应用程序。<a href="http://www.enet.com.cn/"><img height="11" src="http://images.enet.com.cn/end.gif" width="11" align="absMiddle" border="0" target="_blank" /></a><br /><img src ="http://www.cppblog.com/microli/aggbug/11914.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-09-01 10:08 <a href="http://www.cppblog.com/microli/articles/11914.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用VC6.0实现窗口的任意分割</title><link>http://www.cppblog.com/microli/articles/11913.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Fri, 01 Sep 2006 01:56:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/11913.html</guid><description><![CDATA[
		<table cellspacing="0" cellpadding="0" width="100%" border="0">
				<tbody>
						<tr>
								<td width="40" height="74">
								</td>
								<td valign="top" width="*" height="74">
										<form name="form2" action="/SYS/script/find.asp" method="post">
												<table cellspacing="0" cellpadding="0" width="100%" border="0">
														<tbody>
																<tr>
																		<td>
																				<span id="docinfo">[ <font color="#009900">原创文档</font> 本文适合中级读者 已阅读n次 ]</span>
																		</td>
																		<td align="right">
																				<input class="rect" maxlength="20" size="10" name="keyword" />
																				<select class="rect" name="gclsid">
																						<option value="100" selected="">文档</option>
																						<option value="200">代码</option>
																						<option value="400">工具</option>
																				</select>
																				<input type="image" height="15" width="21" src="http://www.vckbase.com/document/image/go.gif" align="absMiddle" border="0" name="imageField" />
																		</td>
																</tr>
														</tbody>
												</table>
										</form>
										<p align="center">
												<span class="big">
														<b>
																<font color="#006633">使用VC6.0实现窗口的任意分割</font>
																<br />
														</b>南京邮政局计算机中心 张中庆</span>
										</p>
										<div align="center">
												<table class="big" height="46" cellspacing="0" cellpadding="0" width="100%" border="0">
														<tbody>
																<tr>
																		<td>
																				<p>
																						<b>一、关于CSplitterWnd类</b>
																						<br />我们在使用CuteFtp或者NetAnt等工具的时候，一般都会被其复杂的界面所吸引，在这些界面中窗口被分割为若干的区域，真正做到了窗口的任意分割。 那么我们自己如何创建类似的界面，也实现窗口的任意的分割呢 ？在VC6.0中这就需要使用到CSplitterWnd类。CSplitterWnd看上去像是一种特殊的框架窗口，每个窗口都被相同的或者不同的视图所填充。当窗口被切分后用户可以使用鼠标移动切分条来调整窗口的相对尺寸。虽然VC6.0支持从AppWizard中创建分割窗口，但是自动加入的分割条总是不能让我们满意，因此我们还是通过手工增加代码来熟悉这个类。 <br />CSplitterWnd的构造函数主要包括下面三个。 <br /></p>
																				<pre>BOOL Create(CWnd* pParentWnd,int nMaxRows,int nMaxCols,SIZE sizeMin,CCreateContext* pContext,DWORD dwStyle,UINT nID);</pre>功能描述：该函数用来创建动态切分窗口。 参数含义：pParentWnd 切分窗口的父框架窗口。 nMaxRows,nMaxCols是创建的最大的列数和行数。 sizeMin是窗格的现实大小。 pContext 大多数情况下传给父窗口。 nID是字窗口的ID号. <pre>BOOL CreateStatic(CWnd* pParentWnd,int nRows,int nCols,DWORD dwStyle,UINT nID) </pre>功能描述：用来创建切分窗口。 参数含义同上。 <pre>BOOL CreateView (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext);</pre>功能描述：为静态切分的窗口的网格填充视图。在将视图于切分窗口联系在一起的时候必 须先将切分窗口创建好。 <br />参数含义：同上。<br />从CSplitterWnd源程序可以看出不管是使用动态创建Create还是使用静态创建CreateStatic，在函数中都调用了一个保护函数CreateCommon，从下面的CreateCommon函数中的关键代码可以看出创建CSplitterWnd的实质是创建了一系列的MDI子窗口。 <br /><pre>DWORD dwCreateStyle = dwStyle &amp; ~(WS_HSCROLL|WS_VSCROLL);
if (afxData.bWin4) 
       dwCreateStyle &amp;= ~WS_BORDER; //create with the same wnd-class as MDI-Frame (no erase bkgnd) 
if (!CreateEx(0, _afxWndMDIFrame, NULL, dwCreateStyle, 
          0, 0, 0, 0,pParentWnd-&gt;m_hWnd, (HMENU)nID, NULL)) 
       return FALSE; // create invisible 
          </pre><br /><b>二、创建嵌套分割窗口</b><br /><b>2.1创建动态分割窗口</b><br />动态分割窗口使用Create方法。下面的代码将创建2x2的窗格。 <br /><pre>m_wndSplitter.Create(this,2,2,CSize(100,100),pContext);</pre><br />但是动态创建的分割窗口的窗格数目不能超过2x2，而且对于所有的窗格，都必须共享同一个视图，所受的限制也比较多，因此我们不将动态创建作为重点。我们的主要精力放在静态分割窗口的创建上。 <br /><b>2.2创建静态分割窗口</b><br />与动态创建相比，静态创建的代码要简单许多，而且可以最多创建16x16的窗格。不同的窗格我们可以使用CreateView填充不同的视图。 <br />在这里我们将创建CuteFtp的窗口分割。CuteFtp的分割情况如下： 
<div align="center"><table height="223" cellspacing="1" cellpadding="0" width="446" bgcolor="#666666" border="0"><tbody><tr bgcolor="#eeeeee"><td colspan="2" height="46"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CCuteFTPView</font></div></td></tr><tr bgcolor="#eeeeee"><td height="123"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CView2</font></div></td><td height="123"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CView3</font></div></td></tr><tr bgcolor="#eeeeee"><td colspan="2" height="44"><div align="center"><font face="Arial, Helvetica, sans-serif" size="2">CView4</font></div></td></tr></tbody></table></div><p>创建步骤： <br />▲ 在创建之前我们必须先用AppWizard生成单文档CuteFTP，生成的视类为 CCuteFTPView.同时在增加三个视类或者从视类继承而来的派生类CView2,CView3 CView4. <br />▲ <b>增加成员：</b><br />在Cmainfrm.h中我们将增加下面的代码： <br /></p><pre>CSplitterWnd wndSplitter1;
                  CSplitterWnd wndSplitter2;</pre>▲ <b>重载CMainFrame::OnCreateClient()函数：</b><pre>BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT  /*lpcs*/, CCreateContext* pContext) 
{ //创建一个静态分栏窗口，分为三行一列 
     if(m_wndSplitter1.CreateStatic(this,3,1)==NULL) 
              return FALSE;
  //将CCuteFTPView连接到0行0列窗格上
     m_wndSplitter1.CreateView(0,0,RUNTIME_CLASS(CCuteFTPView),CSize(100,100), pContext); 
     m_wndSplitter1.CreateView(2,0,RUNTIME_CLASS(CView4),CSize(100,100),pContext); 
  //将CView4连接到0行2列
     if(m_wndSplitter2.CreateStatic(&amp;m_wndSplitter,1,2,WS_CHILD|WS_VISIBLE, 
          m_wndSplitter.IdFromRowCol(1, 0))==NULL) 
               return FALSE; //将第1行0列再分开1行2列 
  //将CView2类连接到第二个分栏对象的0行0列
          m_wndSplitter2.CreateView(0,0,RUNTIME_CLASS(CView2),CSize(400,300),pContext); 
  //将CView3类连接到第二个分栏对象的0行1列
          m_wndSplitter2.CreateView(0,1,RUNTIME_CLASS(CView3),CSize(400,300),pContext); 
               return TRUE; 
} </pre><b>2.3实现各个分割区域的通信</b><br />■<b>有文档相连的视图之间的通信<br /></b>由AppWizard生成的CCuteFTPView是与文档相连的，同时我们也让CView2与文档相连，因此我们需要修改CCuteFTPApp的InitInstance()函数，我们将增加下面的部分。<br /><pre>AddDocTemplate (new CMultiDocTemplate(IDR_VIEW2TYPE, 
          
          RUNTIME_CLASS(CMainDoc), 
          RUNTIME_CLASS(CMDIChildWnd), 
          RUNTIME_CLASS(CView2))); </pre>我们现在来实现CCuteFTPView与CView2之间的通信。由于跟文档类相连的视图类 是不能安全的与除文档类之外的其余的视图类通信的。因此我们只能让他们都与文档 类通信。在文档中我们设置相应的指针以用来获的各个视图。我们重载 CCuteFTPView::OnOpenDocument()函数； <br /><pre>CCuteFTPView* pCuteFTPView;<br />CView2* pView2;
POSITION pos;
CView* pView;
while(pos!=NULL)
{
      pView=GetNextView(pos); 
      if(pView-&gt;IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) 
          pCuteFTPView=(CCuteFTPView*)pView; 
      else(pView-&gt;IsKindOf(RUNTIME_CLASS(CCuteFTPView))==NULL) 
          pView2=(CView2*)pView; 
} </pre>这样我们在文档类中就获的了跟它相连的所有的视图的指针。<br />如果需要在 CCuteFTPView中调用CView2中的一个方法DoIt()则代码如下： <br /><pre>CCuteFTPDoc* pDoc=GetDocument();<br />CView2* pView2=pDoc-&gt;pView3;<br />pView3.DoIt(); </pre><br />■<b>无文档视图与文档关联视图之间的通信<br /></b>CView3和CView4都是不与文档相关联的。我们现在实现CView3与CView2的通信.正如前面所说，CView2只能安全的与CCuteFTPDoc通信，因此，CView3如果需要跟CView2通信，也必须借助于文档类。因此程序的关键是如何在CView3中获得文档的指针。视图类中没有这样的类成员可以用来直接访问文档类。但是我们知道在主窗口类MainFrame中我们可以获得程序的任意窗口类的指针。因此我们只要获得程序主窗口了的指针，就可以解决问题了。代码实现在CView3中访问CView2中的DoIt()方法。<br /><br />CView3中的代码如下： <pre>CMainFrame* MainFrame=(CMainFrame*)this-&gt;GetParent()-&gt;GetParent(); 
          
          CCuteFTPDoc* Doc=(CCuteFTPDoc*)MainFrame-&gt;GetActiveDocument();
          if(Doc!=NULL) Doc-&gt;DoIt(); 
          
          CCuteFTPDoc中的相应的处理函数DoIt()代码如下： 
          
          CView2* pView2; 
          POSITION pos; 
          CView* pView; 
          while(pos!=NULL) 
          { 
                  pView=GetNextView(pos);
                  if(pView-&gt;IsKindOf(RUNTIME_CLASS(CView2))==NULL) 
                  pView2=(CView2*)pView; 
          } 
          pView2-&gt;DoIt(); </pre>■<b>无文档关联视图之间的通信<br /></b>CView3和CView4都是不跟文档相连的，如何实现他们之间的通信呢。 正如我们在上面所说的那样，由于在主框架中我们可以访问任意的视图，因此我们的主要任 务还是在程序中获得主框架的指针。在CView3中访问CView4中的方法DoIt()。 <br /><pre>CMainFrame* MainFrame=(CMainFrame*)this-&gt;GetParent()-&gt;GetParent(); 
          
          CView4* View4=(CView4*)MainFrame-&gt;m_wndSplitter1.GetPane(2,0); 
          View4-&gt;DoIt(); </pre><br />到现在我们已经实现了CuteFTP的主窗口的框架并且能够实现他们之间相互通信的框架。 同样的我们可以实现其他的一些流行界面例如NetAnts，Foxmail的分割。 <br /><br /><b>三、关于对话框的分割</b><br />到目前为止，只有基于文档/视图的程序才能使用CSplitterWnd，而基于对话框的应用程序却不支持CSplitterWnd,但是如果我们在继承类中重载一些虚拟方法，也能使CSplitterWnd 在对话框程序中使用。从MFC的源程序WinSplit.cpp中可以看出，为了获得父窗口的地方程序都调用了虚拟方法GetParentFrame(),因此如果在对话框中使用，我们必须将它改为GetParent();因此我们将CSplitterWnd的下面几个方法重载。<br /><pre>virtual void StartTracking(int ht); 
virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol  = NULL); 
virtual void SetActivePane( int row, int col, CWnd* pWnd  = NULL ); 
virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam); 
virtual BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult ); 
virtual BOOL OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult ); </pre>具体实现如下，实现中我将给出原有代码的主要部分以及修改后的代码以作对比。<br />在cpp文件中加入下面的枚举类型。 <br /><pre>enum HitTestValue 
{ 
                  noHit = 0,//表示没有选中任何对象
                  vSplitterBox = 1,
                  hSplitterBox = 2,
                  bothSplitterBox = 3,
                  vSplitterBar1 = 101,//代表各个方向的水平分割条
                  vSplitterBar15 = 115,
                  hSplitterBar1 = 201,//代表垂直方向的各个分割条
                  hSplitterBar15 = 215,
                  splitterIntersection1 = 301,//代表各个交叉点
                  splitterIntersection225 = 525
};
          <br />
CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol)
          {
                  ASSERT_VALID(this); 
                  //获得当前的获得焦点的窗口
                  //下面注释粗体的是原有的代码的主要部分。
                  // CWnd* pView = NULL;
                  //CFrameWnd* pFrameWnd = GetParentFrame();
                  //ASSERT_VALID(pFrameWnd);
                  //pView = pFrameWnd-&gt;GetActiveView();
                  //if (pView == NULL)
                  // pView = GetFocus();
                  CWnd* pView = GetFocus();
                  if (pView != NULL &amp;&amp; !IsChildPane(pView, pRow, pCol))
                          pView = NULL;
                  return pView; 
} 
          
void CxSplitterWnd::SetActivePane( int row, int col, CWnd* pWnd) 
{
                  CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd; 
                  //下面加注释粗体的是原有代码的主要部分。
                  //FrameWnd* pFrameWnd = GetParentFrame();
                  //ASSERT_VALID(pFrameWnd); 
                  //pFrameWnd-&gt;SetActiveView((CView*)pPane); 
                  pPane-&gt;SetFocus();//修改后的语句 
}
          
void CxSplitterWnd::StartTracking(int ht)
{
                  ASSERT_VALID(this); 
                  if (ht == noHit) 
                          return;
                  // GetHitRect will restrict ''''m_rectLimit'''' as appropriate 
          
                  GetInsideRect(m_rectLimit);
                  if (ht &gt;= splitterIntersection1 &amp;&amp; ht &lt;= splitterIntersection225) 
          
                  { 
                          // split two directions (two tracking rectangles) 
          
                          int row = (ht - splitterIntersection1) / 15; 
          
                          int col = (ht - splitterIntersection1) % 15; 
          
                          GetHitRect(row + vSplitterBar1, m_rectTracker); 
          
                          int yTrackOffset = m_ptTrackOffset.y; 
                          m_bTracking2 = TRUE; 
                          GetHitRect(col + hSplitterBar1, m_rectTracker2); 
          
                          m_ptTrackOffset.y = yTrackOffset; 
                  } 
                  else if (ht == bothSplitterBox) 
                  { 
                  // hit on splitter boxes (for keyboard) 
                  GetHitRect(vSplitterBox, m_rectTracker); 
                  int yTrackOffset = m_ptTrackOffset.y; 
                  m_bTracking2 = TRUE; 
                  GetHitRect(hSplitterBox, m_rectTracker2); 
                  m_ptTrackOffset.y = yTrackOffset; // center it 
                  m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2); m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 
          0); 
                  } 
                  else
                  { 
                  // only hit one bar 
                  GetHitRect(ht, m_rectTracker); 
                  } 
          
          //下面加注释的将从程序中删去。 
          //CView* pView = (CView*)GetActivePane(); 
          //if (pView != NULL &amp;&amp; pView-&gt;IsKindOf(RUNTIME_CLASS(CView))) 
          //{ 
          // ASSERT_VALID(pView); 
          // CFrameWnd* pFrameWnd = GetParentFrame(); 
          //ASSERT_VALID(pFrameWnd); 
          //pView-&gt;OnActivateFrame(WA_INACTIVE, pFrameWnd); 
          // } 
          // steal focus and capture
                  SetCapture();
                  SetFocus();
                  // make sure no updates are pending 
                  RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); 
          
                  // set tracking state and appropriate cursor
                  m_bTracking = TRUE;
                  OnInvertTracker(m_rectTracker); 
                  if (m_bTracking2) 
                          OnInvertTracker(m_rectTracker2); 
                  m_htTrack = ht; 
                  SetSplitCursor(ht); 
}
          
BOOL CxSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam) 
{ 
                  if (CWnd::OnCommand(wParam, lParam)) 
                          return TRUE; 
                  //下面粗体的是原程序的语句 
          //<b>return GetParentFrame()-&gt;SendMessage(WM_COMMAND, wParam, lParam); 
          </b>
                  return GetParent()-&gt;SendMessage(WM_COMMAND, wParam, lParam); 
          
}
BOOL CxSplitterWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
{
                  if (CWnd::OnNotify(wParam, lParam, pResult)) 
                          return TRUE; 
                  //下面粗体的是源程序的语句
                  //<b>*pResult = GetParentFrame()-&gt;SendMessage(WM_NOTIFY, 
          wParam, lParam);</b>
                  *pResult = GetParent()-&gt;SendMessage(WM_NOTIFY, wParam, lParam);
                  return TRUE;
} 
          
BOOL CxSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult) 
{ 
                  // The code line below is necessary if using CxSplitterWnd 
          in a regular dll 
                  // AFX_MANAGE_STATE(AfxGetStaticModuleState());
                  return CWnd::OnWndMsg(message, wParam, lParam, pResult); 
          
} </pre>这样我们就可以在对话框中使用CxSplitterWnd类了。 <br /><br /><b>四、CSplitterWnd的扩展</b><br />CSplitterWnd扩展话题是很多的，我们可以通过对原有方法的覆盖或者增加新的方法来扩展CSplitterWnd。我们在此仅举两个方面的例子。 <br /><b>4.1锁定切分条</b><br />当用户创建好分割窗口后，有时并不希望通过拖动切分条来调节窗口的大小。这时就必须锁定切分条。锁定切分条的最简单的方法莫过于不让CSplitterWnd来处理WM_LBUTTONDOWN,WM_MOUSEMOVE,WM_SETCURSOR消息，而是将这些消息交给CWnd窗口进行处理，从而屏蔽掉这些消息。拿WM_LBUTTONDOWN处理过程来说。修改为如下： <br /><pre>void CXXSplitterWnd::OnLButtonDown(UINT nFlags,CPoint point) <br />{ 
        CWnd::OnLButtonDown(nFlags,point);
} </pre>其余的处理方法类似。 <br /><b>4.2切分条的定制</b><br />由Window自己生成的切分条总是固定的，没有任何的变化，我们在使用一些软件比如ACDSee的时候却能发现它们的切分条却是和自动生成的切分条不一样的。那么如何定制自己的切分条呢？通过重载CSplitterWnd的虚方法OnDrawSplitter和OnInvertTracker可以达到这样的目的。下面的代码生成的效果是分割窗口的边界颜色为红色，分割条的颜色为绿色.代码如下：<br /><pre>void CSplitterWndEx::OnDrawSplitter(CDC *pDC, ESplitType nType, const CRect &amp;rectArg)
{
                  if(pDC==NULL) 
                  { 
                  RedrawWindow(rectArg,NULL,RDW_INVALIDATE|RDW_NOCHILDREN);
                  return;
                  } 
                  ASSERT_VALID(pDC);
                  CRect rc=rectArg;
                  switch(nType) 
                  { 
                  case splitBorder:
                  //重画分割窗口边界,使之为红色 
                          pDC-&gt;Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0));
                          rc.InflateRect(-CX_BORDER,-CY_BORDER); 
                          pDC-&gt;Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); 
          
                          return; 
                  case splitBox:
                          pDC-&gt;Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                          rc.InflateRect(-CX_BORDER,-CY_BORDER); 
                          pDC-&gt;Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                          rc.InflateRect(-CX_BORDER,-CY_BORDER);
                          pDC-&gt;FillSolidRect(rc,RGB(0,0,0)); 
                          pDC-&gt;Draw3dRect(rc,RGB(0,0,0),RGB(0,0,0));
                          return; 
                  case splitBar: 
                  //重画分割条，使之为绿色 
                          pDC-&gt;FillSolidRect(rc,RGB(255,255,255));
                          rc.InflateRect(-5,-5); 
                          pDC-&gt;Draw3dRect(rc,RGB(255,0,0),RGB(255,0,0)); 
          
                          return; 
                  default: 
                          ASSERT(FALSE); 
                  } 
                  pDC-&gt;FillSolidRect(rc,RGB(0,0,255));
} 
void CSplitterWndEx::OnInvertTracker(CRect &amp;rect) 
{ 
                  ASSERT_VALID(this);
                  ASSERT(!rect.IsRectEmpty()); 
                  ASSERT((GetStyle()&amp;WS_CLIPCHILDREN)==0);
                  CRect rc=rect; 
                  rc.InflateRect(2,2);
                  CDC* pDC=GetDC(); 
                  CBrush* pBrush=CDC::GetHalftoneBrush();
                  HBRUSH hOldBrush=NULL;
                  if(pBrush!=NULL) hOldBrush=(HBRUSH)SelectObject(pDC-&gt;m_hDC,pBrush-&gt;m_hObject);
                  pDC-&gt;PatBlt(rc.left,rc.top,rc.Width(),rc.Height(),BLACKNESS); 
          
                  if(hOldBrush!=NULL) 
                  SelectObject(pDC-&gt;m_hDC,hOldBrush);
                  ReleaseDC(pDC); 
} </pre>同样我们只要继承CSplitterWnd中的其余的一些虚拟方法就可以生成具有自己个性的分割窗口了。<br /><br />我的电子信箱：tingya@njpost.com.cn 和tingya@263.net <br />地址：南京邮政局计算机中心 张中庆 <br />邮政编码：210008 </td>
																</tr>
														</tbody>
												</table>
										</div>
								</td>
						</tr>
				</tbody>
		</table>
<img src ="http://www.cppblog.com/microli/aggbug/11913.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-09-01 09:56 <a href="http://www.cppblog.com/microli/articles/11913.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC++实现混合静态分裂视窗的方法</title><link>http://www.cppblog.com/microli/articles/11911.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Fri, 01 Sep 2006 01:54:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/11911.html</guid><description><![CDATA[
		<p style="TEXT-INDENT: 2em">
				<b>摘要</b> 本文以MFC（Microsoft Foundation Class Library）的CsplitterWnd类别为基础，通过对单文档视窗的静态分裂原理进行分析，介绍混合静态分裂视窗的实现方法，并深入阐述子视窗的视图动态切换技术。</p>
		<p style="TEXT-INDENT: 2em">
				<b>关键词</b> 静态分裂视窗 动态切换视图 混合分裂视窗</p>
		<p style="TEXT-INDENT: 2em">
				<b>前言</b>
		</p>
		<p style="TEXT-INDENT: 2em">在许多视窗应用软件中，通常要在屏幕上同时显示若干个子视窗，以显示同一个文档的不同部分，或者是在每个视窗中分别显示不同文档的内容。为了实现多视窗界面，可以采用MDI(Multiple Document Interface)的多文档模式进行处理，但是多文档的应用程序设计与维护相对于单文档的应用程序而言比较复杂。而且，如果要在屏幕上同时显示多个子视窗，通常要利用视窗重叠函数进行管理，每个子视窗的位置往往需要用鼠标人为设定，过多的人为干预降低了程序使用的效率。因此，如果能对单文档视窗做适当的分裂，无疑程序使用者将可以得到更易于操作的接口，数据的显示也更加直观和方便。本文通过对单文档视窗的静态分裂原理进行分析，实现上述要求。 </p>
		<p style="TEXT-INDENT: 2em">
				<b>二分裂视窗的类型</b>
		</p>
		<p style="TEXT-INDENT: 2em">视窗的分裂可分为两种类型，一是动态分裂，二是静态分裂。动态分裂可以让使用者通过拖曳分裂方块的使用，将视窗分裂。但是，动态分裂最多只可以将视窗分裂为2×2个子视窗，不能进行混合分裂视窗，所有子视窗的属性和父视窗都是一样的，而且子视窗的数据通常来源于同一处。而静态分裂，使用者除了可以调整子视窗的大小和进行混合分裂视窗外，最多可将视窗分裂为16×16个子视窗，每个子视窗可以有各自不同的视图类(CView)，各个子视窗显示的数据可以来自于不同的数据源。不论是要创建动态分裂视窗还是静态分裂视窗，都必须要利用MFC的CSplitterWnd类别来完成视窗的分裂。</p>
		<p style="TEXT-INDENT: 2em">
				<b>混合静态分裂视窗的实现</b>
		</p>
		<p style="TEXT-INDENT: 2em">
		</p>
		<p style="TEXT-INDENT: 2em">混合分裂视窗是指在子视窗中进行视窗的再分裂。在MFC的框架下，混合分裂视窗必须完成三件工作：</p>
		<p style="TEXT-INDENT: 2em">⑴在视窗框架类别中定义CSplitterWnd控件为其属性（数据成员）。</p>
		<p style="TEXT-INDENT: 2em">⑵重载视窗框架类别中的OnCreateClient函数（CFrameWnd::OnCreateClient），建立静态分裂子视窗，为静态分裂子视窗填充视图。</p>
		<p style="TEXT-INDENT: 2em">⑶建立维持各子视窗同步更新的机制。</p>
		<p style="TEXT-INDENT: 2em">首先，利用MFC AppWizard生成一个单文档应用程序，在应用程序的CMainFrame类别中声明CSplitterWnd类别的数据成员。</p>
		<p style="TEXT-INDENT: 2em">其次，重载CMainFrame类别中的OnCreateClient(LPCREATESTRUCT,CCreateContext* pContext)函数。在该函数中利用CsplitterWnd类别的构造函数Create Static(CWnd *pParentWnd,int nRows,int nCols,DWORD dwstyle,UINT nID) 创建混合静态分裂子视窗，即在Create Static分裂出的子视窗中利用CsplitterWnd类别的控件再一次分裂视窗。</p>
		<p style="TEXT-INDENT: 2em">Create Static函数的参数含义为：</p>
		<p style="TEXT-INDENT: 2em">·pParentWnd是准备建立静态分裂视窗的视窗框架控件的指针；</p>
		<p style="TEXT-INDENT: 2em">·nRows和nCols是准备建立静态分裂视窗行数（nRows）与列数（nCols）</p>
		<p style="TEXT-INDENT: 2em">因此，创建的静态分裂子视窗个数为nRows × nCols个，这两个参数最小不得小于0，最大不可超过16；dwstyle是设定子视窗的形式；nID静态分裂的代号（ID），此代号预设为AFX_IDW_PANE_FIRST，若静态分裂视窗位于另一个分裂视窗内时，不可以使用默认值，可以利用CsplitterWnd类别的成员函数IdFromRowCol(int row,int col)获得。利用CsplitterWnd类别的成员函数Create View (int row,int col,CruntimeClass* pViewClass,SIZE sizeinit,CcreateContext* pContext) 为静态分裂子视窗填充视图，在将视图与子视窗关联时必须先完成子视窗的创建。</p>
		<p style="TEXT-INDENT: 2em">Create View函数的参数含义为： </p>
		<p style="TEXT-INDENT: 2em">·row和col是指定准备建立View控件的子视窗，其指定的方式是以表示该子视窗所在的行列位置；</p>
		<p style="TEXT-INDENT: 2em">·pViewClass是指定用于建立子视窗View控件的View类别，该类别需要被声明为Run-Time类别；</p>
		<p style="TEXT-INDENT: 2em">·Sizeini是View控件的起始大小；pContext是一个指向记录应用程序所使用的视窗框架控件、Document控件，以及View控件之变量的指针，此参数在CMainFrame::OnCreateClient函数被调用时传入，再由该函数传递给此函数。</p>
		<p style="TEXT-INDENT: 2em">·CsplitterWnd类别的成员函数SetColumnInfo(int col,int cxIdeal,int cxMin)和SetRowInfo(int row,int cyIdeal,cyMin)为设置子视窗的宽度和高度，参数cxIdeal和cxMin是指定子视窗的宽度和最小宽度，cyIdeal和cyMin是指定子视窗的高度和最小高度，在使用这两个函数调整子视窗的大小后还应该使用该类别的成员函数RecalLayout()重新调整视窗框架的布局。如果要设定视窗框架里的活动子视窗，可以通过CsplitterWnd类别的成员函数SetActivePane(int row,int col,CWnd* pWnd=NULL)来完成，该函数指定子视窗的方式有两种，一是指出子视窗所在的行列，二是传入指向该子视窗的控件指针。</p>
		<p style="TEXT-INDENT: 2em">最后，将视窗分裂成多个子视窗后，整个视窗程序中将存在多个View控件。当在其中一个View控件执行更新操作时，如何让其它View控件同步更新数据？可以通过文档类别（CDocument）的UpdateAllViews(CView* pSender,LPARAM lHint,CObject* pHint)成员函数的调用，再由该函数分别调用目前存在于视窗程序中各View控件的On Update函数来完成数据的同步更新。</p>
		<p style="TEXT-INDENT: 2em">UpdateAllViews函数的参数含义为：</p>
		<p style="TEXT-INDENT: 2em">·pSender是指向引发更新操作的View控件指针，如果传入NULL表示所有视图都要执行更新操作；</p>
		<p style="TEXT-INDENT: 2em">·lHint是用于传送更新视图时，需要传送的额外信息参数；</p>
		<p style="TEXT-INDENT: 2em">·pHint是指向记录更新视图所需额外信息的控件。在调用该函数时，将View控件的指针传入的目的是要告诉该函数该子视图已经完成数据更新，该函数不需要再调用该子视图的On Update进行数据更新。</p>
		<p style="TEXT-INDENT: 2em">
				<b>子视图的动态切换</b>
		</p>
		<p style="TEXT-INDENT: 2em">在多视图应用程序中，可以通过改变CCreateContext对象的值，来创建更加灵活的视图，实现多视图的动态切换。CCreateContext是MFC框架所使用的一种数据结构，它将构成文档/视图结构的组件联系起来。这个结构包括指向文档的指针、视窗框架的指针、视图的指针以及文档模板的指针，它还包含一个指向CRuntimeClass结构的指针，以指明所创建的视图的类型。</p>
		<p style="TEXT-INDENT: 2em">其数据成员如下：</p>
		<p style="TEXT-INDENT: 2em">·m_pNewViewClass是指向创建上下文的视图的CRuntimeClass结构的指针； </p>
		<p style="TEXT-INDENT: 2em">·m_pNewDocTemplate是指向与视窗框架的创建相联系的文档模板的指针；</p>
		<p style="TEXT-INDENT: 2em">·m_pCurrentDoc是指向文档对象的指针，以和新视图联系起来；</p>
		<p style="TEXT-INDENT: 2em">·m_pLastView是指向已存在的视图的指针，它是新产生的视图的模型；</p>
		<p style="TEXT-INDENT: 2em">·m_pCurrentFrame是指向已存在的视窗框架的指针，它是新产生的视窗框架的模型。</p>
		<p style="TEXT-INDENT: 2em">此外，任何一个从CObject类别继承而来的子类别，在使用宏DECLARE_DYNAMIC、DECLARE_DYNCREATE、DECLARE_SERIAL三个中的任意一个时都会产生一个CRuntimeClass结构的静态对象，RUNTIME_CLASS返回的就是这个对象的指针，这个对象包含了其基类和本身在运行时刻的信息。</p>
		<p style="TEXT-INDENT: 2em">在单文档静态分裂视窗的应用程序中，利用CsplitterWnd类别的成员函数Delete View(int row,int col)可以删除子视窗的原有视图，然后再通过该类别的成员函数Create View为子视窗创建新的视图。但是，创建新视图前必须初始化创建上下文相关指针，即对CCreateContext结构赋值。值得注意的是，使用Create View函数创建的新视图不能自动调用视图类别的成员函数OnInitialUpdate和自动显示并且激活新视图，需要人工调用OnInitialUpdate函数和ShowWindow(SW_SHOW) 函数，这些函数的调用都可以通过CsplitterWnd类别的成员函数Get Pane(int row,int col)获得新视图的指针来完成。</p>
		<p style="TEXT-INDENT: 2em">
				<b>结束语</b>
		</p>
		<p style="TEXT-INDENT: 2em">在MFC的框架下，混合分裂视窗有多种编程方法，本文只是从CsplitterWnd类别的角度去分析混合静态分裂视窗的实现方法，希望能给读者起到抛砖引玉的作用。 </p>
		<p style="TEXT-INDENT: 2em"> </p>
<img src ="http://www.cppblog.com/microli/aggbug/11911.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-09-01 09:54 <a href="http://www.cppblog.com/microli/articles/11911.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title> VC中使用ListCtrl经验总结(1)</title><link>http://www.cppblog.com/microli/articles/11499.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Sun, 20 Aug 2006 11:28:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/11499.html</guid><description><![CDATA[ListCtrl在工作中，常常用到，也常常看到大家发帖问怎么用这个控件， 
<p>故总结了一下自己的使用经验，以供参考使用。</p><p>　　先注明一下，这里，我们用m_listctrl来表示一个CListCtrl的类对象，</p><p>然后这里我们的ListCtrl都是report形式，至于其他的如什么大图标，小图标</p><p>的暂时不讲，毕竟report是大众话的使用。其次，我们这里用条款一，条款二</p><p>来描述第一点，第二点，这个是参照《Effective C++》的叫法，俺觉得这么</p><p>叫比较COOL :)</p><p>　条款一：设置ListCtrl的风格</p><p>　在CSDN上常常看到有人问怎么设置风格的，他们ListCtrl的样子是一个列表</p><p>，有横条和竖条分界线，然后选中一行，要整一行都选中，而不是只有某一列</p><p>被选中，等等，这里给一个比较全面的设置方法。</p><p>//获得原有风格<br /> DWORD dwStyle = ::GetWindowLong(m_listctrl.m_hWnd, GWL_STYLE); <br /> dwStyle &amp;= ~(LVS_TYPEMASK);<br /> dwStyle &amp;= ~(LVS_EDITLABELS);</p><p> //设置新风格<br />    SetWindowLong(m_listctrl.m_hWnd, GWL_STYLE, </p><p>dwStyle,|LVS_REPORT|LVS_NOLABELWRAP|LVS_SHOWSELALWAYS);</p><p><br /> //设置扩展风格<br /> DWORD styles = </p><p>LVS_EX_FULLROWSELECT|LVS_EX_GRIDLINES|LVS_EX_CHECKBOXES;</p><p> ListView_SetExtendedListViewStyleEx(m_listctrl.m_hWnd, styles, </p><p>styles );</p><p>其中LVS_EX_FULLROWSELECT　就是前面说得整行选中</p><p>LVS_EX_GRIDLINES　网格线（只适用与report风格的listctrl）</p><p>LVS_EX_CHECKBOXES　前面加个checkbox</p><p>pListCtrl-&gt;SetExtendedStyle(  m_listctrl.GetExtendedStyle()</p><p>|LVS_EX_SUBITEMIMAGES);</p><p><br />这也是一个很重要的属性，这样的话，可以在列表中加ICON，记得windows的</p><p>任务管理器吗，你想做得那样，这个属性也要加哦，这个我以后会讲的～</p><p>条款二：加入列头</p><p>　　这是一个比较实质的东西，给列表框分列，然后加上列头</p><p>　　代码说话，来了</p><p>　　TCHAR rgtsz[2][10] = {_T("列头1"), _T("列头2")};<br /> <br /> LV_COLUMN lvcolumn;<br /> CRect rect;<br /> m_listctrl.GetWindowRect(&amp;rect);<br /> for(int i=0;i&lt;2;i++)<br /> {<br />  　lvcolumn.mask = LVCF_FMT | LVCF_SUBITEM | LVCF_TEXT <br />     　　　　　　　　 | LVCF_WIDTH | LVCF_ORDER;<br />  　lvcolumn.fmt = LVCFMT_LEFT;<br />  　lvcolumn.pszText = rgtsz[i];<br /> 　 lvcolumn.iSubItem = i;<br />  　lvcolumn.iOrder = i;<br /> 　 if(i==0)<br />  　{<br />   　　　lvcolumn.cx = rect.Width()*3/5 ; <br /> 　 }<br /> 　 else<br />   　　lvcolumn.cx = rect.Width()*2/5;<br />  　　　　</p><p>　　　m_listctrl.InsertColumn(i, &amp;lvcolumn);<br /> 　}</p><p>这是插入两列的做法，你要插入20列？？随便你，依样画葫芦～～</p><p>　lvcolumn.mask 中那个mask可以有各种属性，具体去看msdn吧，</p><p> </p><p>条款三：把记录，插入列表框中</p><p>　int nIndex = m_listctrl.GetItemCount();</p><p>  LV_ITEM   lvitemAdd = {0};<br />  lvitemAdd.mask = LVIF_TEXT;<br />  lvitemAdd.iItem = nIndex ;<br />  lvitemAdd.iSubItem = 0;<br />  lvitemAdd.pszText =_T("毛毛1");;</p><p><br />  if (m_listctrl.InsertItem(&amp;lvitemAdd) != -1)<br />  { <br />   LV_ITEM lvitem = {0};<br />   lvitem.mask = LVIF_TEXT;<br />   lvitem.iItem = nIndex ;<br />   lvitem.iSubItem = 1;<br /> <br />   lvitem.pszText =_T("毛毛2");<br />   m_listctrl.SetItem(&amp;lvitem);<br />   <br />  }</p><p>nIndex 是当前的行数，然后把新的一行，插在最下面，</p><p> </p><p>条款四：给列表中插入图标</p><p>　在report格式中，也能插入图标</p><p>　继续代码说话</p><p>　m_image是个CImageList对象</p><p>　m_image.Create(16,16, TRUE|ILC_COLOR24, 3, 1);</p><p> m_listctrl.SetImageList(&amp;m_image,LVSIL_SMALL);</p><p>然后调用CImageList的成员函数int CImageList::Add( HICON hIcon );</p><p>把ICON插入到imagelist，</p><p>　然后在插入记录的时候</p><p>　lvitemAdd.mask = LVIF_TEXT;　－》　lvitemAdd.mask = </p><p>LVIF_TEXT|LVIF_IMAGE</p><p>　然后添加一个lvitemAdd.iImage = n;</p><p>　这个n是imagelist中的序号，表示是具体的哪一个图标，list么，呵呵</p><p> </p><p>条款五：　插入记录时使用额外的信息，lParam 的使用</p><p>　　　有时候，你想对于某一行，加入一些额外的信息，那么就可以使用这个</p><p>lParam </p><p>　　ｍｓｄｎ是这么描述的Specifies the 32-bit value of the item</p><p>　　我上次是为了在某一行加入一个信息，窗口句柄，然后是这么加的，</p><p>　　int nIndex = m_listctrl.GetItemCount();</p><p>  LV_ITEM   lvitemAdd = {0};<br />  lvitemAdd.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;<br />  lvitemAdd.iItem = nIndex ;<br />  lvitemAdd.iSubItem = 0;<br />  lvitemAdd.pszText =_T("毛毛1");;</p><p>  lvitemAdd.iImage = n;<br />  lvitemAdd.lParam = (LPARAM)hwnd;(某个窗口的窗口句柄)</p><p><br />  if (m_listctrl.InsertItem(&amp;lvitemAdd) != -1)<br />  { <br />   LV_ITEM lvitem = {0};<br />   lvitem.mask = LVIF_TEXT;<br />   lvitem.iItem = nIndex ;<br />   lvitem.iSubItem = 1;<br /> <br />   lvitem.pszText =_T("毛毛2");<br />   m_listctrl.SetItem(&amp;lvitem);<br />   <br />  }</p><p>ok，这是一个比较全的例子的，又插ICON，又使用PARAM的</p><p>条款六　：　点击列表框，获取选中行信息</p><p>　　响应NM_CLICK消息，如果你有MSDN，可以看到，有专门关于listview的</p><p>NM_CLICK的介绍</p><p>void CMyDlg::OnItemClick(NMHDR* pNMHDR, LRESULT* pResult) <br />{<br /> // TODO: Add your control notification handler code here<br /> int nItem = -1;<br /> <br /> LPNMITEMACTIVATE lpNMItemActivate = (LPNMITEMACTIVATE)pNMHDR;</p><p> if(lpNMItemActivate != NULL)<br /> {<br />     nItem = lpNMItemActivate-&gt;iItem;<br /> }</p><p>} </p><p>现在nItem就是点击选中那行的index了，有了index，获取那行的信息还难吗</p><p>？</p><p>懒汉说：难，因为你还没讲，晕，那就继续说</p><p> </p><p>条款七：　根据行的index，获取该行的信息</p><p>　直接上代码吧</p><p>　LV_ITEM lvitem = {0};<br />   lvitem.iItem = nIndex;<br />   lvitem.iSubItem = 0;<br />   lvitem.mask = LVIF_TEXT|LVIF_IMAGE|LVIF_PARAM;</p><p>m_listctrl.GetItem(&amp;lvitem)</p><p>这样，就把nindex,第一列的信息取出来了，包括刚才我们加入的ICON,和那个</p><p>额外信息（窗口句柄），</p><p>比如我要获取窗口句柄，就可以hwnd = (HWND)lvitem.lParam; </p><p>mask 用来指明你想获取那些信息</p><p>具体可以查msdn中LVITEM Structure的定义和CListCtrl::GetItem</p><p> </p><p>条款八：用程序选中某一行，使之选中</p><p>选中之　</p><p>m_listctrl.SetItemState</p><p>(nIndex,LVIS_SELECTED|LVIS_FOCUSED,LVIS_SELECTED|LVIS_FOCUSED);</p><p>不选中，取消选中之</p><p>m_listctrl.SetItemState(nIndex,0,LVIS_SELECTED|LVIS_FOCUSED);</p><p> </p><p>条款九：获取当前所有选中的行（多选）</p><p>　　这个，俺就比较懒了，抄msdn的代码吧，反正很简单</p><p>　　</p><p>Example<br />// CListCtrl* pListCtrl = (CListCtrl*) GetDlgItem</p><p>(IDC_YOURLISTCONTROL);<br />ASSERT(pListCtrl != NULL);</p><p>POSITION pos = pList-&gt;GetFirstSelectedItemPosition();<br />if (pos == NULL)<br />   TRACE0("No items were selected!\n");<br />else<br />{<br />  while (pos)<br />  {<br />     int nItem = pList-&gt;GetNextSelectedItem(pos);<br />     TRACE1("Item %d was selected!\n", nItem);<br />     // you could do your own processing on nItem here<br />  }<br />}</p><p> </p><p>条款十：删除条款九中选中的行</p><p>　　这个相对前面九个条款是比较麻烦的，因为如果你要删除多行的话。往往要出错</p><p>　　比如，我现在要删除第0行和第1行（列表的行序列是从0开始的）</p><p>　　那么好啊。我来删了</p><p>　　m_listctrl.DeleteItem(0)</p><p>        m_listctrl.DeleteItem(1)</p><p>　　恭喜你，错了，我好开心啊　：）</p><p>　　因为你删除第0行以后，下面的行会往上移，那么原来的第1行就变成了第0行，那么你再 m_listctrl.DeleteItem(1)，那么删除的是原来的第２行，真麻烦，</p><p>　　　所以，只有从下往上删，才是安全的，先删的，不会影响后面的操作，</p><p>　　　　m_listctrl.DeleteItem(1)</p><p>        m_listctrl.DeleteItem(0)</p><p>　　但有时候，我们也不知道要删除哪些行，只知道要删除选中的那些行，像条款九中的那些</p><p>　　　如果我们还是用</p><p>　　　</p><p>POSITION pos = m_listctrl.GetFirstSelectedItemPosition();<br />if (pos == NULL)<br />   TRACE0("No items were selected!\n");<br />else<br />{<br />  while (pos)<br />  {<br />     int nItem = m_listctrl.GetNextSelectedItem(pos);<br />    </p><p>　m_listctrl.DeleteItem(nItem );</p><p>  }<br />}</p><p>你就等着收尸吧</p><p>这时候我们就要B4微软了，为虾米木有GetLastselectedItemPosition 和GetPrevSelectedItem</p><p>多写一对成员函数会死啊　:(</p><p>　没办法，办法自己想，这里有个笨办法</p><p>　POSITION  sSelPos = NULL;</p><p> while(sSelPos = m_listctrl.GetFirstSelectedItemPosition())<br /> {<br />        int nSelItem = -1;<br />         nSelItem = m_listctrl.GetNextSelectedItem(sSelPos);</p><p>         if(nSelItem &gt;= 0 &amp;&amp; nSelItem&lt;m_listctrl.GetItemCount())<br />       {</p><p>             好了，这个nSelItem 就是我们要的DD</p><p>      }</p><p>}</p><p>GetNextSelectedItem这个函数，看msdn的用法，其实是返回第一个的index，然后走到下一个选中的行去，所以这么做也是安全的，在实际中，俺也是这么做的，测试也通过，没问题的</p><p>当然，还有个办法，先通过GetFirstSelectedItemPosition和GetNextSelectedItem</p><p>来获取所有的选中行的index，然后把这些index放到一个数组里，然后再从下往上删</p><p>唉真麻烦啊，还要不定数组，不说用new在堆上开吧，那么一个vector总是要的吧，麻烦啊</p><p>所以我暂时是用上述的办法来删除，也供大家参考，希望能找到更好的办法。</p><p> </p><p>好了，今天就暂时先整理上述十点。listctrl其他高级的用法，网上资料也很多，我也暂时不总结，以后有机会再说吧。</p><p>搞了好长时间啊，要睡觉去了，累死了　：）</p><br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=662462</p><div class="postFoot"><script src="http://localhost:82/PromoteIcon.aspx?id=662462"></script>
[<a href="javascript:StorePage()">点击此处收藏本文</a>]   毛毛发表于 2006年04月13日 23:32:00 </div><link href="http://blog.csdn.net/handsomerun/Services/Pingback.aspx" rel="pingback" /><!--
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/">
<rdf:Description
rdf:about="http://blog.csdn.net/handsomerun/archive/2006/04/13/662462.aspx"
dc:identifier="http://blog.csdn.net/handsomerun/archive/2006/04/13/662462.aspx"
dc:title="VC中使用ListCtrl经验总结(1)"
trackback:ping="http://tb.blog.csdn.net/TrackBack.aspx?PostId=662462" />
</rdf:RDF>
--><script><![CDATA[unction hide(){showComment();}]]&gt;</script><br /><div id="tagad"><script language="javascript"><![CDATA[
ad_width=468;
ad_height=60;
adcss=2;
unionuser=13;
]]&gt;</script><script language="javascript" src="http://tagegg.csdn.net/showads.js" type="text/javascript"></script><script language="JavaScript1.1" src="http://tagegg.csdn.net/a.aspx?action=displayad&amp;unionuser=13&amp;unionurl=http://blog.csdn.net/handsomerun/archive/2006/04/13/662462.aspx&amp;adcss=2&amp;ad_type=c&amp;width=468&amp;height=60&amp;ad_color=&amp;ad_color_border="></script><link href="http://tagegg.csdn.net/css/css2.css" type="text/css" rel="stylesheet" /><table height="60" cellspacing="1" cellpadding="0" width="468" border="0"><tbody><tr><td><table height="58" cellspacing="0" cellpadding="2" width="466" border="0"><tbody><tr><td class="tagad_td" valign="top" align="left" width="33%"><a class="tagad_a" href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fwww.uplooking.com%2fcontent%2fview%2f530%2f2%2f&amp;adid=109&amp;tag=" target="_blank">Linux百人免费培训,火热报名!</a><br /><a href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fwww.uplooking.com%2fcontent%2fview%2f530%2f2%2f&amp;adid=109&amp;tag=" target="_blank">高薪没有捷径——唯有专业享受高薪 签北京就业合同</a><br /><a class="tagad_a" href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fwww.uplooking.com%2fcontent%2fview%2f530%2f2%2f&amp;adid=109&amp;tag=" target="_blank">http://www.uplooking...</a></td><td class="tagad_td" valign="top" align="left" width="33%"><a class="tagad_a" href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fprj.csdn.net&amp;adid=194&amp;tag=" target="_blank">CSDN项目外包平台</a><br /><a href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fprj.csdn.net&amp;adid=194&amp;tag=" target="_blank">软件项目外包,软件交易,发项目接项目一切轻松搞定</a><br /><a class="tagad_a" href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fprj.csdn.net&amp;adid=194&amp;tag=" target="_blank">http://prj.csdn.net</a></td><td class="tagad_td" valign="top" align="left" width="33%"><a class="tagad_a" href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fjob.csdn.net%2fJobs%2fViewJob%2fC_ASP.net_82334d9b856149c49e11ccf1c034ca92.aspx&amp;adid=198&amp;tag=" target="_blank">CSDN邀您共同发展</a><br /><a href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fjob.csdn.net%2fJobs%2fViewJob%2fC_ASP.net_82334d9b856149c49e11ccf1c034ca92.aspx&amp;adid=198&amp;tag=" target="_blank">好工作好前途尽在CSDN,快来试试吧</a><br /><a class="tagad_a" href="http://tagegg.csdn.net/a.aspx?action=click&amp;unionuser=13&amp;adurl=http%3a%2f%2fjob.csdn.net%2fJobs%2fViewJob%2fC_ASP.net_82334d9b856149c49e11ccf1c034ca92.aspx&amp;adid=198&amp;tag=" target="_blank">http://job.csdn.net/...</a></td></tr></tbody></table></td></tr></tbody></table></div><script type="text/javascript"><![CDATA[ocument.write("<img src=http://counter.csdn.net/pv.aspx?id=24 border=0 width=0 height=0>");]]&gt;</script><img height="0" src="http://counter.csdn.net/pv.aspx?id=24" width="0" border="0" /><a name="664089"> </a><div class="post"><div class="postTitle"><a href="http://blog.sina.com.cn/u/1162579663" target="_blank" rel="nofollow">PPG</a> 发表于2006-04-14 22:50:00  IP: 222.94.6.*</div><div class="postText">好文章，收藏一下</div></div><br /><a name="816440"> </a><div class="post"><div class="postTitle">yyh9186 发表于2006-06-20 17:11:00  IP: 221.122.51.*</div><div class="postText">您好，我最近遇到个难缠的问题，看了您的文章后，我想您在listctrl方面一定了解很透彻，希望您能帮我解决这个问题。描述如下：listctrl的托选功能，类似于windows托选功能。我分析分为两种情况：(1)按住鼠标左键进行托选；(2)按住鼠标左键，并按下ctrl键进行托选。 <br />这个问题我自己实在是搞不定了，希望高手您给出代码，我的邮箱: <br />yyh9186@163.com；msn:yyh9186@hotmail.com</div></div><br /><a name="817918"> </a><div class="post"><div class="postTitle">毛毛 发表于2006-06-21 10:38:00  IP: 218.4.149.*</div><div class="postText">托选是什么，多选吗？？晕 <br /><br />现在的listctrl，如果选择那个多选的属性（控件属性里有），那么就是；(2)按住鼠标左键，并按下ctrl键进行多选。 <br /><br />如果你想只是左键多选，那么 <br />自己模拟的,首先判断鼠标左键单击在了listCtrl里面,然后就截获这个消息,修改消息参数 <br />WM_LBUTTONDOWN <br /><br />WPARAM wParam <br />LPARAM lParam; <br />wParam <br />MK_CONTROL <br />The CTRL key is down. <br />wParam=MK_CONTROL <br />然后继续传递这个消息就得了 <br /><br />俺没试过，8知道行不行</div></div><img src ="http://www.cppblog.com/microli/aggbug/11499.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-08-20 19:28 <a href="http://www.cppblog.com/microli/articles/11499.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CRichEditCtrl 超文本编辑</title><link>http://www.cppblog.com/microli/articles/11482.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Sun, 20 Aug 2006 03:20:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/11482.html</guid><description><![CDATA[
		<p align="center">
				<span style="FONT-WEIGHT: bold; FONT-SIZE: 18px; FONT-FAMILY: Verdana" align="center">CRichEditCtrl 超文本编辑（MSN/QQ常用控件）</span>
		</p>
		<p align="center">owg 转自－vcmute （2005-9-9 13:48:00）<br /><br />//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////</p>
		<p>
				<font color="#008000">
						<b>一.常见问题<br /></b>
						<br />a.可以编译,不能执行的</font>
				<br />AfxInitRichEdit();<br /><br /><font color="#008000">b.升级默认的Riched版本(默认的有一些bug)</font>，如可在InitInstance中添加LoadLibrary("RICHED20.DLL") 最后注意 FreeLibrary<br /><br />如果是CRichEditView基类的可用<br />BOOL CXXXXXXView::PreCreateWindow(CREATESTRUCT&amp; cs)<br />{<br />    //装入rich edit version 2.0<br />    if (LoadLibraryA("RICHED20.DLL") == NULL)<br />     { <br />        AfxMessageBox(_T("Fail to load \"riched20.dll\"."),MB_OK | MB_ICONERROR);<br />        PostMessage(WM_QUIT,0,0);<br />        return FALSE;<br />       }<br /><br />       m_strClass = RICHEDIT_CLASSA;//for 2.0 class<br /><br />       return CRichEditView::PreCreateWindow(cs);<br />}<br /><br /><font color="#008000">c.最后追加行</font><br />richeditctrl.SetSel(-1, -1);<br />richeditctrl.ReplaceSel( (LPCTSTR)str );<br /><br /><font color="#008000">d.字数限制</font><br />CRichEditCtrl::LimitText(long nChars)<br /><br /><font color="#008000">e.换行切换<br /></font><br />CRichEditView的OnInitialUpdate()函数中加入下面两句：<br />m_nWordWrap = WrapNone;<br />WrapChanged(); <br />WrapChanged实际上也是调用<br />ctrl.SetTargetDevice(NULL, 1); <font color="#008000">//m_nWordWrap == WrapNone</font><br />ctrl.SetTargetDevice(NULL, 0);<font color="#008000"> //m_nWordWrap == WrapToWindow</font><br />还有不常用的 m_nWordWrap == WrapToTargetDevice<br />ctrl.SetTargetDevice(m_dcTarget, GetPrintWidth());<br />如果是在Dialog中，可使用SetTargetDevice，注意在属性里面加上want return<br /><br /><font color="#008000">f.有时候不希望带格式的数据粘贴，可通过PasteSpecial选择性粘贴</font><br />pmyRichEditCtrl-&gt;PasteSpecial(CF_TEXT);<br /><br /><font color="#008000">g.随着输入随着自动滚动条滚动到最后一行</font><br />int nFirstVisible = pmyRichEditCtrl-&gt;GetFirstVisibleLine();<br />if (nFirstVisible &gt; 0)<br />{<br />    pmyRichEditCtrl-&gt;LineScroll(-nFirstVisible, 0);<br />}<br />或<br />m_cRichEdit.PostMessage(WM_VSCROLL, SB_BOTTOM,0);<br /><br /><br /><font color="#008000">h.设置UNDO的次数(只能用在RICHED20以上，即默认不支持，必须升级)</font><br />SendMessage(EM_SETTEXTMODE,TM_MULTILEVELUNDO,0);<br />TM_MULTILEVELUNDO 支持多取消(默认值).可通过EM_SETUNDOLIMIT设置最大次数 <br />SendMessage(EM_SETUNDOLIMIT,100,0);<br /><br /><font color="#008000">i.响应OnChange</font><br />EM_SETEVENTMASK 设置 ENM_CHANGE <br />long lMask = GetEventMask();<br />lMask |= ENM_CHANGE;<br />lMask &amp;= ~ENM_PROTECTED;<br />SetEventMask(lMask);<br /><br /><font color="#008000">j.设置只读</font><br />CRichEditCtrl::SetReadOnly( BOOL bReadOnly = TRUE );<br />通过设置PROTECTED实现选中的文本只读，参见<br />http://www.codeguru.com/Cpp/controls/richedit/article.php/c2401/<br /><br /><b><font color="#008000">二.函数应用<br /></font></b><br /><font color="#008000">a.设置字体（主要是通过SetSelectionCharFormat）<br /></font><br />CHARFORMAT cf;<br /><br />rich.GetSelectionCharFormat(cf);<br /><br />cf.dwMask|=CFM_BOLD;<br /><br />cf.dwEffects|=CFE_BOLD;<font color="#008000">//设置粗体，取消用cf.dwEffects&amp;=~CFE_BOLD;</font><br /><br />cf.dwMask|=CFM_ITALIC;<br /><br />cf.dwEffects|=CFE_ITALIC;<font color="#008000">//设置斜体，取消用cf.dwEffects&amp;=~CFE_ITALIC;</font><br /><br />cf.dwMask|=CFM_UNDERLINE;<br /><br />cf.dwEffects|=CFE_UNDERLINE;<font color="#008000">//设置斜体，取消用cf.dwEffects&amp;=~CFE_UNDERLINE;<br /></font><br />cf.dwMask|=CFM_COLOR;<br /><br />cf.crTextColor = RGB(255,0,0);<font color="#008000">//设置颜色<br /></font><br />cf.dwMask|=CFM_SIZE;<br /><br />cf.yHeight =200;<font color="#008000">//设置高度<br /></font><br />cf.dwMask|=CFM_FACE;<br /><br />strcpy(cf.szFaceName ,_T("隶书"));<font color="#008000">//设置字体</font><br /><br />rich.SetSelectionCharFormat(cf);<br /><br /><font color="#008000">b.设置字体的行间距<br /></font><br />要用richedit2.0以上试试<br /><br />PARAFORMAT2 pf;<br />pf.cbSize = sizeof(PARAFORMAT2);<br />pf.dwMask = PFM_NUMBERING | PFM_OFFSET;<br />pf.wNumbering = PFN_BULLET;//注意PFM_NUMBERING <br />pf.dxOffset = 10;<br />VERIFY(SetParaFormat(pf)); <br /><br />常用的dwMask有<br /><br />1 PFM_NUMBERING 成员 wNumbering 才起作用，项目符号，默认用PFN_BULLET<br />2 使用阿拉伯数字 (1, 2, 3, ...). <br />3 使用小写字母 (a, b, c, ...). <br />4 使用大写字母 (A, B, C, ...). <br />5 使用小写罗马数字 (i, ii, iii, ...). <br />6 使用大写罗马数字 (I, II, III, ...). <br />7 自定义，字符见成员 wNumberingStart. <br />PFM_OFFSET 成员 dxOffset 才起作用，缩进，单位twips<br />PFM_STARTINDENT 成员 dxStartIndent 才起作用，首行缩进<br />PFM_SPACEAFTER 成员 dySpaceAfter 才起作用，段间距<br />PFM_LINESPACING 成员 dyLineSpacing 才起作用，行间距<br /><font color="#008000"><br />c.设置CRichEditCtrl(2.0)背景透明 </font><br />long style = ::GetWindowLong(GetSafeHwnd(), GWL_EXSTYLE);<br />style &amp;= WS_EX_TRANSPARENT;<br />::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLE, style);<br />或 CreateEx，然后把WS_EX_TRANSPARENT样式加上<br /><br /><font color="#008000">e.得到内容有三种</font><br /><br />1)GetWindowText<br /><br />2)使用EM_GETTEXTEX<br /><br />GETTEXTEX gt;<br /><br />gt.cb = 200;<br /><br />gt.flags = GT_DEFAULT;<br /><br />gt.codepage = CP_ACP ;<br /><br />gt.lpDefaultChar = NULL; <br /><br />gt.lpUsedDefChar = NULL;<br /><br />SendMessage(EM_GETTEXTEX,(WPARAM)&amp;gt,(LPARAM)text);</p>
		<p>
				<br />3)StreamOut(主要用于RTF等格式输出)<br /><br />static DWORD CALLBACK <br />MyStreamOutCallback(DWORD dwCookie, LPBYTE pbBuff, LONG cb, LONG *pcb)<br />{<br />    CFile* pFile = (CFile*) dwCookie;<br /><br />    pFile-&gt;Write(pbBuff, cb);<br /><br />    *pcb = cb;<br /><br />    return 0;<br />}<br /><br /><br />CFile cFile(TEXT("myfile.rtf"), CFile::modeCreate|CFile::modeWrite);<br /><br />EDITSTREAM es;<br /><br />es.dwCookie = (DWORD) &amp;cFile;<font color="#008000">//设置用例参数,以便回调函数调用</font><br /><br />es.pfnCallback = MyStreamOutCallback; <br /><br />pmyRichEditCtrl-&gt;StreamOut(SF_RTF, es);<br /><br />读入可以此类推，SetWindowText,EM_SETTEXTEX,StreamIn<br /><font color="#008000"><br />f.查找字符串<br /></font><br />FINDTEXTEX ft;<br />ft.chrg.cpMin = 0;<br />ft.chrg.cpMax = -1;<br />ft.lpstrText = "|";<br />long lPos = FindText(0, &amp;ft);<br /><br />如果要继续查找，修改cpMin,如<br />int nCount = 0;<br />do<br />{<br />   long lPos = GetRichEditCtrl().FindText(0, &amp;ft);<br />   if( -1 == lPos) break;<br />   ft.chrg.cpMin = lPos + strlen(ft.lpstrText);<br />   ++nCount;<br />}while(TRUE);<br /><font color="#008000"><br />g.以Html格式保存<br /></font><br />目前做法可先转为RTF格式，再通过RTF-to-HTML Converter<br />http://www.codeguru.com/Cpp/controls/richedit/conversions/article.php/c5377/<br /><br /><font color="#008000">h.重载OnProtected函数得到对应的消息，如粘贴等</font><br />void CMYichEditorView::OnProtected(NMHDR* pNMHDR, LRESULT* pResult)<br />{<br />   ENPROTECTED* pEP = (ENPROTECTED*)pNMHDR;<br /><br />   switch (pEP-&gt;msg) {<br />   case WM_KEYDOWN://按键，判断pEP-&gt;wParam<br />   case WM_PASTE://粘贴<br />   case WM_CUT://剪切<br />   case EM_SETCHARFORMAT:<br />   default:<br />   break;<br />};<br /><br />*pResult = FALSE;<br />}<br /><br /><font color="#008000"><b>三.聊天常用 <br /></b></font><br /><font color="#008000">a.LINK 链接功能<br /></font><br />1. LoadLibrary(_T("Riched20.dll"));<br /><br />2. 创建RichEdit2.0控件<br /><br />CreateEx(0, _T("RichEdit20A"), NULL, WS_CHILD|WS_VISIBLE|WS_VSCROLL|WS_TABSTOP<br />|ES_READONLY|ES_WANTRETURN|ES_MULTILINE,<br />rect.left, rect.top, cx, cy,<br />pParentWnd-&gt;m_hWnd, (HMENU)nID, NULL);<br /><br />3. 设定选中的文字为链接显示<br />CHARFORMAT2 cf2;<br />ZeroMemory(&amp;cf2, sizeof(CHARFORMAT2));//<br />cf2.cbSize = sizeof(CHARFORMAT2);<br />cf2.dwMask = CFM_LINK;<br />cf2.dwEffects |= CFE_LINK;<br />m_cRichEdit.SendMessage(EM_SETCHARFORMAT, SCF_SELECTION, (LPARAM)&amp;cf2);<br /><br />4.支持链接的点击响应<br />m_cRichEdit.SetEventMask(ENM_LINK);<br /><br />5.响应链接的点击EN_LINK<br />BEGIN_MESSAGE_MAP(CMyRichEdit, CRichEditCtrl)<br />ON_NOTIFY_REFLECT(EN_LINK,OnURL)<br />END_MESSAGE_MAP()<br />......<br /><br />void CMyRichEdit::OnURLClick(NMHDR *pNmhdr, LRESULT *pResult)<br />{<br />    TCHAR LinkChar[512];<br />    ENLINK *pLink = (ENLINK *)pNmhdr;<br />    if (pLink-&gt;msg == WM_LBUTTONUP)<br />    {<br />        SetSel(penLink-&gt;chrg);<font color="#008000">//这是链接的文字范围</font><br />        long Res = GetSelText((char *)LinkChar);<font color="#008000">//这是链接文字</font><br />       <font color="#008000"> //后面是你的处理过程</font><br />        ......<br />     }<br />}<br /><br /><font color="#008000">b.插入位图</font><br />http://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/<br />http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/<br /><br />自定义在RichEdit中插入对象的图标<br />http://www.blogcn.com/user3/jiangsheng/blog/1319738.html<br />方法基本同Knowledge Base文章Q220844 HOWTO: Insert a Bitmap Into an RTF Document Using the RichEdit Control<br />只是在最后插入之前调用一下IOleCache::SetData,用一个HGLOBAL作为参数，HGLOBAL里面的数据是一个METAFILEPICT结构，包含自己提供的图片<br /><br />使用CRichEditView::InsertFileAsObject就可以插入图像。VC++带有一个例子WordPad。<br />另外可以参考“Insert any HBITMAP (Bitmap) in your RichEdit Control”(http://www.codeguru.com/richedit/richeditrc.html)。 <br /><font color="#008000"><br />c.显示GIF动画</font><br />常用的是通过qq的imageole.dll(也有用Gif89.dll的)<br />http://www.xiaozhou.net/cooldog/blogview.asp?logID=82<br />http://www.codeproject.com/richedit/AnimatedEmoticon.asp<br /><br />在richedit控件中插入动态GIF (Native C++版)<br />http://blog.joycode.com/jiangsheng/archive/2004/12/15/41209.aspx<br /><br />d.IRichEditOleCallback的使用<br />http://61.186.252.131/Expert/topic/905/905844.xml?temp=.8379022<br /><br />类似 MSN 信息发送框的制作(上)<br />http://www.vckbase.com/document/viewdoc/?id=1087<br />内容包含：实现右键菜单，图片插入，读取/写入RTF格式字符串<br /><br />自定义 CRichEditCtrl 控件<br />http://www.vckbase.com/document/viewdoc/?id=328<br />内容包含：鼠标右键消息，消息映射，字体变换<br /><br />PS.richedit控件升级到2.0后，先把字体设为楷体，输入汉字没有问题，但输入字母时，字母自动跳转为Arial字体，而1.0却没有这个文题，仍然是用楷体显示字母<br />是一个专门的设计 Dual-font, Smart font apply, 参见 http://61.186.252.131/Expert/topic/913/913807.xml?temp=.3753778 <br />----------------------<br />比我想象中还要花时间，所以最后潦草了点，见谅</p>
		<br />
<img src ="http://www.cppblog.com/microli/aggbug/11482.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-08-20 11:20 <a href="http://www.cppblog.com/microli/articles/11482.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>【原】CEdit &amp; CRichEdit 使用技巧</title><link>http://www.cppblog.com/microli/articles/11472.html</link><dc:creator>铁观音</dc:creator><author>铁观音</author><pubDate>Sat, 19 Aug 2006 16:34:00 GMT</pubDate><guid>http://www.cppblog.com/microli/articles/11472.html</guid><description><![CDATA[【原】CEdit &amp; CRichEdit 使用技巧<br />作者：lixiaosan<br />日期：04/07/2006<br /><br /><br />注：<br />        m_edit1代表ID为IDC_EDIT1的CEdit控件的control类型的变量<br />        m_richedit1代表ID为IDC_RICHEDIT1的CRichEditCtrl控件的control类型的变量<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">1.设置edit只读属性<br /><br /></span>    方法一：<br />                m_edit1.SetReadOnly(TRUE);<br />    方法二：<br />                ::SendMessage(m_edit1.m_hWnd, EM_SETREADONLY, TRUE, 0);<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">2.判断edit中光标状态并得到选中内容(richedit同样适用)<br /><br /></span>        int nStart, nEnd;<br />        CString strTemp;<br /><br />        m_edit1.GetSel(nStart, nEnd);<br />        if(nStart == nEnd)<br />        {<br />            strTemp.Format(_T("光标在%d"), nStart);<br />            AfxMessageBox(strTemp);<br />        }<br />        else<br />        {<br />            //得到edit选中的内容     <br />            m_edit1.GetWindowText(strTemp);<br />            strTemp = strTemp.Mid(nStart) - strTemp.Mid(nEnd);<br />            AfxMessageBox(strTemp); <br />        }<br />    注：GetSel后，如果nStart和nEnd，表明光标处于某个位置（直观来看就是光标在闪动）；<br />             如果nStart和nEnd不相等，表明用户在edit中选中了一段内容。<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">3.在edit最后添加字符串<br /><br /></span>        CString str;<br />        m_edit1.SetSel(-1, -1);<br />        m_edit1.ReplaceSel(str);<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">4.随输入自动滚动到最后一行(richedit同样适用)<br /><br /></span>    方法一：（摘自msdn）<br />        // The pointer to my edit.<br />        extern CEdit* pmyEdit;<br />        int nFirstVisible = pmyEdit-&gt;GetFirstVisibleLine();<br /><br />        // Scroll the edit control so that the first visible line<br />        // is the first line of text.<br />        if (nFirstVisible &gt; 0)<br />        {<br />            pmyEdit-&gt;LineScroll(-nFirstVisible, 0);<br />        }<br />    方法二：<br />        m_richedit.PostMessage(WM_VSCROLL, SB_BOTTOM, 0);<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">5.如何限制edit输入指定字符<br /><br /></span>   可以从CEdit派生一个类，添加WM_CHAR消息映射。下面一个例子实现了限定输入16进制字符的功能。<br /><br />   void CMyHexEdit::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)  <br />   { <br />        if ( (nChar &gt;= '0' &amp;&amp; nChar &lt;= '9') || <br />             (nChar &gt;= 'a' &amp;&amp; nChar &lt;= 'f') || <br />             (nChar &gt;= 'A' &amp;&amp; nChar &lt;= 'F') || <br />              nChar == VK_BACK ||  <br />              nChar == VK_DELETE)    //msdn的virtual key<br />       { <br />            CEdit::OnChar(nChar, nRepCnt, nFlags); <br />        }     <br />   }<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">6.如何使用richedit<br /><br /></span>    添加AfxInitRichEdit();<br />       CxxxApp::InitInstance()<br />        {<br />             AfxInitRichEdit();<br />          .............<br />       }<br /><br />   AfxInitRichEdit()功能：装载 RichEdit 1.0 Control (RICHED32.DLL).<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">7.如何使用richedit2.0 or richedit3.0<br /><br /></span>    使用原因：由于RichEdit2.0A自动为宽字符（WideChar），所以它可以解决中文乱码以及一些汉字问题<br /><br />    方法一：（msdn上的做法，适用于用VC.NET及以后版本创建的工程）<br />            To update rich edit controls in existing Visual C++ applications to version 2.0,<br />            open the .RC file as text, change the class name of each rich edit control from   "RICHEDIT" to  "RichEdit20a". <br />            Then replace the call to AfxInitRichEdit with AfxInitRichEdit2.<br />    方法二：以对话框为例：<br />       (1)    增加一全局变量 HMODULE hMod;<br />       (2)    在CxxxApp::InitInstance()中添加一句hMod = LoadLibrary(_T("riched20.dll"));<br />              在CxxxApp::ExitInstance()中添加一句FreeLibrary(hMod);<br />       (3)      在对话框上放一个richedit，文本方式打开.rc文件修改该richedit控件的类名"RICHEDIT" to  "RichEdit20a".<br />       (4)      在对话框头文件添加 CRichEditCtrl m_richedit;<br />              在OnInitDialog中添加 m_richedit.SubclassDlgItem(IDC_RICHEDIT1, this);<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">8.改变richedit指定区域的颜色及字体<br /><br /></span>        CHARFORMAT cf;<br />        ZeroMemory(&amp;cf, sizeof(CHARFORMAT));<br />        cf.cbSize = sizeof(CHARFORMAT);<br />        cf.dwMask = CFM_BOLD | CFM_COLOR | CFM_FACE |<br />                            CFM_ITALIC | CFM_SIZE | CFM_UNDERLINE;<br />        cf.dwEffects = 0;<br />        cf.yHeight = 12*12;//文字高度<br />        cf.crTextColor = RGB(200, 100, 255); //文字颜色<br />        strcpy(cf.szFaceName ,_T("隶书"));//设置字体<br />     <br />        m_richedit1.SetSel(1, 5); //设置处理区域<br />        m_richedit1.SetSelectionCharFormat(cf);<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">9.设置行间距（只适用于richedit2.0）<br /><br /></span>        PARAFORMAT2 pf;<br />        pf2.cbSize = sizeof(PARAFORMAT2);<br />        pf2.dwMask = PFM_LINESPACING | PFM_SPACEAFTER;<br />        pf2.dyLineSpacing = 200;<br />        pf2.bLineSpacingRule  = 4;<br />        m_richedit.SetParaFormat(pf2);<br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">10.richedit插入位图<br /><br /></span>Q220844：How to insert a bitmap into an RTF document using the RichEdit control in Visual C++ 6.0<br /><a href="http://support.microsoft.com/default.aspx?scid=kb;en-us;220844">http://support.microsoft.com/default.aspx?scid=kb;en-us;220844</a><br /><a href="http://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/">http://www.codeguru.com/Cpp/controls/richedit/article.php/c2417/</a><br /><a href="http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/">http://www.codeguru.com/Cpp/controls/richedit/article.php/c5383/</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">11.richedit插入gif动画<br /><a href="http://www.codeproject.com/richedit/AnimatedEmoticon.asp"><br /></a></span><a href="javascript:void(0);/*1144809701660*/">http://www.codeproject.com/richedit/AnimatedEmoticon.asp</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">12.richedit嵌入ole对象<br /><br /></span><a href="http://support.microsoft.com/kb/141549/en-us">http://support.microsoft.com/kb/141549/en-us</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">13.使richedit选中内容只读<br /><br /></span><a href="http://www.codeguru.com/cpp/controls/richedit/article.php/c2401/">http://www.codeguru.com/cpp/controls/richedit/article.php/c2401/</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">14.打印richedit</span><span style="COLOR: rgb(0,0,0)"><br /><br /><a href="http://www.protext.com/MFC/RichEdit3.htm">http://www.protext.com/MFC/RichEdit3.htm</a></span><br /><a href="http://www.protext.com/MFC/RichEdit3.htm"><span style="COLOR: rgb(0,0,0)"></span></a><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">15.richeidt用于聊天消息窗口<br /><br /></span><a href="http://www.vckbase.com/document/viewdoc/?id=1087">http://www.vckbase.com/document/viewdoc/?id=1087</a><br /><a href="http://www.codeproject.com/richedit/chatrichedit.asp">http://www.codeproject.com/richedit/chatrichedit.asp</a><br /><a href="http://www.codeguru.com/Cpp/controls/richedit/article.php/c2395/">http://www.codeguru.com/Cpp/controls/richedit/article.php/c2395/</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">16.解决richedit的EN_SETFOCUS和EN_KILLFOCUS无响应的问题<br /><br /></span><a href="http://support.microsoft.com/kb/181664/en-us">http://support.microsoft.com/kb/181664/en-us</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">17.richedit拼写检查<br /><br /></span><a href="http://www.codeproject.com/com/AutoSpellCheck.asp">http://www.codeproject.com/com/AutoSpellCheck.asp</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">18.改变edit背景色<br /><br /></span>Q117778：How to change the background color of an MFC edit control<br /><a href="http://support.microsoft.com/kb/117778/en-us">http://support.microsoft.com/kb/117778/en-us</a><br /><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">19.当edit控件的父窗口属性是带标题栏WS_CAPTION和子窗口WS_CHILD时，不能设置焦点SetFocus<br /><br /></span>Q230587：PRB: Can't Set Focus to an Edit Control When its Parent Is an Inactive Captioned Child Window<br style="COLOR: rgb(153,51,0)" /><span style="COLOR: rgb(153,51,0)"><a href="http://support.microsoft.com/kb/230587/en-us"><span style="COLOR: rgb(153,51,0)">http://support.microsoft.com/kb/230587/en-us</span><br style="COLOR: rgb(153,51,0)" /></a></span><br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">20. 在Edit中回车时，会退出对话框  </span><br /><br />选中Edit的风格Want Return。<br /><br />MSDN的解释如下：<br /><font size="+0"><font face="verdana,arial,helvetica" size="2"><strong>ES_WANTRETURN</strong>   Specifies that a carriage return be inserted when the user presses the ENTER key while entering text into a multiple-line edit control in a dialog box. Without this style, pressing the ENTER key has the same effect as pressing the dialog box's default pushbutton. This style has no effect on a single-line edit control.<br /><br /></font></font><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">21. 动态创建的edit没有边框的问题</span><br /><br />    m_edit.Create(....);<br />    m_edit.ModifyStyleEx(0, WS_EX_CLIENTEDGE, SWP_DRAWFRAME);<br /><hr style="WIDTH: 100%; HEIGHT: 2px" /><span style="COLOR: rgb(153,51,0)">22. 一个能显示RTF，ole（包括gif， wmv，excel ，ppt）的例子</span><br /><br /><a href="http://www.codeproject.com/richedit/COleRichEditCtrl.asp">http://www.codeproject.com/richedit/COleRichEditCtrl.asp</a><br /><br /><p id="TBPingURL">Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=652795</p><img src ="http://www.cppblog.com/microli/aggbug/11472.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/microli/" target="_blank">铁观音</a> 2006-08-20 00:34 <a href="http://www.cppblog.com/microli/articles/11472.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>