国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > .NET > 正文

用.NET實(shí)現(xiàn)所見即所得的設(shè)計(jì)器

2024-07-10 13:09:47
字體:
供稿:網(wǎng)友
  摘要

  本文討論了如何使用c#編寫一個(gè)所見即所得的設(shè)計(jì)器,分析了設(shè)計(jì)器的基本原理,可能遇到的技術(shù)問題,以及如何調(diào)用.net框架來實(shí)現(xiàn)一個(gè)設(shè)計(jì)器。

  版權(quán)聲明

  本文是xdesigner軟件工作室撰寫,xdesigner軟件工作室擁有本文版權(quán),轉(zhuǎn)載請(qǐng)注明出處,并保留本版權(quán)聲明。

  前言

  隨著計(jì)算機(jī)信息系統(tǒng)不斷深入發(fā)展,其系統(tǒng)結(jié)構(gòu)要求越來越靈活,這種靈活性就是表現(xiàn)為程序的高度可配置性,可能應(yīng)用程序的工作流程可以隨便改變,用戶界面也可以隨便改變,面對(duì)這種不斷增強(qiáng)的靈活,是不可能通過修改程序代碼來實(shí)現(xiàn)的,應(yīng)用系統(tǒng)本身需要發(fā)生深刻變化,需要實(shí)現(xiàn)很強(qiáng)的擴(kuò)展性和靈活性。此外z專門用于修改系統(tǒng)配置的外圍工具也是非常重要的。這些系統(tǒng)外圍定制工具很大一部分就是一些所見即所得的設(shè)計(jì)器。比如工作流編制工具,winform或webform界面設(shè)計(jì)器,而報(bào)表設(shè)計(jì)器也是典型的外圍定制工具。

  總所周知,所見即所得的設(shè)計(jì)器是個(gè)相當(dāng)復(fù)雜的程序,首先它需要復(fù)雜的圖形化用戶界面編程,包括圖形的繪制,鼠標(biāo)鍵盤事件的處理,還要抗屏幕閃爍。其次還有它后臺(tái)的數(shù)據(jù)維護(hù)處理,包括用戶界面和數(shù)據(jù)的同步,數(shù)據(jù)的組織安排,以及加載和保存文檔的處理。而且這些處理過程可以算是糾纏在一起,需要非常認(rèn)真小心的分析設(shè)計(jì),仔細(xì)編碼。

  本文就是探討如何實(shí)現(xiàn)一個(gè)所見即所得的設(shè)計(jì)器。 關(guān)于本文,可以參考作者的另一篇文章-如何使用c#編寫文本編輯器。

  設(shè)計(jì)器類型

  設(shè)計(jì)器按照用戶界面和使用體驗(yàn),可以分為兩種模式,一種是基于直角坐標(biāo)方式,另一種是基于流式排版方式。微軟的visio就是典型的直角坐標(biāo)方式,而word則是流式排版方式,而vs.net的webform窗體設(shè)計(jì)器就是這兩者的結(jié)合。

  在直角坐標(biāo)方式的設(shè)計(jì)器中,設(shè)計(jì)元素是使用xy坐標(biāo)來在設(shè)計(jì)視圖中定位的,對(duì)于矩形元素一般指定它的左上角的位置來定位,設(shè)計(jì)者需要指定設(shè)計(jì)元素的位置,有時(shí)還要設(shè)置它的大小。對(duì)于線段需要指定兩個(gè)端點(diǎn)的xy坐標(biāo)。設(shè)計(jì)者只要設(shè)置好了各個(gè)元素的位置大小就完成了設(shè)計(jì)文檔的基本結(jié)構(gòu),剩下的就是設(shè)置各個(gè)元素各自的內(nèi)容了。

  在流式排版設(shè)計(jì)器中,設(shè)計(jì)元素是不需要指定位置的,是根據(jù)一般根據(jù)從左到右,從上到下的排列原則填充到設(shè)計(jì)視圖中(但有時(shí)會(huì)變成其他排列原則)。設(shè)計(jì)元素的位置是動(dòng)態(tài)計(jì)算的。流式設(shè)計(jì)器可能還要使用鍵盤直接輸入文本,需要顯示光標(biāo)。流式排版設(shè)計(jì)器可以看作文字處理器。

  這兩種設(shè)計(jì)器用戶界面和使用體驗(yàn)不一樣,因此其程序處理的方式也不一樣,直角坐標(biāo)設(shè)計(jì)器存在設(shè)計(jì)元素間相互覆蓋,這影響繪圖,此外還需要大量的鼠標(biāo)拖拽操作,需要認(rèn)真處理鼠標(biāo)事件,但鍵盤事件處理得不多。而流式排版設(shè)計(jì)器中元素不會(huì)相互覆蓋,因此繪制起來方便點(diǎn),鼠標(biāo)事件處理不多,但鍵盤事件處理的多,此外還需要處理光標(biāo)。但這兩種設(shè)計(jì)器它的文檔對(duì)象模型有比較大的類似性。

  在本文中,以下只討論直角坐標(biāo)方式的設(shè)計(jì)器。

  設(shè)計(jì)器的功能

  個(gè)人認(rèn)為一個(gè)設(shè)計(jì)器應(yīng)當(dāng)實(shí)現(xiàn)的功能有

  ·設(shè)計(jì)文檔的加載和保存,設(shè)計(jì)器可以將當(dāng)前設(shè)計(jì)的內(nèi)容保存到一個(gè)文檔中,這個(gè)文檔可以保存到文件中,也可保存到數(shù)據(jù)庫或某個(gè)服務(wù)器中。設(shè)計(jì)器可以加載文檔來完全重現(xiàn)上次的設(shè)計(jì)結(jié)果。

  ·設(shè)計(jì)器可以快速準(zhǔn)確的繪制文檔視圖,當(dāng)視圖大小超過設(shè)計(jì)區(qū)域時(shí),用戶界面應(yīng)當(dāng)出現(xiàn)滾動(dòng)條來進(jìn)行滾動(dòng)操作。

  ·當(dāng)前有互換式設(shè)計(jì)體驗(yàn),用戶可以使用鼠標(biāo)拖拽操作來改變?cè)氐奈恢么笮〉炔季衷O(shè)置,用戶改變了元素的布局或某些屬性時(shí),必須立即更新文檔視圖,而且更新區(qū)域應(yīng)當(dāng)盡量小。

  ·支持所見即所得的設(shè)計(jì)體驗(yàn),當(dāng)設(shè)計(jì)器需要進(jìn)行圖形輸出,例如輸出圖片或打印時(shí),用戶在設(shè)計(jì)器中的設(shè)計(jì)視圖應(yīng)當(dāng)和輸出的圖形保持一致。

  ·盡量減少屏幕閃爍。這需要繪制圖形或更新視圖時(shí)需要進(jìn)行優(yōu)化,盡快完成繪制操作。

  ·若設(shè)計(jì)器需要進(jìn)行擴(kuò)展時(shí),設(shè)計(jì)器應(yīng)當(dāng)提供足夠的擴(kuò)展能力,開發(fā)人員可以在這個(gè)設(shè)計(jì)器的基礎(chǔ)上添加新的特性,使得設(shè)計(jì)器能顯示新樣式的文檔視圖。并且加載和保存文檔時(shí)也能處理新的文檔結(jié)構(gòu)。

  ·若需要可以支持vba腳本,用戶可以編寫vba腳本來控制設(shè)計(jì)器,包括其設(shè)計(jì)的文檔內(nèi)容。

  文檔對(duì)象模型

  對(duì)于計(jì)算機(jī)程序,后臺(tái)決定前臺(tái),而設(shè)計(jì)器的后臺(tái)就是文檔對(duì)象模型。相信大家對(duì)文檔對(duì)象模型有所了解,我們?cè)趙eb頁面中使用javascript腳本時(shí)就是訪問了html文檔對(duì)象模型,我們操作xml文檔就是訪問xml文檔對(duì)象模型。

  w3c國際組織對(duì)文檔對(duì)象模型是這樣定義的(摘自 http://www.w3.org/dom/ )

  the document object model is a platform- and language-neutral interface that will allow programs and scripts to dynamically access and update the content, structure and style of documents. the document can be further processed and the results of that processing can be incorporated back into the presented page. this is an overview of dom-related materials here at w3c and around the web.

  以我個(gè)人的英文水平翻譯如下

  文檔對(duì)象模型是一種語言中立的接口或平臺(tái),程序或腳本能利用它來訪問和更新結(jié)構(gòu)化的文檔。這些文檔可以被進(jìn)一步的處理,處理結(jié)果可以組成一個(gè)有效頁面。這是w3c對(duì)web上的對(duì)文檔對(duì)象模型原理的一般看法。

  我個(gè)人認(rèn)為,對(duì)于編程,文檔對(duì)象模型其主要內(nèi)容就是,面對(duì)比較復(fù)雜的文檔,使用面向?qū)ο蟮木幊趟枷耄褂靡粋€(gè)個(gè)程序世界中的對(duì)象來映射文檔中的每一個(gè)特定的部分。加載文檔時(shí),可以解析文檔,并把其表示的內(nèi)容映射為一個(gè)個(gè)對(duì)象,此時(shí)應(yīng)用程序可以修改這些對(duì)象的數(shù)據(jù),當(dāng)保存文檔時(shí),可以將這些對(duì)象數(shù)據(jù)組織起來按照特定的格式保存到文檔中。這樣程序就通過訪問文檔對(duì)象來訪問文檔,也可以修改文檔對(duì)象來修改文檔,如此實(shí)現(xiàn)了對(duì)復(fù)雜文檔的處理。文檔對(duì)象模型是處理復(fù)雜文檔的標(biāo)準(zhǔn)操作模式。

  設(shè)計(jì)器處理的是復(fù)雜的文檔,因此也需要使用文檔對(duì)象模型。文檔對(duì)象模型可分為三大部分:文檔基本元素,文檔對(duì)象和各種類型的從文檔基本元素派生出的文檔元素。

  文檔基本元素是整個(gè)文檔對(duì)象模型的最基礎(chǔ)的對(duì)象(就像object類型是.net對(duì)象集團(tuán)的基礎(chǔ)一樣),它定義了文檔元素的通用接口,一般定義為抽象類,類型名稱可以為designelement 。

  文檔對(duì)象是文檔對(duì)象模型的頂級(jí)對(duì)象,它包含了整個(gè)文檔的內(nèi)容,其類型名稱可以為 designdocument 。

  各種類型的文檔元素,它是派生自文檔基本元素類型,用于描述文檔中各種實(shí)際存在的元素。其中可以定義一種文檔元素,它們可以容納其他的文檔元素,這些元素就是容器元素。實(shí)際上文檔對(duì)象就是最大的容器元素。由于文檔對(duì)象模型中存在容器元素,因此所有的對(duì)象都組成一個(gè)樹狀結(jié)構(gòu),稱為文檔對(duì)象樹,其中根節(jié)點(diǎn)就是文檔對(duì)象。各種文檔元素是文檔對(duì)象模型的活躍分子,擴(kuò)展文檔對(duì)象模型大部分工作就是擴(kuò)展這些文檔元素,擴(kuò)展文檔元素需要擴(kuò)展它們的兩個(gè)功能,一個(gè)是文檔的加載和保存,一個(gè)就是文檔本身保存的數(shù)據(jù)。

  文檔對(duì)象模型可以和用戶界面相關(guān),也可以不相關(guān),例如xml文檔對(duì)象模型是無用戶界面的。設(shè)計(jì)器的文檔對(duì)象模型是和用戶界面相關(guān)的,對(duì)此,擴(kuò)展設(shè)計(jì)文檔對(duì)象模型的文檔元素時(shí)還需要擴(kuò)展它們的繪制圖形的能力以便設(shè)計(jì)器能繪制新型的文檔元素圖形。

  對(duì)于設(shè)計(jì)文檔對(duì)象模型,其文檔基礎(chǔ)元素可以定義的內(nèi)容有三個(gè)方面,文檔的加載和保存,用戶界面相關(guān)的接口,維護(hù)文檔對(duì)象樹的接口。

  文檔的加載和保存

  設(shè)計(jì)文檔可以保存為二進(jìn)制文檔,純文本文檔和其他格式,在此推薦使用xml文檔格式。其好處是

  ·設(shè)計(jì)文檔對(duì)象模型和xml文檔對(duì)象模型都屬于文檔對(duì)象模型,兩者原理和結(jié)構(gòu)上都有著很大的相似性,設(shè)計(jì)文檔元素和xml文檔元素可以存在一一對(duì)應(yīng)的關(guān)系。因此使用xml文檔加載和保存設(shè)計(jì)文檔對(duì)象是很自然的,實(shí)現(xiàn)起來比較簡單。

  ·xml文檔是國際標(biāo)準(zhǔn)的文檔格式,非常開方,其他應(yīng)用程序很容易利用設(shè)計(jì)器生成的文件,簡化了設(shè)計(jì)器和其他應(yīng)用系統(tǒng)的數(shù)據(jù)接口。

  ·已經(jīng)存在標(biāo)準(zhǔn)的xml文檔解析器和xml文檔對(duì)象模型,因此不需自己處理xml文檔,只需調(diào)用標(biāo)準(zhǔn)庫加載xml文檔對(duì)象模型,然后按照一一對(duì)應(yīng)的關(guān)系來生成設(shè)計(jì)文檔對(duì)象模型。

  ·使用xml文檔有利于保持設(shè)計(jì)器的各個(gè)版本間的兼容性。只要xml文檔結(jié)構(gòu)不發(fā)生大變化,低版本的設(shè)計(jì)器可以加載高版本的設(shè)計(jì)器生成的文檔,同樣高版本的設(shè)計(jì)器也很容易加載低版本的設(shè)計(jì)器生成的文檔。若使用二進(jìn)制文件格式,則設(shè)計(jì)器需要編寫對(duì)于不同版本的設(shè)計(jì)文檔的預(yù)處理器,比較麻煩而且很難做到向上兼容。

  在保存對(duì)象數(shù)據(jù)到xml文檔時(shí),保存方式有兩種,保存到xml屬性和保存到xml元素。當(dāng)指定某個(gè)xml元素用于保存對(duì)象數(shù)據(jù)時(shí),若使用保存到xml屬性時(shí),會(huì)對(duì)對(duì)象每一個(gè)屬性,將其數(shù)據(jù)保存到指定名稱的xml屬性中,而保存到xml元素時(shí),會(huì)在當(dāng)前的xml節(jié)點(diǎn)下新增一個(gè)指定名稱的xml子元素。然后將屬性值保存到xml子元素中。這兩種方式生成的xml片斷為

  <element attributename2="value2" attributename1="value1" />

  和

  <element>
   <attributename1>value1</attributename1>
   <attributename2>value2</attributename2>
  </element>

  面對(duì)這兩種方式,我建議選擇第二種,其原因有:

  ·若保存到xml屬性,則當(dāng)對(duì)象屬性比較多是,使用縮進(jìn)方式輸出的xml文檔將比較寬,在查看是會(huì)出現(xiàn)橫向滾動(dòng)條,不利于閱讀。而保存到xml元素時(shí),xml文檔不會(huì)很寬,便于閱讀。

  ·若多行文本保存到xml屬性,則一般不會(huì)以多行文本的方式保存,不利于閱讀。而保存到xml元素時(shí),則保存的文本和實(shí)際的文本比較接近,便于閱讀。

  ·若保存到xml屬性,則保存方式只能是一個(gè)屬性字符串,而保存到xml元素時(shí)則保存的方式很容易進(jìn)行擴(kuò)展。

  ·雖然保存到xml屬性方式生成的xml文檔比保存為xml元素的方式要小,但xml文檔格式的設(shè)計(jì)目標(biāo)是方便保存數(shù)據(jù)和交換數(shù)據(jù),而不在乎文檔是否冗余,因此我們選擇保存方式時(shí)不必在乎xml文檔的大小。而且一般設(shè)計(jì)文檔的內(nèi)容不很多,以目前計(jì)算機(jī)硬件條件無須在意xml文檔大小。

  當(dāng)設(shè)計(jì)器從xml文檔加載設(shè)計(jì)文檔時(shí), 首先生成xml文檔對(duì)象樹, 然后根據(jù)一一對(duì)應(yīng)的關(guān)系來生成設(shè)計(jì)文檔對(duì)象樹,此時(shí)需要從xml元素保存的信息來判斷該xml元素是對(duì)應(yīng)于那種設(shè)計(jì)文檔元素,設(shè)計(jì)器可以從xml元素名稱來判斷,也可以從某個(gè)xml屬性來判斷,在此我使用xml元素名稱來判斷,首先是針對(duì)一個(gè)xml元素,獲得其名稱比獲得某個(gè)屬性值要方便,其次是xml名稱是必然存在的,肯定不為空,而xml屬性則可能由于某種原因而缺失,xml名稱比xml屬性要穩(wěn)定。

  基于上述的認(rèn)識(shí),當(dāng)采用xml文檔作為保存方式時(shí),設(shè)計(jì)基礎(chǔ)元素需要定義兩個(gè)虛函數(shù),一個(gè)用于從xml文檔加載對(duì)象屬性數(shù)據(jù),另一個(gè)要向xml文檔保存對(duì)象數(shù)據(jù)。而其他文檔元素對(duì)象則根據(jù)需要重載這兩個(gè)函數(shù)來實(shí)現(xiàn)自己的加載和保存對(duì)象屬性的操作,對(duì)于容器元素,還需要保存子元素?cái)?shù)據(jù)到xml文檔和從xml文檔加載子元素。當(dāng)然在實(shí)際應(yīng)用中還要根據(jù)需要定義一些輔助成員來幫助加載和保存xml文檔。

  設(shè)計(jì)器生成的xml文檔一般保存為文件形式,當(dāng)然可以根據(jù)需要來保存的數(shù)據(jù)庫里或者上傳到各種服務(wù)器中。若直接保存到數(shù)據(jù)庫中,則整個(gè)應(yīng)用系統(tǒng)中所有的設(shè)計(jì)器編輯的都是同一個(gè)文檔版本,而且一旦保存便可立即應(yīng)用。

  用戶界面相關(guān)的接口

  設(shè)計(jì)器需要繪制文檔視圖,則需要設(shè)計(jì)文檔對(duì)象模型提供支持。因此文檔基本元素需要定義兩類通用接口,一個(gè)是和繪制文檔相關(guān)的接口,一個(gè)是處理鼠標(biāo)鍵盤事件相關(guān)的接口。

  繪制文檔相關(guān)接口

  大部分文檔元素需要在文檔視圖中繪制內(nèi)容,因此它們需要重載繪制文檔的接口,這類接口主要有兩個(gè)函數(shù),一個(gè)是計(jì)算元素大小的函數(shù),一般命名為 refreshsize , 一個(gè)是繪制元素的函數(shù),一般命名為refreshview。

  一般設(shè)計(jì)者指定元素的大小,元素本身不需要計(jì)算其大小,但某些元素可能是根據(jù)其內(nèi)容自動(dòng)設(shè)置大小,因此需要重載計(jì)算元素大小的函數(shù)refreshsize來自動(dòng)設(shè)置大小。自動(dòng)設(shè)置大小可能只是設(shè)置元素的寬度或高度,也可能是同時(shí)設(shè)置其寬度和高度。同一個(gè)元素,可能在一種狀態(tài)下不會(huì)自動(dòng)設(shè)置大小,而在另外一種狀態(tài)下需要自動(dòng)設(shè)置大小。所有的這些操作都需要在refreshsize函數(shù)中完成。

  一般的設(shè)計(jì)元素都需要在文檔視圖中繪制內(nèi)容,這時(shí)需要重載refreshview函數(shù),這個(gè)函數(shù)參數(shù)包含了一個(gè)system.drawing.graphics對(duì)象,元素需要使用這個(gè)graphics對(duì)象來繪制自己特定的內(nèi)容,可能是繪制文本,圖片或其他圖形。

  當(dāng)所有的文檔元素都實(shí)現(xiàn)了繪制文檔相當(dāng)?shù)慕涌冢瑒t在設(shè)計(jì)器的調(diào)度下,一個(gè)完整的設(shè)計(jì)文檔視圖就繪制出來了。而擴(kuò)展設(shè)計(jì)器時(shí),若需要指定新顯示樣式的元素時(shí),需要重載refreshview和refreshsize函數(shù)來實(shí)現(xiàn)新的顯示樣式,此時(shí)擴(kuò)展的設(shè)計(jì)器就能顯示新樣式的文檔視圖。

  處理鼠標(biāo)鍵盤事件相關(guān)接口

  設(shè)計(jì)器中主要處理鼠標(biāo)事件,文檔基礎(chǔ)元素可以定義一些處理鼠標(biāo)事件的虛函數(shù),名稱可以為 handlemousedown , handlemousemove 和 handlemouseup 。

  為了方便文檔元素處理鼠標(biāo)坐標(biāo),設(shè)計(jì)器在調(diào)用文檔元素的handlemouse函數(shù)時(shí),首先將鼠標(biāo)光標(biāo)坐標(biāo)進(jìn)行轉(zhuǎn)換,要將鼠標(biāo)光標(biāo)在視圖區(qū)域中的坐標(biāo)轉(zhuǎn)換為文檔元素內(nèi)部的相對(duì)坐標(biāo),即相對(duì)于元素左上角的相對(duì)坐標(biāo)。

  設(shè)計(jì)器要依靠鼠標(biāo)事件來實(shí)現(xiàn)設(shè)計(jì)元素的拖拽操作以實(shí)現(xiàn)互換式設(shè)計(jì)體驗(yàn)。關(guān)于鼠標(biāo)拖拽操作典型的應(yīng)用就是使用8個(gè)控制點(diǎn)來編輯元素邊界。當(dāng)一個(gè)元素邊界是矩形時(shí),會(huì)在元素的邊界矩形的四個(gè)角和四個(gè)邊的中點(diǎn)上分布8個(gè)控制點(diǎn),當(dāng)鼠標(biāo)移動(dòng)到這8個(gè)點(diǎn)時(shí)會(huì)修改鼠標(biāo)光標(biāo)樣式,當(dāng)鼠標(biāo)光標(biāo)在某個(gè)控制點(diǎn)上時(shí),用戶按下鼠標(biāo)按鍵則開始進(jìn)行鼠標(biāo)拖拽操作,拖拽時(shí)會(huì)顯示一個(gè)虛線繪制的邊框,當(dāng)松開鼠標(biāo)按鍵則拖拽操作結(jié)束,此時(shí)設(shè)計(jì)器修改拖拽的元素的矩形邊界。

  某些文檔元素并不進(jìn)行標(biāo)準(zhǔn)的鼠標(biāo)拖拽操作,例如對(duì)于容器元素,其內(nèi)部的鼠標(biāo)拖拽不移動(dòng)對(duì)象而是畫出一個(gè)選擇矩形來選擇若干個(gè)子對(duì)象;對(duì)于表格元素,它的表格線上的鼠標(biāo)拖拽操作是修改表格行的高度和表格列的寬度;而對(duì)于線段則是修改端點(diǎn)位置。

  當(dāng)用戶不小心按下鼠標(biāo)按鍵,或只是選擇某個(gè)元素而并不想進(jìn)行鼠標(biāo)拖拽操作,此時(shí)可以使用一個(gè)參數(shù) system.windows.forms.systeminformation.dragsize 來判斷是否進(jìn)行鼠標(biāo)拖拽。當(dāng)鼠標(biāo)按鍵按下時(shí),設(shè)計(jì)器就鎖定鼠標(biāo),若鼠標(biāo)按鍵按下后鼠標(biāo)移動(dòng)距離超出了 dragsize 的范圍時(shí),則表示用戶是想進(jìn)行鼠標(biāo)拖拽操作的,此時(shí)開始真正的鼠標(biāo)拖拽操作。若鼠標(biāo)按鍵從按下到松開時(shí)鼠標(biāo)移動(dòng)距離始終沒超出 dragsize 的范圍,則表示用戶沒有進(jìn)行鼠標(biāo)拖拽操作的意圖。這樣的判斷可以讓設(shè)計(jì)器容忍用戶的一些誤操作。

  設(shè)計(jì)器還要處理鼠標(biāo)雙擊事件處理,對(duì)于某些包含文本的元素,用戶雙擊該元素,則在設(shè)計(jì)視圖中顯示個(gè)文本輸入框來直接編輯對(duì)象的文本內(nèi)容。可以定義一個(gè)接口 ilabeleditable , 當(dāng)用戶雙擊某個(gè)元素,設(shè)計(jì)器發(fā)現(xiàn)該元素實(shí)現(xiàn)了 ilabeleditable 接口,則在設(shè)計(jì)視圖中動(dòng)態(tài)的顯示一個(gè)文本輸入框,然后調(diào)用該接口的成員來直接編輯對(duì)象文本內(nèi)容。

  維護(hù)文檔對(duì)象樹

  文檔基礎(chǔ)元素要定義不少接口來用于維護(hù)文檔對(duì)象樹。要定義 ownerdocument 屬性來指定元素所在的文檔對(duì)象,要定義 parent 屬性來指明元素的父節(jié)點(diǎn),定義 items 屬性來指明該元素的子元素列表。對(duì)于容器元素,還要維護(hù)它的子元素列表。

  設(shè)計(jì)文檔對(duì)象作為文檔樹的根節(jié)點(diǎn),擔(dān)負(fù)著維護(hù)整個(gè)對(duì)象樹的重任,包括文檔整體的加載保存,文檔整體的繪制,遍歷整個(gè)對(duì)象樹結(jié)構(gòu)入口,還要為腳本提供接口。它是訪問文檔對(duì)象樹的入口點(diǎn)。

  一些比較基礎(chǔ)的文檔元素類型

  可以從文檔基礎(chǔ)元素上派生一些比較基礎(chǔ)的文檔元素類型。這些比較基礎(chǔ)的文檔元素類型可以包括:

  ·矩形元素基礎(chǔ)類型,類型名稱為designrectangleelement , 設(shè)計(jì)文檔中大部分元素的邊界是矩形,因此定義矩形元素基礎(chǔ)類型作為這些矩形類型的元素的共同基礎(chǔ)。矩形元素基礎(chǔ)類型實(shí)現(xiàn)了使用8個(gè)點(diǎn)的控制點(diǎn)來修改元素位置和大小的能力,鼠標(biāo)在對(duì)象邊界只那的鼠標(biāo)拖拽操作就可移動(dòng)元素位置。此外還定義了內(nèi)容和邊界之間的邊距信息。

  ·線段類型,類型名稱為designlineelement, 設(shè)計(jì)文檔某些元素是以線段方式顯示的,因此定義線段類型作為這些元素類型的基礎(chǔ)類,線段類型定義了兩個(gè)端點(diǎn)的位置,線段的顯示樣式,標(biāo)簽文檔等信息。此外還重載了鼠標(biāo)事件,使得用戶可以使用鼠標(biāo)拖拽線段的兩個(gè)端點(diǎn)來修改線段端點(diǎn)的坐標(biāo)。此外還要重載命中操作,用于判斷某個(gè)坐標(biāo)是否命中線段對(duì)象,若指定點(diǎn)距離線段的垂直距離小于某個(gè)參數(shù),和點(diǎn)在線段某個(gè)端點(diǎn)上的拖拽點(diǎn)中則命中線段,否則沒命中。

  ·容器元素類型,類型名稱為designelementcontainer , 該元素可以包含若干個(gè)子元素,它是從designrectangleelement 派生的,因此它的邊界是矩形。鼠標(biāo)在容器中的拖拽操作不是移動(dòng)容器,而是動(dòng)態(tài)繪制一個(gè)選擇矩形,當(dāng)完成拖拽操作時(shí),就根據(jù)這個(gè)選擇矩形來設(shè)置子元素的選中狀態(tài)。根據(jù)選擇矩形來選擇子元素有兩種方式,一種是,若子元素邊界和選擇矩形粘邊就被選中,另一種是,若子元素完全在選擇矩形內(nèi)部時(shí)才被選中。容器元素在繪制子元素時(shí)就執(zhí)行矩形覆蓋操作后再調(diào)用子元素的refreshview成員。

  ·帶標(biāo)題容器元素,類型名稱為 designcaptioncontainer , 該元素派生自容器元素,可以包含若干個(gè)子元素,但它頂端有個(gè)標(biāo)題欄,可以顯示文本,用戶使用鼠標(biāo)拖拽這個(gè)標(biāo)題欄可以修改元素的位置。此外它還實(shí)現(xiàn)了 ilabeleditable 接口,當(dāng)用戶雙擊標(biāo)題欄時(shí)可以直接編輯標(biāo)題欄文本。

  ·文本元素,類型名稱為designtextelement,很多文檔元素只是簡單的顯示文本內(nèi)容,則定義文本元素作為這些簡單顯示文本內(nèi)容的元素的共同基礎(chǔ)。它派生自designrectangleelement , 此外還實(shí)現(xiàn)了 ilabeleditable 接口用于直接編輯文本內(nèi)容。此外還支持文本輸出角度控制,此時(shí)繪制文本時(shí)將以元素中心為原點(diǎn)旋轉(zhuǎn)任意角度進(jìn)行繪制。文本元素繪制帶角度的文本時(shí)需要臨時(shí)修改圖形繪制對(duì)象graphics的轉(zhuǎn)換矩陣來設(shè)置繪制角度。

  ·增強(qiáng)文本元素,類型名稱為designtextelementext , 該元素派生自designtextelement, 對(duì)文本輸出格式進(jìn)行了強(qiáng)化,它支持行間距和字符間距,此外還進(jìn)行了文本右邊緣的對(duì)齊操作。顯示對(duì)于大段文本時(shí),尤其包含中文字符和英文字符,某些程序沒有進(jìn)行文本右邊緣對(duì)齊操作。例如ie,記事本等,這是因?yàn)橹形淖址陀⑽淖址麑挾炔灰粯印C恳恍形谋镜膬?nèi)容寬度由于中英字符的個(gè)數(shù)不一樣,很容易導(dǎo)致文本寬度不一樣,因此當(dāng)文本左邊緣對(duì)齊時(shí),其右邊緣很可能是參差不齊的。但ms word顯示大段文本時(shí)它的文本左右邊緣都是對(duì)齊的,它通過在顯示文本時(shí)插入額外的用戶難以察覺字符間距來修正文本顯示寬度。增強(qiáng)型文本元素就利用了這個(gè)原理來實(shí)現(xiàn)文本右邊緣對(duì)齊。

  ·表格元素,類型名稱為designtableelement,表格元素是一種復(fù)雜的容器元素,它包含表格行(designtablerowelement),表格列(designtablecolumnelemetn)和單元格(designtablecellelement)對(duì)象,其中單元格可以進(jìn)行橫向合并和縱向合并。而表格包含的表格行和單元格也是容器元素,用戶不能直接修改單元格的大小位置,而只能調(diào)解表格行的高度和表格列的寬度來修改單元格的大小位置。單元格也是容器元素,因此單元格內(nèi)可以放置若干個(gè)子元素。在很多情況下單元格只是顯示簡單的文本內(nèi)容,因此單元格定義了一些用于顯示文本內(nèi)容的屬性,此外實(shí)現(xiàn)了 ilabeleditable 接口來方便直接編輯單元格文本內(nèi)容。

  ·圖片元素,類型名稱為 designimageelement , 它是從designrectangleelement 派生的,用于簡單的顯示一個(gè)圖片。由于圖片對(duì)象(system.drawing.image)使用了未托管資源,因此圖片元素實(shí)現(xiàn)了 system.idisposable 接口。

  ·此外還定義了一些元素,這些元素可以模擬繪制windows基礎(chǔ)控件,包括文本標(biāo)簽,按鈕,單選框,復(fù)選框,文本框,列表,下列列表,組合框,進(jìn)度條和窗體。可以根據(jù)這些元素來很容易的模擬出一個(gè)窗體設(shè)計(jì)器。

  繪制文檔視圖

  設(shè)計(jì)器的主要工作之一就是繪制文檔視圖。其繪制過程一般是:

  ·設(shè)計(jì)器控件重載它的onpaint成員或綁定paint事件。

  ·當(dāng)操作系統(tǒng)需要重新繪制設(shè)計(jì)器控件時(shí)會(huì)觸發(fā)它的paint事件。

  ·設(shè)計(jì)器獲得繪制圖形使用的system.drawing.graphics對(duì)象和一個(gè)表示繪制區(qū)域的剪切矩形cliprectangle,然后將其作為參數(shù)調(diào)用文檔對(duì)象的refreshview函數(shù)。

  ·文檔對(duì)象進(jìn)行一個(gè)初始化工作,然后遍歷對(duì)象樹結(jié)構(gòu),找到所有和剪切矩形粘邊的文檔元素,調(diào)用它們的refreshview函數(shù),讓各個(gè)元素繪制各自內(nèi)容。

  ·當(dāng)所有工作完畢,則文檔視圖繪制完畢。

  設(shè)計(jì)器繪制文檔是遇到一個(gè)難題就是閃爍,當(dāng)用戶滾動(dòng)視圖和更新視圖時(shí),用戶界面很容易出現(xiàn)閃爍,過多的閃爍會(huì)比較嚴(yán)重的影響使用者的使用。關(guān)于閃爍的原理我曾經(jīng)寫過一篇文章討論了一下(點(diǎn)擊查看)。由于設(shè)計(jì)文檔是比較復(fù)雜的文檔,繪制整個(gè)文檔視圖工作量大,繪制時(shí)間長,因此需要采用各種優(yōu)化來減少繪制時(shí)間,減少閃爍。

  對(duì)于閃爍有一個(gè)算是一勞永逸的辦法就是使用雙緩沖技術(shù)。在繪制圖形時(shí),首先將圖形繪制到一個(gè)內(nèi)存中的bmp圖片上,然后將這個(gè)bmp圖片繪制到用戶界面上。這種方法可以最大程度的減少閃爍,而且在.net中使用雙緩沖也比較簡單。但我不大使用雙緩沖技術(shù),有兩個(gè)原因:

  ·雙緩沖實(shí)際上增加了整個(gè)繪制文檔的工作量,延長了繪圖時(shí)間。當(dāng)用戶滾動(dòng)視圖時(shí),會(huì)造成視圖很“沉重”的感覺,用戶界面響應(yīng)遲鈍。

  ·雙緩沖掩蓋了程序的不足之處。開發(fā)人員可以根據(jù)閃爍程度來判斷繪圖操作是否需要優(yōu)化,以及優(yōu)化效果。但雙緩沖消滅了閃爍,開發(fā)人員也就沒有優(yōu)化繪圖操作的迫切需求,助長了開發(fā)人員的懶惰。程序繪制圖形時(shí)緩慢不堪,而很難從表面看出問題的可能原因。

  其實(shí)可以這樣,設(shè)計(jì)器在開發(fā)時(shí)不使用雙緩沖,但發(fā)布時(shí)則使用雙緩沖。

  由于設(shè)計(jì)器采用直角坐標(biāo)方式,因此各個(gè)元素間存在相互覆蓋的關(guān)系,當(dāng)存在大面積的覆蓋時(shí),繪制文檔時(shí)必需要針對(duì)這種情況進(jìn)行優(yōu)化處理來提高繪制文檔的速度,減少計(jì)算機(jī)屏幕閃爍。針對(duì)覆蓋現(xiàn)象而進(jìn)行優(yōu)化時(shí)可以進(jìn)行矩形覆蓋操作,對(duì)于矩形覆蓋操作,本人有另一篇文章對(duì)此進(jìn)行了說明(點(diǎn)擊查看)。設(shè)計(jì)器繪制某個(gè)元素時(shí),首先針對(duì)這個(gè)元素進(jìn)行矩形覆蓋運(yùn)算,將運(yùn)算結(jié)果作為refreshview函數(shù)的某個(gè)參數(shù)來傳入,當(dāng)文檔元素內(nèi)容比較多時(shí),可以根據(jù)這個(gè)矩形覆蓋運(yùn)算結(jié)果來減少繪制量,提高繪制速度。

  設(shè)計(jì)視圖還應(yīng)提供縮放顯示功能,可以放大設(shè)計(jì)視圖來更清楚的顯示細(xì)節(jié),可以縮小設(shè)計(jì)視圖來總體的把握整個(gè)文檔。gdi+有個(gè)轉(zhuǎn)換矩陣,可以很容易的實(shí)現(xiàn)設(shè)計(jì)視圖的縮放顯示。但此時(shí)所有的鼠標(biāo)坐標(biāo)數(shù)據(jù)都得進(jìn)行相應(yīng)的縮放處理。

  設(shè)計(jì)視圖控件

  設(shè)計(jì)視圖控件是設(shè)計(jì)器在用戶界面上的展示接口。它是一個(gè)標(biāo)準(zhǔn)的windows控件,該控件派生自system.windows.form.usercontrol。用戶使用鼠標(biāo)和鍵盤在這個(gè)控件里面編輯文檔,它重載了onmousedown , onmousemove 和 onmouseup 成員,對(duì)鼠標(biāo)消息進(jìn)行了一下包裝后供設(shè)計(jì)文檔對(duì)象使用。重載了onpaint 成員來更新文檔視圖。重載了 ondoubleclick 來進(jìn)行試圖直接編輯文檔元素的文本內(nèi)容。

  當(dāng)用戶設(shè)置某個(gè)元素為當(dāng)前元素,則設(shè)計(jì)視圖控件將根據(jù)需要來進(jìn)行滾動(dòng)以便當(dāng)前元素出現(xiàn)在可視區(qū)域中。若當(dāng)前元素大小小于可視區(qū)域大小,則處理比較簡單,只要根據(jù)可視區(qū)域大小和元素在視圖中的位置就可計(jì)算滾動(dòng)位置。若元素寬度或高度大于可視區(qū)域的寬度和高度,則需要進(jìn)行額外的判斷,以避免滾動(dòng)時(shí)發(fā)生跳躍。

  鷹眼技術(shù)

  一個(gè)好的設(shè)計(jì)器應(yīng)當(dāng)支持鷹眼技術(shù),所謂鷹眼,通俗的講就是小地圖,它一般放置在程序界面的某個(gè)角落,它的面積不大,主要功能是讓人瞥上一眼就能大體了解整個(gè)文檔的結(jié)構(gòu),并能通過鼠標(biāo)點(diǎn)擊快速的滾動(dòng)文檔。關(guān)于鷹眼,本人寫過一個(gè)文章專門討論了它(點(diǎn)擊查看).

  總結(jié)

  使用方便的所見即所得的設(shè)計(jì)器是一個(gè)復(fù)雜的程序,需要豐富的相關(guān)開發(fā)經(jīng)驗(yàn),它涉及到圖形化,文檔對(duì)象模型以及其他各種編程技術(shù),是一個(gè)多種編程技術(shù)的有機(jī)混合,通常需要編寫數(shù)萬行的代碼才能實(shí)現(xiàn)。因此其技術(shù)門檻比較高,一般的小公司沒有能力完成,即使有些公司有實(shí)力開發(fā),那也要花數(shù)月的時(shí)間,有可能影響公司正常的項(xiàng)目開發(fā)。但隨著各種信息系統(tǒng)越來越靈活,它們必須配備良好的設(shè)計(jì)器,若有一個(gè)使用方便功能強(qiáng)大的設(shè)計(jì)器,則處理這種系統(tǒng)配置是事半功倍的,因此很多開發(fā)人員都不得不面對(duì)開發(fā)設(shè)計(jì)器這個(gè)技術(shù)難題。

  有鑒于此,xdesigner軟件工作室憑著自身豐富的設(shè)計(jì)器開發(fā)經(jīng)驗(yàn)開發(fā)了xdesignerlib,一個(gè)設(shè)計(jì)器中間件,也就是一個(gè)設(shè)計(jì)器的半成品,這個(gè)中間件實(shí)現(xiàn)了所見即所得的設(shè)計(jì)器的全部基礎(chǔ),并提供了非常充分的擴(kuò)展接口.開發(fā)人員了解了xdesignerlib以后就可以僅僅編寫比較簡單的幾千行代碼就能實(shí)現(xiàn)一個(gè)功能強(qiáng)大的設(shè)計(jì)器。借助xdesignerlib,開發(fā)人員不必處理非常繁瑣的底層細(xì)節(jié),只需了解xdesignerlib的接口,擴(kuò)展它就行了。實(shí)事上xdesigner工作室已經(jīng)開發(fā)的各種設(shè)計(jì)器都是基于xdesignerlib的。關(guān)于xdesigner軟件工作室和xdesignerlib,請(qǐng)?jiān)L問 http://www.xdesigner.cn .
發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
主站蜘蛛池模板: 漠河县| 茂名市| 嫩江县| 安吉县| 始兴县| 英吉沙县| 沙田区| 佳木斯市| 余姚市| 阜新| 裕民县| 阜康市| 乳源| 罗定市| 肥乡县| 二连浩特市| 柘荣县| 浮山县| 瓦房店市| 会昌县| 永登县| 依安县| 沧源| 信宜市| 辽阳市| 砚山县| 房产| 阿巴嘎旗| 怀柔区| 远安县| 绥德县| 凯里市| 临泉县| 灌南县| 张家口市| 灵丘县| 稻城县| 青神县| 武乡县| 诸暨市| 开江县|