在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;
}
// 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);
}
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();
}
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);
}
}
/**//// <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()的方法。该方法是将“最近打开列表”保存到注册表中。