第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()
{
    //(*AppInitialize
    bool 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_UNICODE
        wxbuild << _T("-Unicode build");
#else
        wxbuild << _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()

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

实现作画函数

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/263540.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

linux静态ip配置方法(vmware虚拟机)

1、背景 自己搭建了一个虚拟机&#xff0c;vmware虚拟机&#xff0c;如果使用动态ip,经常变换地址&#xff0c;登录不方便。 优点&#xff1a; 静态网络配置的好处是该服务器地址是静态ip的&#xff0c;不会随着网络更换而出现波动。 2、配置方法 2.1 进入centos系统&#…

算法与数据结构--散列表与哈希算法

引入 我们知道c的set和unorder_set&#xff08;map本质上也是set&#xff0c;就是把set的存储对象换成键值对结构体&#xff09;&#xff0c;set底层是红黑树实现的&#xff0c;那么unorder_set是怎么实现的呢&#xff1f;这一节就来讲讲实现unorder_set的哈希表&#xff0c;也…

量化交易学习笔记:XGBoost 在量化选股中的应用

一、引言 本篇文章通过借鉴传统机器学习算法——XGBoost——对相同的量价因子进行实验&#xff0c;方便与深度学习模型进行对比实践。 二、算法介绍 XGBoost 是在 Gradient Boosting&#xff08;梯度提升&#xff09;框架下实现的机器学习算法&#xff0c;全称为“极限梯度提…

css 实现满屏升空的气球动画

问题一 怎么实现满屏气球&#xff1f;简单理解就是多个气球的合并&#xff0c;难道要写多个盒子吗&#xff1f;确实是这样子&#xff0c;但可以有更好的办法&#xff0c;其实就是通过原生操作多个盒子生成&#xff0c;所以只需要实现一个颜色、大小、位置可自定义的气球即可。…

AngularJS

理解实现代码的逻辑为主要&#xff0c;代码怎么写为次要。 参考资料&#xff1a; 《AngularJS入门与进阶》&#xff0c;江荣波著 前端开发常用框架 React&#xff1a;由Facebook开发&#xff0c;用于构建用户界面的JavaScript库&#xff0c;以组件化和虚拟DOM著称。 Angular&…

牦牛角划破眼睑,幼儿紧急就医抢救眼睛

前几天深夜&#xff0c;成都爱尔眼科医院收治了一位患儿&#xff0c;年仅2岁&#xff0c;被父亲抱在怀中与邻居一起从西藏来到成都。因孩子父亲无法用普通话交流&#xff0c;医生从邻居口中了解孩子无意间右眼被牦牛角击中眼皮断裂了。在当地医院接受检查&#xff0c;但无法实施…

锐捷配置PVLAN

一、实验拓扑 二、实验目的 PVLAN可以通过主VLAN和辅助VLAN的概念&#xff0c;部署隔离技术&#xff0c;实现用户间的互访控制。 三、实验配置 SW2 Ruijie >enable Ruijie #configure terminal Ruijie (config)#vlan 20 Ruijie (config-vlan)#private-vlan community …

4.使用 Blazor 构建 Web 应用程序

微软官方培训 了解如何通过 Blazor Web 用户界面框架构建你的第一个 Web 应用程序。 https://learn.microsoft.com/zh-cn/training/paths/build-web-apps-with-blazor/?viewaspnetcore-8.0 8个模块 目录 微软官方培训 1.使用 Blazor 进行 Web 开发的简介 2.使用 Blazor…

【网络技术】BGP 基础与概述

该笔记主要作用与 BGP 路由协议的基础和概述讲解&#xff0c;其萌芽作用 参考视频&#xff1a;红茶三杯 关键词阐述&#xff1a;AS 独立自治网络系统机构 前置知识 在我们学习 BGP 路由之前所学习的所有动态路由策略&#xff0c;都同属一个路由类中&#xff1a;IGP BGP 路由协…

为什么越来越多公司开始用低代码开发?

时代洪流的走向&#xff0c;我们无法左右&#xff0c;能够把握的&#xff0c;只有做好自己。如何在寒冬来之不易的机会中&#xff0c;生存并且壮大。 不知道大家有没有发现&#xff0c;今年的低代码赛道异常火热&#xff0c;但火热的背后才值得思考&#xff0c;市场需求持续被挖…

信号与线性系统翻转课堂笔记7——信号正交与傅里叶级数

信号与线性系统翻转课堂笔记7——信号正交与傅里叶级数 The Flipped Classroom7 of Signals and Linear Systems 对应教材&#xff1a;《信号与线性系统分析&#xff08;第五版&#xff09;》高等教育出版社&#xff0c;吴大正著 一、要点 &#xff08;1&#xff0c;重点&a…

音视频类App广告变现如何破局,最大化广告变现收益,让应用增收?

音视频App已然成为了我们日常获取、发布和交换信息的重要方式&#xff0c;在音视频行业不断的拓展中&#xff0c;用户的渗透率提升。 据数据显示&#xff0c;我国网络视听用户的规模已达9亿人次&#xff0c;网民使用率也突破了90%。庞大的市场规模和用户需求吸引了大批开发者和…

[已解决] Ubuntu远程桌面闪退+登录显示“远程桌面由于数据加密错误 , 这个会话将结束“

两个月前&#xff0c;由于跑代码在Ubuntu配置环境&#xff0c;乱七八糟的下载了很多东西&#xff0c;导致了一系列问题..... 问题1 Ubuntu远程桌面闪退 实验室有两台服务器&#xff0c;IP后三位分别为141和142&#xff0c;其中141在输入密码后立即闪退&#xff0c;142可以正常…

Open3D点云处理简明教程

推荐&#xff1a;用NSDT编辑器快速搭建可编程3D场景 这是“激光雷达入门”文章的延续。 在这篇文章中&#xff0c;我们将查看用于处理点云的 python 库和 Open3D 数据结构&#xff0c;执行可视化并操作点云数据&#xff0c;以便进行后续的分析处理。 如果你需要快速预览3D点云…

不明觉厉,Meta宣布了Fairy——快速并行指令引导视频到视频合成

Meta 刚刚宣布了Fairy——一项快速并行指令引导视频到视频合成的创新技术。这一引入图像编辑扩散模型的简约而强大的改进&#xff0c;极大地增强了其视频编辑应用程序的性能。 他们的方法聚焦于基于锚的跨帧注意力的概念&#xff0c;这是一种隐式跨帧传播扩散特征的机制&#…

Ninja H2 HySE川崎的氢能增压摩托车真的来了,像在开火箭?

川崎最近发布了第一款氢能源的摩托车&#xff0c;而HySE则是日本四大厂&#xff08;本田、雅马哈、川崎、铃木&#xff09;联合丰田针对氢作为燃料的动力研发机构&#xff0c;值得一提的是这H2仍然采用的999cc直喷增压发动机&#xff0c;具体的动力数据暂时没有曝光。 车辆后方…

Python Selenium中的强大等待设置详解

更多资料获取 &#x1f4da; 个人网站&#xff1a;ipengtao.com 在Web自动化测试中&#xff0c;等待是至关重要的一环&#xff0c;而Selenium提供了丰富的等待设置来确保测试脚本的可靠性和稳定性。本文将深入研究Python Selenium中常用的必备等待设置&#xff0c;包括显式等待…

2023.12.19 关于 Redis 通用全局命令

目录 引言 Redis 全局命令 SET & GET KEYS EXISTS DEL EXPIRE TTL TYPE redis 引入定时器高效处理过期 key 基于优先级队列方式 基于时间轮方式 引言 Redis 是根据键值对的方式存储数据的必须要进入 redis-cli 客户端程序 才能输入 redis 命令 Redis 全局命令 R…

antdv中的slider组件会默认将min值传递给value

如果是使用响应式变量&#xff0c;会将min的值传递到v-model对应的变量里

VPN理论入门及GRE、L2TP、IPsec(HCIP)

一、VPN概述 IPsec-VPN&#xff1a; 1、应用范围&#xff1a;用于分公司和总部之间。 2、作用&#xff1a;机密性、证书&#xff08;身份认证&#xff09; VPN概述 VPN概述&#xff1a;VPN&#xff08;Virtual Private Network&#xff09;是指依靠Internet服务提供商ISP&a…