在PDN順利執行了啟動邏輯後,就進入Application.Run(new MainForm(arg))了,接下來我們一起來 看看Main裡面有什麼奧秘。
進入MainForm類,發現該類繼承自PdnBaseForm類,而這個基類的注釋裡,說明了該基類用於修復 Form類中透明度不能為1.0的bug,那麼我們之後再看,還是先看看MainForm(string[])構造函數。
在該構造函數中,一進來先是檢查啟動參數。(如何使用啟動參數啟動PDN?這裡提供一個比較簡單 的方法:進入CMD(命令行模式),進入PDN安裝目錄中,並執行paintdotnet.ext /splash或/test等啟 動參數)。(splashForm是啟動歡迎窗口)
如果沒有啟動參數,則構造一個空白的畫布:
構造空白畫布
// no file specified? create a blank image
if (fileNames.Count == 0)
{
//設置畫布定位單位
MeasurementUnit units = Document.DefaultDpuUnit;
double dpu = Document.GetDefaultDpu(units);
Size newSize = this.appWorkspace.GetNewDocumentSize();
this.appWorkspace.CreateBlankDocumentInNewWorkspace(newSize, units, dpu, true);
this.appWorkspace.ActiveDocumentWorkspace.IncrementJustPaintWhite();
this.appWorkspace.ActiveDocumentWorkspace.Document.Dirty = false;
}
以上代碼中,Document、AppWorkspace都是非常重要的概念,我以後會單獨說明,現在還是繼續往下 看。之後調用了LoadWindowState()來設置窗體尺寸。這個方法裡仔細看一下,原來窗體初始化尺寸也是 使用注冊表保存的,有興趣的朋友可以修改一下這些值看看效果。
初始化工作基本完成了,還有最後兩句:啟動一個定時器以及注冊應用程序空閒事件。這兩個事件我 在這裡也說一下:
從定時器變量命名上看出,該定時器是用來延時一些操作的,轉到定時器出發事件中,我們看到定時 器只執行一次,執行的方法為this.appWorkspace.ToolBar.MainMenu.PopulateEffects();。一路追蹤進 去,發現該方法的作用為“加載濾鏡PluginDLL”,使用延時定時器來觸發該方法,避免了應用程序啟動 時需要加載過多DLL而造成假死現象。這樣做,大大加快了應用程序的啟動速度。
窗體初始化的最後,注冊了一句:Application_Idle事件。該事件在應用程序空閒時觸發。追蹤到 ProcessMessage方法,該方法用作處理在隊列中的Windows消息。
到這裡,MainForm的初始化工作就全部完成了。下面我們再看看該窗體的一些重寫方法和一些窗體注 冊事件:
OnDragDrop重寫
protected override void OnDragDrop(DragEventArgs drgevent)
{
Activate();
if (!IsCurrentModalForm || !Enabled)
{
// do nothing
}
else if (drgevent.Data.GetDataPresent(DataFormats.FileDrop))
{
string[] allFiles = (string[])drgevent.Data.GetData (DataFormats.FileDrop);
if (allFiles == null)
{
return;
}
string[] files = PruneDirectories(allFiles);
bool importAsLayers = true;
if (files.Length == 0)
{
return;
}
else
{
TaskButton openTB = new TaskButton(
ImageResource.Get("Icons.MenuFileOpenIcon.png").Reference,
PdnResources.GetString ("DragDrop.OpenOrImport.OpenButton.ActionText"),
PdnResources.GetString ("DragDrop.OpenOrImport.OpenButton.ExplanationText"));
string importLayersExplanation;
if (this.appWorkspace.DocumentWorkspaces.Length == 0)
{
importLayersExplanation = PdnResources.GetString ("DragDrop.OpenOrImport.ImportLayers.ExplanationText.NoImagesYet");
}
else
{
importLayersExplanation = PdnResources.GetString ("DragDrop.OpenOrImport.ImportLayers.ExplanationText");
}
TaskButton importLayersTB = new TaskButton(
ImageResource.Get ("Icons.MenuLayersImportFromFileIcon.png").Reference,
PdnResources.GetString ("DragDrop.OpenOrImport.ImportLayers.ActionText"),
importLayersExplanation);
TaskButton clickedTB = TaskDialog.Show(
this,
new Icon(PdnResources.GetResourceStream ("Icons.Question.ico")),
PdnInfo.GetBareProductName(),
null,
false,
PdnResources.GetString("DragDrop.OpenOrImport.InfoText"),
new TaskButton[] { openTB, importLayersTB, TaskButton.Cancel },
null,
TaskButton.Cancel);
if (clickedTB == openTB)
{
importAsLayers = false;
}
else if (clickedTB == importLayersTB)
{
importAsLayers = true;
}
else
{
return;
}
}
if (!importAsLayers)
{
// open files into new tabs
this.appWorkspace.OpenFilesInNewWorkspace(files);
}
else
{
// no image open? we will have to create one
if (this.appWorkspace.ActiveDocumentWorkspace == null)
{
Size newSize = this.appWorkspace.GetNewDocumentSize();
this.appWorkspace.CreateBlankDocumentInNewWorkspace(
newSize,
Document.DefaultDpuUnit,
Document.GetDefaultDpu(Document.DefaultDpuUnit),
false);
}
ImportFromFileAction action = new ImportFromFileAction();
HistoryMemento ha = action.ImportMultipleFiles (this.appWorkspace.ActiveDocumentWorkspace, files);
if (ha != null)
{
this.appWorkspace.ActiveDocumentWorkspace.History.PushNewMemento(ha);
}
}
}
base.OnDragDrop(drgevent);
}
以上代碼重寫了DragDrop方法,分析一下它做了什麼。
string[] files = PruneDirectories(allFiles);獲取了所有拖拽入窗體的文件列表,然後使用 TashDialog詢問直接打開新文件還是在新圖層中添加。
TaskDialog類提供了PDN中所有詢問窗口的ShowDialog方法,並返回TaskButton對象,TaskButton對 象中封裝了詢問按鈕提示文字,顯示圖片以及DialogResult等,這各類所提供的詢問窗口定制性強,而 且顯示美觀,值得參考!
在接到用戶選擇的TaskButton結果後,執行相應的方法1.往當前Workspace中添加新DocumentView。 2.在當前DocumentView中添加新圖層。(DoucmentView也是重要概念,以後再講)。接著,構造了一個 HistoryMemento對象。該對象描述了PDN應喲個程序中的“歷史記錄”,該類以後成立專題研究。
this.appWorkspace.ActiveDocumentWorkspace.History.PushNewMemento(ha);將剛才構造的歷史記 錄推入活動的DocumentView中。
原來我們使用拖拽文件到PDN中,並彈出對話框等一系列過程是如此的~。
我們繼續研究。MainForm重寫了OnClosing事件,裡面調用了SaveSetting()方法:
保存設置
private void SaveSettings()
{
Settings.CurrentUser.SetInt32(PdnSettings.Width, this.Width);
Settings.CurrentUser.SetInt32(PdnSettings.Height, this.Height);
Settings.CurrentUser.SetInt32(PdnSettings.Top, this.Top);
Settings.CurrentUser.SetInt32(PdnSettings.Left, this.Left);
Settings.CurrentUser.SetString(PdnSettings.WindowState, this.WindowState.ToString());
Settings.CurrentUser.SetBoolean(PdnSettings.TranslucentWindows, PdnBaseForm.EnableOpacity);
if (this.WindowState != FormWindowState.Minimized)
{
Settings.CurrentUser.SetBoolean(PdnSettings.ToolsFormVisible, this.appWorkspace.Widgets.ToolsForm.Visible);
Settings.CurrentUser.SetBoolean(PdnSettings.ColorsFormVisible, this.appWorkspace.Widgets.ColorsForm.Visible);
Settings.CurrentUser.SetBoolean(PdnSettings.HistoryFormVisible, this.appWorkspace.Widgets.HistoryForm.Visible);
Settings.CurrentUser.SetBoolean(PdnSettings.LayersFormVisible, this.appWorkspace.Widgets.LayerForm.Visible);
}
SnapManager.Save(Settings.CurrentUser);
this.appWorkspace.SaveSettings();
}
把值設置到注冊表
/**//// <summary>
/// 把值保存到注冊表中
/// </summary>
/// <param name="key">The name of the key to set.</param>
/// <param name="value">The new value of the key.</param>
public void SetObject(string key, object value)
{
using (RegistryKey pdnKey = CreateSettingsKey(true))
{
pdnKey.SetValue(key, value);
}
}
該方法裡把窗體的尺寸,位置等保存到了注冊表中,那麼下次用戶再啟動應用程序的時候就可以把窗 體恢復到最近一次關閉的狀態了。在appWorkspace.SveSettings()追蹤進去,發現了一個SaveMruList() 的方法。該方法是將“最近打開列表”保存到注冊表中。