利用wxWidgets创建多文档实例

Doodle--一个简单的手绘程序,支持简单的撤销和重做。【用以说明Document-View的应用步骤】

1.选择界面风格。

传统的Windows多文档应用使用"wxMDIParentFrame"【Chap4】,一个父框架管理一系列文档子框架,每个激活的子框架使用菜单栏提供命令;另一种是Mac OS风格,一个主窗口,每个文档显示在新的框架中,在桌面上能不受限制的移动。Mac OS风格必须创建一个OFF-SCREEN离屏框架,其菜单栏在所有可见窗口销毁时能自动显示。

2. 创建、使用框架类。

对于MDI应用,需要使用wxDocMDIParentFrame和wxDocMDIChildFrame.对于单个主框架和多个独立的文档框架,使用wxDocParentFrame和wxDocChildFrame.如果同时仅显示一个主框架和一个文档,则使用wxDocParentFrame.如果没有主框架,仅有多个文档框架,使用wxDocParentFrame或wxDocChildFrame。下面是Doodle框架的定义,其中存放一个用于画板的指针,和编辑菜单的指针,关联文档命令处理器,便于系统更新Undo和Redo菜单项。

//定义新的框架

class DoodleFrame: public wxDocParentFrame{

DECLARE_CLASS(DoodleFrame)

DECLARE_EVENT_TABLE()

public:

DoodleFrame(wxDocManager *manager, wxFrame *frame, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long type);

/// 显示About窗口

void OnAbout(wxCommandEvent& event);

/// 获取edit菜单

wxMenu* GetEditMenu() const {return m_editMenu;}

/// 获取画板

DoodleCanvas* GetCanvas() const {return m_canvas;}

private:

wxMenu* m_editMenu;

DoodleCanvas* m_canvas;

};

------------------------------------------------------------------------------------------------------

IMPLEMENT_CLASS(DoodleFrame, wxDocParentFrame)
BEGIN_EVENT_TABLE(DoodleFrame, wxDocParentFrame)
EVT_MENU(DOCVIEW_ABOUT, DoodleFrame::OnAbout)
END_EVENT_TABLE()
DoodleFrame::DoodleFrame(wxDocManager *manager, wxFrame *parent, wxWindowID id, const wxString& title, const wxPoint& pos, const wxSize& size, long type):
wxDocParentFrame(manager, parent, id, title, pos, size, type){
m_editMenu = NULL;
m_canvas = new DoodleCanvas(this, wxDefaultPosition, wxDefaultSize, 0);

 m_canvas->SetCursor(wxCursor(wxCURSOR_PENCIL));
// Give it scrollbars
m_canvas->SetScrollbars(20, 20, 50, 50);
m_canvas->SetBackgroundColour(*wxWHITE);
m_canvas->ClearBackground();
// Give it an icon
SetIcon(wxIcon(doodle_xpm));
// Make a menu bar
wxMenu *fileMenu = new wxMenu;
wxMenu *editMenu = (wxMenu *) NULL;
fileMenu->Append(wxID_NEW, wxT(“&New...”));
fileMenu->Append(wxID_OPEN, wxT(“&Open...”));
fileMenu->Append(wxID_CLOSE, wxT(“&Close”));
fileMenu->Append(wxID_SAVE, wxT(“&Save”));
fileMenu->Append(wxID_SAVEAS, wxT(“Save &As...”));
fileMenu->AppendSeparator();
fileMenu->Append(wxID_PRINT, wxT(“&Print...”));
fileMenu->Append(wxID_PRINT_SETUP, wxT(“Print &Setup...”));
fileMenu->Append(wxID_PREVIEW, wxT(“Print Pre&view”));
editMenu = new wxMenu;
editMenu->Append(wxID_UNDO, wxT(“&Undo”));
editMenu->Append(wxID_REDO, wxT(“&Redo”));
editMenu->AppendSeparator();
editMenu->Append(DOCVIEW_CUT, wxT(“&Cut last segment”));
m_editMenu = editMenu;
fileMenu->AppendSeparator();
fileMenu->Append(wxID_EXIT, wxT(“E&xit”));
wxMenu *helpMenu = new wxMenu;
helpMenu->Append(DOCVIEW_ABOUT, wxT(“&About”));
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(fileMenu, wxT(“&File”));
menuBar->Append(editMenu, wxT(“&Edit”));
menuBar->Append(helpMenu, wxT(“&Help”));
// Associate the menu bar with the frame
SetMenuBar(menuBar);
// A nice touch: a history of files visited. Use this menu.
manager->FileHistoryUseMenu(fileMenu);
}
void DoodleFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
{
(void)wxMessageBox(wxT(“Doodle Sample\n(c) 2004, Julian Smart”),
wxT(“About Doodle”));
}

 3.定义文档和视图类

文档类必须提供默认构造函数,使用DECLARE_DYNAMIC_CLASS 和IMPLEMENT_DYNAMIC_CLASS确保框架能创建文档对象。(或者覆盖wxDocTemplate::CreateDocument)。同时需要告知框架如何保存和装载对象。本例中基于wxWidgets流可以重载SaveObject和LoadObject。或者通过重载DoSaveDocument和DoLoadDocument实现自定义处理。下面是DoodleDocument申明:

/*
* Represents a doodle document
*/
class DoodleDocument: public wxDocument {
DECLARE_DYNAMIC_CLASS(DoodleDocument)
public:
DoodleDocument() {};
~DoodleDocument();
/// Saves the document
wxOutputStream& SaveObject(wxOutputStream& stream);
/// Loads the document
wxInputStream& LoadObject(wxInputStream& stream);
inline wxList& GetDoodleSegments() { return m_doodleSegments; };
private:
wxList m_doodleSegments;
};

-------------------------------------------------

/*
* Defines a line from one point to the other
*/
class DoodleLine: public wxObject
{
public:
DoodleLine(wxInt32 x1 = 0, wxInt32 y1 = 0,
wxInt32 x2 = 0, wxInt32 y2 = 0)
{ m_x1 = x1; m_y1 = y1; m_x2 = x2; m_y2 = y2; }
wxInt32 m_x1;
wxInt32 m_y1;
wxInt32 m_x2;
wxInt32 m_y2;
};
/*
* Contains a list of lines: represents a mouse-down doodle
*/
class DoodleSegment: public wxObject
{
public:
DoodleSegment(){};
DoodleSegment(DoodleSegment& seg);
~DoodleSegment();
void Draw(wxDC *dc);
/// Saves the segment
wxOutputStream& SaveObject(wxOutputStream& stream);
/// Loads the segment
wxInputStream& LoadObject(wxInputStream& stream);
/// Gets the lines
wxList& GetLines() { return m_lines; }
private:
wxList m_lines;
};

-----------------------------------------------------------------------

/*
* DoodleDocument
*/
IMPLEMENT_DYNAMIC_CLASS(DoodleDocument, wxDocument)
DoodleDocument::~DoodleDocument()

{
WX_CLEAR_LIST(wxList, m_doodleSegments);
}
wxOutputStream& DoodleDocument::SaveObject(wxOutputStream& stream)
{
wxDocument::SaveObject(stream);
wxTextOutputStream textStream( stream );
wxInt32 n = m_doodleSegments.GetCount();
textStream << n << wxT(‘\n’);
wxList::compatibility_iterator node = m_doodleSegments.GetFirst();
while (node)
{
DoodleSegment *segment = (DoodleSegment *)node->GetData();
segment->SaveObject(stream);
textStream << wxT(‘\n’);
node = node->GetNext();
}
return stream;
}
wxInputStream& DoodleDocument::LoadObject(wxInputStream& stream)
{
wxDocument::LoadObject(stream);
wxTextInputStream textStream( stream );
wxInt32 n = 0;
textStream >> n;
for (int i = 0; i < n; i++)
{
DoodleSegment *segment = new DoodleSegment;
segment->LoadObject(stream);
m_doodleSegments.Append(segment);
}
return stream;
}
/*
* DoodleSegment
*/
DoodleSegment::DoodleSegment(DoodleSegment& seg)
{
wxList::compatibility_iterator node = seg.GetLines().GetFirst();
while (node)
{
DoodleLine *line = (DoodleLine *)node->GetData();
DoodleLine *newLine = new DoodleLine(line->m_x1, line->m_y1,
line->m_x2, line->m_y2);

GetLines().Append(newLine);
node = node->GetNext();
}
}
DoodleSegment::~DoodleSegment()
{
WX_CLEAR_LIST(wxList, m_lines);
}
wxOutputStream &DoodleSegment::SaveObject(wxOutputStream& stream)
{
wxTextOutputStream textStream( stream );
wxInt32 n = GetLines().GetCount();
textStream << n << wxT(‘\n’);
wxList::compatibility_iterator node = GetLines().GetFirst();
while (node)
{
DoodleLine *line = (DoodleLine *)node->GetData();
textStream
<< line->m_x1 << wxT(“ “)
<< line->m_y1 << wxT(“ “)
<< line->m_x2 << wxT(“ “)
<< line->m_y2 << wxT(“\n”);
node = node->GetNext();
}
return stream;
}
wxInputStream &DoodleSegment::LoadObject(wxInputStream& stream)
{
wxTextInputStream textStream( stream );
wxInt32 n = 0;
textStream >> n;
for (int i = 0; i < n; i++)
{
DoodleLine *line = new DoodleLine;
textStream
>> line->m_x1
>> line->m_y1
>> line->m_x2
>> line->m_y2;
GetLines().Append(line);
}
return stream;
}
void DoodleSegment::Draw(wxDC *dc)
{
wxList::compatibility_iterator node = GetLines().GetFirst();
while (node)
{DoodleLine *line = (DoodleLine *)node->GetData();
dc->DrawLine(line->m_x1, line->m_y1, line->m_x2, line->m_y2);
node = node->GetNext();
}
}

拦截绘图命令

/*
* A doodle command
*/
class DoodleCommand: public wxCommand
{
public:
DoodleCommand(const wxString& name, int cmd, DoodleDocument *doc,
DoodleSegment *seg);
~DoodleCommand();
/// Overrides
virtual bool Do();
virtual bool Undo();
/// Combine do/undo code since the commands are symmetric
bool DoOrUndo(int cmd);
protected:
DoodleSegment* m_segment;
DoodleDocument* m_doc;
int m_cmd;
};
/*
* Doodle command identifiers
*/
#define DOODLE_CUT 1
#define DOODLE_ADD 2

/*
* DoodleCommand
*/
DoodleCommand::DoodleCommand(const wxString& name, int command,
DoodleDocument *doc, DoodleSegment *seg):
wxCommand(true, name)
{
m_doc = doc;
m_segment = seg;
m_cmd = command;
}
DoodleCommand::~DoodleCommand()
{
if (m_segment)
delete m_segment;
}
bool DoodleCommand::Do()
{
return DoOrUndo(m_cmd);
}
bool DoodleCommand::Undo()
{
switch (m_cmd)
{
case DOODLE_ADD:
{
return DoOrUndo(DOODLE_CUT);
}
case DOODLE_CUT:
{
return DoOrUndo(DOODLE_ADD);
}
}
return true;
}
bool DoodleCommand::DoOrUndo(int cmd)
{
switch (cmd)
{
case DOODLE_ADD:
{
wxASSERT( m_segment != NULL );

if (m_segment)
m_doc->GetDoodleSegments().Append(m_segment);
m_segment = NULL;
m_doc->Modify(true);
m_doc->UpdateAllViews();
break;
}
case DOODLE_CUT:
{
wxASSERT( m_segment == NULL );
// Cut the last segment
if (m_doc->GetDoodleSegments().GetCount() > 0)
{
wxList::compatibility_iterator node = m_doc-
>GetDoodleSegments().GetLast();
m_segment = (DoodleSegment *)node->GetData();
m_doc->GetDoodleSegments().Erase(node);
m_doc->Modify(true);
m_doc->UpdateAllViews();
}
break;
}
}
return true;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值