运行效果:
一 源代码:
//item_line.hpp
#ifndef ITEM_LINE_HPP_INCLUDED
#define ITEM_LINE_HPP_INCLUDED
#include <wx/gdicmn.h>
#include <wx/dc.h>
class LineItem
{
public:
LineItem()
: _startPosition(0, 0), _endPosition(0, 0)
{
}
void SetStartPosition(wxPoint const& point);
void SetEndPosition(wxPoint const& point);
wxPoint const& GetStartPosition() const
{
return _startPosition;
}
wxPoint const& GetEndPosition() const
{
return _endPosition;
}
private:
//不写Logic后缀,但仍然是存储逻辑坐标
wxPoint _startPosition, _endPosition;
};
#endif // ITEM_LINE_HPP_INCLUDED
//item_line.cpp
#include "item_line.hpp"
void LineItem::SetStartPosition(wxPoint const& point)
{
this->_startPosition = point;
}
void LineItem::SetEndPosition(wxPoint const& point)
{
this->_endPosition = point;
}
/***************************************************************
* 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_line.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 idMenuAbout;
static const long ID_STATUSBAR1;
//*)
//(*Declarations(wxMyPainterFrame)
wxScrolledWindow* ScrolledWindow1;
wxStatusBar* StatusBar1;
wxListBox* ListBox1;
//*)
private:
void RemoveAllItems();
/*每当用户鼠标按下,就创建一个新的_newItem,等画完之后(鼠标抬起),
就将它加入“_items”列表中。这也解释了为什么不需要“_drawing”这个标志,
因为当“_newItem”不为空,就说明用户正在画新的线。OnPaint事件的思路配套调整
为:每次都画出“_items”中的所有元素;然后如果“_newItem”不为空,则把用户正在
拖拽的线也画出来。*/
LineItem* _newItem;
std::list <LineItem*> _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>
//(*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::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* MenuItem2;
wxMenuItem* MenuItem1;
wxMenu* Menu1;
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();
MenuItem1 = new wxMenuItem(Menu1, idMenuQuit, _("Quit\tAlt-F4"), _("Quit the application"), wxITEM_NORMAL);
Menu1->Append(MenuItem1);
MenuBar1->Append(Menu1, _("&File"));
Menu2 = new wxMenu();
MenuItem2 = new wxMenuItem(Menu2, idMenuAbout, _("About\tF1"), _("Show info about this application"), wxITEM_NORMAL);
Menu2->Append(MenuItem2);
MenuBar1->Append(Menu2, _("Help"));
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..."));
}
void wxMyPainterFrame::RemoveAllItems()
{
for(std::list<LineItem*>::iterator it = _items.begin()
; it != _items.end(); ++it)
{
delete *it; //释放每个_newItem占据的内存
}
_items.clear(); //释放_items中元素(指向_newItem的指针)占据的内存
}
void wxMyPainterFrame::OnScrolledWindow1LeftDown(wxMouseEvent& event)
{
if(_newItem)//逻辑别搞反
{
return; //正在划线,返回
}
_newItem = new LineItem();
_newItem->SetStartPosition(
ScrolledWindow1->CalcUnscrolledPosition(event.GetPosition()));
}
void wxMyPainterFrame::OnScrolledWindow1MouseMove(wxMouseEvent& event)
{
if(!_newItem) //不在绘画状态
{
return;//直接退出
}
_newItem->SetEndPosition(//物理坐标转为逻辑坐标
ScrolledWindow1->CalcUnscrolledPosition(event.GetPosition()));
ScrolledWindow1->Refresh();
}
void wxMyPainterFrame::OnScrolledWindow1LeftUp(wxMouseEvent& event)
{
if(!_newItem) //不在绘画状态?
{
return;//直接退出
}
_newItem->SetEndPosition(//物理坐标转为逻辑坐标
ScrolledWindow1->CalcUnscrolledPosition(event.GetPosition()));
_items.push_back(_newItem); //记录到列表中
_newItem = nullptr; //结束绘画状态
ScrolledWindow1->Refresh();
}
//将_items中的所有线都画出来
void wxMyPainterFrame::OnScrolledWindow1Paint(wxPaintEvent& event)
{
wxPaintDC dc(ScrolledWindow1);
//先画出list中的每一条线
for(std::list <LineItem*> :: const_iterator it = _items.begin()
; it != _items.end(); ++it)
{
LineItem const* item = *it;
//逻辑坐标转为物理坐标
wxPoint startPostion = ScrolledWindow1->CalcScrolledPosition(
item->GetStartPosition());
wxPoint endPosition = ScrolledWindow1->CalcScrolledPosition(
item->GetEndPosition());
dc.DrawLine(startPostion, endPosition);
}
//如果刚巧用户正在画新线,把它也显示出来
//否则用户只能“盲画”了
if(_newItem)
{
wxPoint startPosition = ScrolledWindow1->CalcScrolledPosition(
_newItem->GetStartPosition());
wxPoint endPosition = ScrolledWindow1->CalcScrolledPosition(
_newItem->GetEndPosition());
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;
}
二 关键代码:
添加item_line.hpp
添加item_line.cpp
添加一个私有成员函数和两个私有成员
wxMyPainterMain.h头文件,wxMyPaiterFram类中添加成员函数和成员变量
void RemoveAllItems
LineItem* _newItem;
std::list <LineItem*> _items;
原来的_startPositionLogical, _currentPositionLogical,以及 _drawing成员,全都不需要了,改成
并初始化为:
实现清理图元的函数,并由析构函数调用。