时间: 2021-07-31 作者:daque
南京邮政局计划机重心 张中庆一、对于csplitterwnd类 咱们在运用cuteftp大概netant等东西的功夫,普遍城市被其搀杂的界面所招引,在那些界面中窗口被分隔为几何的地区,真实做到了窗口的大肆分隔。 那么咱们本人怎样创造一致的界面,也实行窗口的大肆的分隔呢 ?在vc6.0中这就须要运用到csplitterwnd类。csplitterwnd看上去像是一种特出的框架窗口,每个窗口都被沟通的大概各别的视图所弥补。当窗口被切分后用户不妨运用鼠标挪动切分条来安排窗口的对立尺寸。固然vc6.0扶助从appwizard中创造分隔窗口,然而机动介入的分隔条老是不许让咱们合意,所以咱们仍旧经过细工减少代码来熟习这个类。 csplitterwnd的结构因变量重要囊括底下三个。 bool create(cwnd* pparentwnd,int nmaxrows,int nmaxcols,size sizemin,ccreatecontext* pcontext,dword dwstyle,uint nid); 功效刻画:该因变量用来创造动静切分窗口。 参数含意:pparentwnd 切分窗口的父框架窗口。 nmaxrows,nmaxcols是创造的最大的列数和行数。 sizemin是窗格的实际巨细。 pcontext 大普遍情景下传给父窗口。 nid是字窗口的id号. bool createstatic(cwnd* pparentwnd,int nrows,int ncols,dword dwstyle,uint nid) 功效刻画:用来创造切分窗口。 参数含意同上。 bool createview (int row,int col,cruntimeclass* pviewclass,size sizeinit,ccreatecontext* pcontext); 功效刻画:为静态切分的窗口的网格弥补视图。在将视图于切分窗口接洽在一道的功夫必 须先将切分窗口创造好。 参数含意:同上。 从csplitterwnd源步调不妨看出尽管是运用动静创造create仍旧运用静态创造createstatic,在因变量中都挪用了一个养护因变量createcommon,从底下的createcommon因变量中的要害代码不妨看出创造csplitterwnd的本质是创造了一系列的mdi子窗口。 dword dwcreatestyle = dwstyle & ~(ws_hscroll|ws_vscroll); if (afxdata.bwin4) dwcreatestyle &= ~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->m_hwnd, (hmenu)nid, null)) return false; // create invisible 二、创造嵌套分隔窗口 2.1创造动静分隔窗口 动静分隔窗口运用create本领。底下的代码将创造2x2的窗格。 m_wndsplitter.create(this,2,2,csize(100,100),pcontext); 然而动静创造的分隔窗口的窗格数量不许胜过2x2,并且对于一切的窗格,都必需共享同一个视图,所受的控制也比拟多,所以咱们不将动静创造动作中心。咱们的重要精神放在静态分隔窗口的创造上。 2.2创造静态分隔窗口与动静创造比拟,静态创造的代码要大略很多,并且不妨最多创造16x16的窗格。各别的窗格咱们不妨运用createview弥补各别的视图。 在这边咱们将创造cuteftp的窗口分隔。cuteftp的分隔情景如次:ccuteftpview cview2 cview3 cview4 创造办法: ▲ 在创造之前咱们必需先用appwizard天生单文书档案cuteftp,天生的视类为 ccuteftpview.同声在减少三个视类大概从视类接受而来的派生类cview2,cview3 cview4. ▲ 减少分子: 在cmainfrm.h中咱们将减少底下的代码: csplitterwnd wndsplitter1; csplitterwnd wndsplitter2; ▲ 重载cmainframe::oncreateclient()因变量: 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(&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; } 2.3实行各个分隔地区的通讯 ■有文书档案贯串的视图之间的通讯由appwizard天生的ccuteftpview是与文书档案贯串的,同声咱们也让cview2与文书档案贯串,所以咱们须要窜改ccuteftpapp的initinstance()因变量,咱们将减少底下的局部。adddoctemplate (new cmultidoctemplate(idr_view2type, runtime_class(cmaindoc), runtime_class(cmdichildwnd), runtime_class(cview2))); 咱们此刻来实行ccuteftpview与cview2之间的通讯。因为跟文书档案类贯串的视图类 是不许安定的与除文书档案类除外的其他的视图类通讯的。所以咱们只能让她们都与文书档案 类通讯。在文书档案中咱们树立相映的南针以用来获的各个视图。咱们重载 ccuteftpview::onopendocument()因变量; ccuteftpview* pcuteftpview;cview2* pview2;position pos;cview* pview;while(pos!=null){ pview=getnextview(pos); if(pview->iskindof(runtime_class(ccuteftpview))==null) pcuteftpview=(ccuteftpview*)pview; else(pview->iskindof(runtime_class(ccuteftpview))==null) pview2=(cview2*)pview; } 如许咱们在文书档案类中就获的了跟它贯串的一切的视图的南针。即使须要在 ccuteftpview中挪用cview第22中学的一个本领doit()则代码如次: ccuteftpdoc* pdoc=getdocument();cview2* pview2=pdoc->pview3;pview3.doit(); ■无文书档案视图与文书档案关系视图之间的通讯cview3和cview4都是不与文书档案关系联的。咱们此刻实行cview3与cview2的通讯.正如前方所说,cview2只能安定的与ccuteftpdoc通讯,所以,cview3即使须要跟cview2通讯,也必需借助于文书档案类。所以步调的要害是怎样在cview3中赢得文书档案的南针。视图类中没有如许的类分子不妨用来径直考察文书档案类。然而咱们领会在主窗口类mainframe中咱们不妨赢得步调的大肆窗口类的南针。所以咱们只有赢得步调主窗口了的南针,就不妨处置题目了。代码实行在cview3中考察cview第22中学的doit()本领。cview3中的代码如次: cmainframe* mainframe=(cmainframe*)this->getparent()->getparent(); ccuteftpdoc* doc=(ccuteftpdoc*)mainframe->getactivedocument();if(doc!=null) doc->doit(); ccuteftpdoc中的相映的处置因变量doit()代码如次: cview2* pview2; position pos; cview* pview; while(pos!=null) { pview=getnextview(pos); if(pview->iskindof(runtime_class(cview2))==null) pview2=(cview2*)pview; } pview2->doit(); ■无文书档案关系视图之间的通讯cview3和cview4都是不跟文书档案贯串的,怎样实行她们之间的通讯呢。 正如咱们在上头所说的那么,因为在主框架中咱们不妨考察大肆的视图,所以咱们的重要任 务仍旧在步调中赢得主框架的南针。在cview3中考察cview4中的本领doit()。 cmainframe* mainframe=(cmainframe*)this->getparent()->getparent(); cview4* view4=(cview4*)mainframe->m_wndsplitter1.getpane(2,0); view4->doit(); 到此刻咱们仍旧实行了cuteftp的主窗口的框架而且不妨实行她们之间彼此通讯的框架。 同样的咱们不妨实行其余的少许时髦界面比方netants,foxmail的分隔。 三、对于对话框的分隔 到暂时为止,惟有鉴于文书档案/视图的步调本领运用csplitterwnd,而鉴于对话框的运用步调却不扶助csplitterwnd,然而即使咱们在接受类中重载少许假造本领,也能使csplitterwnd 在对话框步调中运用。从mfc的源步调winsplit.cpp中不妨看出,为了赢得父窗口的场合步调都挪用了假造本领getparentframe(),所以即使在对话框中运用,咱们必需将它改为getparent();所以咱们将csplitterwnd的底下几个本领重载。 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 ); 简直实行如次,实行中我将给出原有代码的重要局部以及窜改后的代码以抵制比。在cpp文献中介入底下的列举典型。 enum hittestvalue { nohit = 0,//表白没有选中任何东西 vsplitterbox = 1, hsplitterbox = 2, bothsplitterbox = 3, vsplitterbar1 = 101,//代办各个目标的水等分割条 vsplitterbar15 = 115, hsplitterbar1 = 201,//代办笔直目标的各个分隔条 hsplitterbar15 = 215, splitterintersection1 = 301,//代办各个穿插点 splitterintersection225 = 525};cwnd* cxsplitterwnd::getactivepane(int* prow, int* pcol){ assert_valid(this); //赢得暂时的赢得中心的窗口 //底下解释粗体的是原有的代码的重要局部。 // cwnd* pview = null; //cframewnd* pframewnd = getparentframe(); //assert_valid(pframewnd); //pview = pframewnd->getactiveview(); //if (pview == null) // pview = getfocus(); cwnd* pview = getfocus(); if (pview != null && !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->setactiveview((cview*)ppane); ppane->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 >= splitterintersection1 && ht <= 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 && pview->iskindof(runtime_class(cview))) //{ // assert_valid(pview); // cframewnd* pframewnd = getparentframe(); //assert_valid(pframewnd); //pview->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; //底下粗体的是原步调的语句 //return getparentframe()->sendmessage(wm_command, wparam, lparam); return getparent()->sendmessage(wm_command, wparam, lparam); }bool cxsplitterwnd::onnotify( wparam wparam, lparam lparam, lresult* presult ){ if (cwnd::onnotify(wparam, lparam, presult)) return true; //底下粗体的是源步调的语句 //*presult = getparentframe()->sendmessage(wm_notify, wparam, lparam); *presult = getparent()->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); } 如许咱们就不妨在对话框中运用cxsplitterwnd类了。 四、csplitterwnd的扩充 csplitterwnd扩充话题是很多的,咱们不妨经过对原有本领的掩盖大概减少新的本领来扩充csplitterwnd。咱们在此仅举两个上面的例子。 4.1锁定切分条当用户创造好分隔窗口后,偶尔并不蓄意经过拖动切分条来安排窗口的巨细。这时候就必需锁定切分条。锁定切分条的最大略的本领莫过于不让csplitterwnd来处置wm_lbuttondown,wm_mousemove,wm_setcursor动静,而是将那些动静交给cwnd窗口举行处置,进而樊篱掉那些动静。拿wm_lbuttondown处置进程来说。窜改为如次: void cxxsplitterwnd::onlbuttondown(uint nflags,cpoint point) { cwnd::onlbuttondown(nflags,point);} 其他的处置本领一致。 4.2切分条的定制 由window本人天生的切分条老是恒定的,没有任何的变革,咱们在运用少许软硬件比方acdsee的功夫却能创造它们的切分条却是和机动天生的切分条不一律的。那么怎样定制本人的切分条呢?经过重载csplitterwnd的虚本领ondrawsplitter和oninverttracker不妨到达如许的手段。底下的代码天生的功效是分隔窗口的边境脸色为赤色,分隔条的脸色为绿色.代码如次:void csplitterwndex::ondrawsplitter(cdc *pdc, esplittype ntype, const crect &rectarg){ if(pdc==null) { redrawwindow(rectarg,null,rdw_invalidate|rdw_nochildren); return; } assert_valid(pdc); crect rc=rectarg; switch(ntype) { case splitborder: //重画分隔窗口边境,使之为赤色 pdc->draw3drect(rc,rgb(255,0,0),rgb(255,0,0)); rc.inflaterect(-cx_border,-cy_border); pdc->draw3drect(rc,rgb(255,0,0),rgb(255,0,0)); return; case splitbox: pdc->draw3drect(rc,rgb(0,0,0),rgb(0,0,0)); rc.inflaterect(-cx_border,-cy_border); pdc->draw3drect(rc,rgb(0,0,0),rgb(0,0,0)); rc.inflaterect(-cx_border,-cy_border); pdc->fillsolidrect(rc,rgb(0,0,0)); pdc->draw3drect(rc,rgb(0,0,0),rgb(0,0,0)); return; case splitbar: //重画分隔条,使之为绿色 pdc->fillsolidrect(rc,rgb(255,255,255)); rc.inflaterect(-5,-5); pdc->draw3drect(rc,rgb(255,0,0),rgb(255,0,0)); return; default: assert(false); } pdc->fillsolidrect(rc,rgb(0,0,255));} void csplitterwndex::oninverttracker(crect &rect) { assert_valid(this); assert(!rect.isrectempty()); assert((getstyle()&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->m_hdc,pbrush->m_hobject); pdc->patblt(rc.left,rc.top,rc.width(),rc.height(),blackness); if(holdbrush!=null) selectobject(pdc->m_hdc,holdbrush); releasedc(pdc); } 同样咱们只有接受csplitterwnd中的其他的少许假造本领就不妨天生具备本人天性的分隔窗口了。我的电子邮箱:tingya@njpost.com.cn 和tingya@263.net 地方:南京邮政局计划机重心 张中庆 邮编:210008