第11章 GUI Page411~420 步骤五 支持其他图形

2023-12-22 18:52

本文主要是介绍第11章 GUI Page411~420 步骤五 支持其他图形,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

运行效果:

源代码

//item_i.hpp 抽象“图形元素”接口定义
#ifndef ITEM_I_HPP_INCLUDED
#define ITEM_I_HPP_INCLUDED#include <wx/gdicmn.h>
#include <wx/dc.h>class IItem
{
public://作为接口,记得要有虚析构virtual ~IItem(){}//使用DC画出自己//注意:“画”的方法不应该修改对象的数据virtual void Draw(wxDC& dc) const = 0; //纯虚函数//开始在某一点上绘图virtual void OnDrawStart(wxPoint const& point) = 0; //纯虚函数//结束在某一点virtual void OnDrawEnd(wxPoint const& point) = 0; //纯虚函数
};#endif // ITEM_I_HPP_INCLUDED
//item_line.hpp 修改现有的LineItem类,实现IItem接口#ifndef ITEM_LINE_HPP_INCLUDED
#define ITEM_LINE_HPP_INCLUDED#include "item_i.hpp"class LineItem : public IItem
{
public:LineItem(): _startPosition(0, 0), _endPosition(0, 0){}virtual void Draw(wxDC& dc) const;//    virtual void OnDrawStart(wxPoint const& point) //书上写法void OnDrawStart(wxPoint const& point) override //C++11{_startPosition = point;}virtual void OnDrawEnd(wxPoint const& point) //写不写virtual不影响{_endPosition = point;}private://不写Logic后缀,但仍然是存储逻辑坐标wxPoint _startPosition, _endPosition;
};#endif // ITEM_LINE_HPP_INCLUDED

//item_line.cpp
#include "item_line.hpp"void LineItem::Draw(wxDC& dc) const
{dc.DrawLine(_startPosition, _endPosition);//就这一行,画直线
}

/**************************************************************** Name:      wxMyPainterApp.h* Purpose:   Defines Application Class* Author:    yanzhenxi (3065598272@qq.com)* Created:   2023-12-21* Copyright: yanzhenxi ()* License:**************************************************************/#ifndef WXMYPAINTERAPP_H
#define WXMYPAINTERAPP_H#include <wx/app.h>class wxMyPainterApp : public wxApp
{public:virtual bool OnInit();
};#endif // WXMYPAINTERAPP_H

/**************************************************************** Name:      wxMyPainterApp.cpp* Purpose:   Code for Application Class* Author:    yanzhenxi (3065598272@qq.com)* Created:   2023-12-21* Copyright: yanzhenxi ()* License:**************************************************************/#include "wxMyPainterApp.h"//(*AppHeaders
#include "wxMyPainterMain.h"
#include <wx/image.h>
//*)IMPLEMENT_APP(wxMyPainterApp);bool wxMyPainterApp::OnInit()
{//(*AppInitializebool wxsOK = true;wxInitAllImageHandlers();if ( wxsOK ){wxMyPainterFrame* Frame = new wxMyPainterFrame(0);Frame->Show();SetTopWindow(Frame);}//*)return wxsOK;}

/**************************************************************** Name:      wxMyPainterMain.h* Purpose:   Defines Application Frame* Author:    yanzhenxi (3065598272@qq.com)* Created:   2023-12-21* Copyright: yanzhenxi ()* License:**************************************************************/#ifndef WXMYPAINTERMAIN_H
#define WXMYPAINTERMAIN_H
#include <list>
#include "item_i.hpp"//(*Headers(wxMyPainterFrame)
#include <wx/scrolwin.h>
#include <wx/sizer.h>
#include <wx/menu.h>
#include <wx/listbox.h>
#include <wx/frame.h>
#include <wx/statusbr.h>
//*)class wxMyPainterFrame: public wxFrame
{public:wxMyPainterFrame(wxWindow* parent,wxWindowID id = -1);virtual ~wxMyPainterFrame();private://(*Handlers(wxMyPainterFrame)void OnQuit(wxCommandEvent& event);void OnAbout(wxCommandEvent& event);void OnScrolledWindow1LeftDown(wxMouseEvent& event);void OnScrolledWindow1MouseMove(wxMouseEvent& event);void OnScrolledWindow1LeftUp(wxMouseEvent& event);void OnScrolledWindow1Paint(wxPaintEvent& event);//*)//(*Identifiers(wxMyPainterFrame)static const long ID_LISTBOX1;static const long ID_SCROLLEDWINDOW1;static const long idMenuQuit;static const long idMenuNone;static const long idMenuLine;static const long idMenuRectangle;static const long idMenuCircle;static const long idMenuText;static const long idMenuAbout;static const long ID_STATUSBAR1;//*)//(*Declarations(wxMyPainterFrame)wxMenuItem* MenuItemLine;wxMenuItem* MenuItemNone;wxScrolledWindow* ScrolledWindow1;wxMenu* Menu3;wxMenuItem* MenuItemText;wxStatusBar* StatusBar1;wxMenuItem* MenuItemRectangle;wxMenuItem* MenuItemCircle;wxListBox* ListBox1;//*)private:void RemoveAllItems();IItem* CreateNewItem();/*每当用户鼠标按下,就创建一个新的_newItem,等画完之后(鼠标抬起),就将它加入“_items”列表中。这也解释了为什么不需要“_drawing”这个标志,因为当“_newItem”不为空,就说明用户正在画新的线。OnPaint事件的思路配套调整为:每次都画出“_items”中的所有元素;然后如果“_newItem”不为空,则把用户正在拖拽的线也画出来。*/IItem* _newItem;std::list <IItem*> _items;DECLARE_EVENT_TABLE()
};#endif // WXMYPAINTERMAIN_H

/**************************************************************** Name:      wxMyPainterMain.cpp* Purpose:   Code for Application Frame* Author:    yanzhenxi (3065598272@qq.com)* Created:   2023-12-21* Copyright: yanzhenxi ()* License:**************************************************************/#include "wxMyPainterMain.h"
#include <wx/msgdlg.h>
#include <wx/dcclient.h>
#include "item_line.hpp"//(*InternalHeaders(wxMyPainterFrame)
#include <wx/settings.h>
#include <wx/intl.h>
#include <wx/string.h>
//*)//helper functions
enum wxbuildinfoformat {short_f, long_f };wxString wxbuildinfo(wxbuildinfoformat format)
{wxString wxbuild(wxVERSION_STRING);if (format == long_f ){
#if defined(__WXMSW__)wxbuild << _T("-Windows");
#elif defined(__UNIX__)wxbuild << _T("-Linux");
#endif#if wxUSE_UNICODEwxbuild << _T("-Unicode build");
#elsewxbuild << _T("-ANSI build");
#endif // wxUSE_UNICODE}return wxbuild;
}//(*IdInit(wxMyPainterFrame)
const long wxMyPainterFrame::ID_LISTBOX1 = wxNewId();
const long wxMyPainterFrame::ID_SCROLLEDWINDOW1 = wxNewId();
const long wxMyPainterFrame::idMenuQuit = wxNewId();
const long wxMyPainterFrame::idMenuNone = wxNewId();
const long wxMyPainterFrame::idMenuLine = wxNewId();
const long wxMyPainterFrame::idMenuRectangle = wxNewId();
const long wxMyPainterFrame::idMenuCircle = wxNewId();
const long wxMyPainterFrame::idMenuText = wxNewId();
const long wxMyPainterFrame::idMenuAbout = wxNewId();
const long wxMyPainterFrame::ID_STATUSBAR1 = wxNewId();
//*)BEGIN_EVENT_TABLE(wxMyPainterFrame,wxFrame)//(*EventTable(wxMyPainterFrame)//*)
END_EVENT_TABLE()wxMyPainterFrame::wxMyPainterFrame(wxWindow* parent,wxWindowID id): _newItem(nullptr)
{//(*Initialize(wxMyPainterFrame)wxMenuItem* MenuItemAbout;wxMenu* Menu1;wxMenuItem* MenuItemQuit;wxBoxSizer* BoxSizer1;wxMenuBar* MenuBar1;wxMenu* Menu2;Create(parent, id, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxDEFAULT_FRAME_STYLE, _T("id"));SetClientSize(wxSize(208,94));BoxSizer1 = new wxBoxSizer(wxHORIZONTAL);ListBox1 = new wxListBox(this, ID_LISTBOX1, wxDefaultPosition, wxSize(168,68), 0, 0, 0, wxDefaultValidator, _T("ID_LISTBOX1"));BoxSizer1->Add(ListBox1, 0, wxALL|wxEXPAND, 5);ScrolledWindow1 = new wxScrolledWindow(this, ID_SCROLLEDWINDOW1, wxDefaultPosition, wxDefaultSize, wxVSCROLL|wxHSCROLL, _T("ID_SCROLLEDWINDOW1"));ScrolledWindow1->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW));BoxSizer1->Add(ScrolledWindow1, 1, wxALL|wxEXPAND, 5);SetSizer(BoxSizer1);MenuBar1 = new wxMenuBar();Menu1 = new wxMenu();MenuItemQuit = new wxMenuItem(Menu1, idMenuQuit, _("退出\tAlt-F4"), _("Quit the application"), wxITEM_NORMAL);Menu1->Append(MenuItemQuit);MenuBar1->Append(Menu1, _("文件[&F]"));Menu3 = new wxMenu();MenuItemNone = new wxMenuItem(Menu3, idMenuNone, _("无"), wxEmptyString, wxITEM_RADIO);Menu3->Append(MenuItemNone);MenuItemLine = new wxMenuItem(Menu3, idMenuLine, _("直线"), wxEmptyString, wxITEM_RADIO);Menu3->Append(MenuItemLine);MenuItemRectangle = new wxMenuItem(Menu3, idMenuRectangle, _("矩形"), wxEmptyString, wxITEM_RADIO);Menu3->Append(MenuItemRectangle);MenuItemCircle = new wxMenuItem(Menu3, idMenuCircle, _("圆形"), wxEmptyString, wxITEM_RADIO);Menu3->Append(MenuItemCircle);MenuItemText = new wxMenuItem(Menu3, idMenuText, _("文字"), wxEmptyString, wxITEM_RADIO);Menu3->Append(MenuItemText);MenuBar1->Append(Menu3, _("组件[&I]"));Menu2 = new wxMenu();MenuItemAbout = new wxMenuItem(Menu2, idMenuAbout, _("关于\tF1"), _("Show info about this application"), wxITEM_NORMAL);Menu2->Append(MenuItemAbout);MenuBar1->Append(Menu2, _("帮助[&H]"));SetMenuBar(MenuBar1);StatusBar1 = new wxStatusBar(this, ID_STATUSBAR1, 0, _T("ID_STATUSBAR1"));int __wxStatusBarWidths_1[1] = { -1 };int __wxStatusBarStyles_1[1] = { wxSB_NORMAL };StatusBar1->SetFieldsCount(1,__wxStatusBarWidths_1);StatusBar1->SetStatusStyles(1,__wxStatusBarStyles_1);SetStatusBar(StatusBar1);SetSizer(BoxSizer1);Layout();ScrolledWindow1->Connect(wxEVT_PAINT,(wxObjectEventFunction)&wxMyPainterFrame::OnScrolledWindow1Paint,0,this);ScrolledWindow1->Connect(wxEVT_LEFT_DOWN,(wxObjectEventFunction)&wxMyPainterFrame::OnScrolledWindow1LeftDown,0,this);ScrolledWindow1->Connect(wxEVT_LEFT_UP,(wxObjectEventFunction)&wxMyPainterFrame::OnScrolledWindow1LeftUp,0,this);ScrolledWindow1->Connect(wxEVT_MOTION,(wxObjectEventFunction)&wxMyPainterFrame::OnScrolledWindow1MouseMove,0,this);Connect(idMenuQuit,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxMyPainterFrame::OnQuit);Connect(idMenuAbout,wxEVT_COMMAND_MENU_SELECTED,(wxObjectEventFunction)&wxMyPainterFrame::OnAbout);//*)//设置滚动选项ScrolledWindow1->SetScrollRate(10, 10);ScrolledWindow1->SetVirtualSize(500, 480);
}wxMyPainterFrame::~wxMyPainterFrame()
{RemoveAllItems();//(*Destroy(wxMyPainterFrame)//*)
}void wxMyPainterFrame::OnQuit(wxCommandEvent& event)
{Close();
}void wxMyPainterFrame::OnAbout(wxCommandEvent& event)
{wxString msg = wxbuildinfo(long_f);wxMessageBox(msg, _("Welcome to..."));
}IItem* wxMyPainterFrame::CreateNewItem()
{if(this->MenuItemLine->IsChecked())//小心,别写成IsCheckable(){return new LineItem();}return nullptr;
}void wxMyPainterFrame::RemoveAllItems()
{for(std::list<IItem*>::iterator it = _items.begin(); it != _items.end(); ++it){delete *it; //释放每个_newItem占据的内存}_items.clear(); //释放_items中元素(指向_newItem的指针)占据的内存
}void wxMyPainterFrame::OnScrolledWindow1LeftDown(wxMouseEvent& event)
{if(_newItem) return; //正在划线,返回_newItem = this->CreateNewItem();if(!_newItem) return;_newItem->OnDrawStart(ScrolledWindow1->CalcUnscrolledPosition(event.GetPosition()));
}void wxMyPainterFrame::OnScrolledWindow1MouseMove(wxMouseEvent& event)
{if(!_newItem) //不在绘画状态{return;//直接退出}_newItem->OnDrawEnd(//物理坐标转为逻辑坐标ScrolledWindow1->CalcUnscrolledPosition(event.GetPosition()));ScrolledWindow1->Refresh();
}void wxMyPainterFrame::OnScrolledWindow1LeftUp(wxMouseEvent& event)
{if(!_newItem) //不在绘画状态?{return;//直接退出}_newItem->OnDrawEnd(//物理坐标转为逻辑坐标ScrolledWindow1->CalcUnscrolledPosition(event.GetPosition()));_items.push_back(_newItem); //记录到列表中_newItem = nullptr; //结束绘画状态ScrolledWindow1->Refresh();
}
//将_items中的所有线都画出来
void wxMyPainterFrame::OnScrolledWindow1Paint(wxPaintEvent& event)
{wxPaintDC dc(ScrolledWindow1);//DoPrepareDC会自行调校ScrolledWindow1->DoPrepareDC(dc);//先画出list中的每一项for(std::list <IItem*> :: const_iterator it = _items.begin(); it != _items.end(); ++it){IItem const* item = *it;item->Draw(dc);}//如果刚巧用户正在画新项,把它也显示出来//否则用户只能“盲画”了if(_newItem){_newItem->Draw(dc);}
}

关键代码:

抽象出“图形元素”接口类

改造LineItem

改造外部使用环境

实现CreateNewItem()和RemoveAllItems()

实现鼠标按下,移动,抬起函数

实现作画函数

这篇关于第11章 GUI Page411~420 步骤五 支持其他图形的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/525073

相关文章

SpringBoot路径映射配置的实现步骤

《SpringBoot路径映射配置的实现步骤》本文介绍了如何在SpringBoot项目中配置路径映射,使得除static目录外的资源可被访问,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一... 目录SpringBoot路径映射补:springboot 配置虚拟路径映射 @RequestMapp

Python与MySQL实现数据库实时同步的详细步骤

《Python与MySQL实现数据库实时同步的详细步骤》在日常开发中,数据同步是一项常见的需求,本篇文章将使用Python和MySQL来实现数据库实时同步,我们将围绕数据变更捕获、数据处理和数据写入这... 目录前言摘要概述:数据同步方案1. 基本思路2. mysql Binlog 简介实现步骤与代码示例1

Linux搭建ftp服务器的步骤

《Linux搭建ftp服务器的步骤》本文给大家分享Linux搭建ftp服务器的步骤,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录ftp搭建1:下载vsftpd工具2:下载客户端工具3:进入配置文件目录vsftpd.conf配置文件4:

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

MySQL设置密码复杂度策略的完整步骤(附代码示例)

《MySQL设置密码复杂度策略的完整步骤(附代码示例)》MySQL密码策略还可能包括密码复杂度的检查,如是否要求密码包含大写字母、小写字母、数字和特殊字符等,:本文主要介绍MySQL设置密码复杂度... 目录前言1. 使用 validate_password 插件1.1 启用 validate_passwo

springboot整合mqtt的步骤示例详解

《springboot整合mqtt的步骤示例详解》MQTT(MessageQueuingTelemetryTransport)是一种轻量级的消息传输协议,适用于物联网设备之间的通信,本文介绍Sprin... 目录1、引入依赖包2、yml配置3、创建配置4、自定义注解6、使用示例使用场景:mqtt可用于消息发

Java实现TXT文件导入功能的详细步骤

《Java实现TXT文件导入功能的详细步骤》在实际开发中,很多应用场景需要将用户上传的TXT文件进行解析,并将文件中的数据导入到数据库或其他存储系统中,本文将演示如何用Java实现一个基本的TXT文件... 目录前言1. 项目需求分析2. 示例文件格式3. 实现步骤3.1. 准备数据库(假设使用 mysql

MySQL进行分片合并的实现步骤

《MySQL进行分片合并的实现步骤》分片合并是指在分布式数据库系统中,将不同分片上的查询结果进行整合,以获得完整的查询结果,下面就来具体介绍一下,感兴趣的可以了解一下... 目录环境准备项目依赖数据源配置分片上下文分片查询和合并代码实现1. 查询单条记录2. 跨分片查询和合并测试结论分片合并(Shardin

MySQL配置多主复制的实现步骤

《MySQL配置多主复制的实现步骤》多主复制是一种允许多个MySQL服务器同时接受写操作的复制方式,本文就来介绍一下MySQL配置多主复制的实现步骤,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 环境准备2. 配置每台服务器2.1 修改每台服务器的配置文件3. 安装和配置插件4. 启动组复制4.

nginx配置错误日志的实现步骤

《nginx配置错误日志的实现步骤》配置nginx代理过程中,如果出现错误,需要看日志,可以把nginx日志配置出来,以便快速定位日志问题,下面就来介绍一下nginx配置错误日志的实现步骤,感兴趣的可... 目录前言nginx配置错误日志总结前言在配置nginx代理过程中,如果出现错误,需要看日志,可以把