1 wxWidget绘图基础
1.1 实现窗口
wxWidgets 窗口程序需要四个必须的部分: 1、添加一个继承wxApp 的应用程序类。 2、添加一个继承wxFrame 的框架类。 3、重载wxApp::OnInit() 成员函数,并在其中创建框架类的对象。 4、在调用宏定义IMPLEMENT_APP() 实例化应用程序。
#include <wx/wx.h>
#include <cstdlib>
class Tetris : public wxFrame {
public:
Tetris(const wxString &title)
:wxFrame(NULL, wxID_ANY, title) {}
}
1.2 实现面板
- 所有的绘制都在面板上。并且在框架中添加面板类。
1、添加一个继承wxPanel 的应用程序类。 2、在框架类的构造函数中创建面板类的对象。
class Board : public wxPanel {
public:
Board(wxFrame *parent): wxPanel(parent){
}
};
class Tetris : public wxFrame {
public:
Tetris(const wxString &title)
:wxFrame(NULL, wxID_ANY, title) {
Board *board = new Board(this);
}
};
1.3. 绘制事件
通常GUI程序绘制图像,是使用绘制事件通知的方式界面(面板)绘制的。这是一个经典的MVC模式。 一般在如下几种情况会触发绘制事件:
1、程序初始化界面显示。 2、窗口最小化后再重新出现。 3、窗口尺寸变化。 4、窗口被挡住后,重新出现。 5、代码调用Refresh() 或ReflashRect() 。 6、为了能够处理绘制事件,我们需要给它绑定一个绘制事件。
class Board : public wxPanel {
public:
Board(wxFrame *parent): wxPanel(parent){
Bind(wxEVT_PAINT, &Board::OnPaint,this);
}
void OnPaint(wxPaintEvent &event) {
}
};
其中,wxPaintEvent 是绘制事件类,它包含了一些绘制信息。wxEVT_PAINT 是绘制事件宏定义表示事件类型。
1.4 绘制原理
1.4.1 绘制图形
计算机绘制图像与人类画画有很多相似的地方。也需要画板、绘图工具(笔、刷子)。面板Panel 就是我们的画板,绘图工具在程序中被称为设备上下文(Device Context,简称DC)。DC提供了绘制各种图像的方法。
在wxWidgets 常用wxPaintDC 绘制图像。它可以绘制各种图像。例如:直线、矩形、
函数 | 功能 |
---|
void DrawPoint (const wxPoint &pt) | 画点(像素) | void DrawLine (const wxPoint &pt1, const wxPoint &pt2) | 画线 | void DrawRectangle (const wxPoint &pt, const wxSize &sz) | 画矩形 | void DrawPolygon (int n, const wxPoint points[]) | 画多边形 | void DrawCircle (const wxPoint &pt, wxCoord radius) | 画圆 | void DrawText (const wxString &text, const wxPoint &pt) | 绘制文本 |
说明: wxPoint 表示一个二维坐标的点,构造函数是wxPoint(int x,int y) 。 wxCoord 表示一个数字值,原型是整形int 。 wxSize 表示宽高,构造函数是wxPoint(int width,int height) 。
注意: 屏幕使用的坐标系被称为屏幕坐标系,默认的坐标原点在屏幕左上角。与我们数学中使用的笛卡尔坐标系是有区别的。 实例:
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
dc.DrawPoint(wxPoint(10, 10));
dc.DrawLine(wxPoint(15, 15), wxPoint(75, 75));
dc.DrawRectangle(wxPoint(80, 35),wxSize(50,45));
const wxPoint points[] = {
wxPoint(120,120),
wxPoint(120,160),
wxPoint(140,160)
};
dc.DrawPolygon(3,points);
dc.DrawCircle(wxPoint(280,100),80);
dc.DrawText(wxT("测试文字"), wxPoint(200, 160));
}
1.4.2 设置绘制
上面的图形都是黑线白底,线的宽度是1个像素,可以通过下面的方式修改。
函数 | 功能 |
---|
void SetPen (const wxPen &pen) | 设置画笔 | void SetBrush (const wxBrush &brush) | 设置画刷 | void SetFont (const wxFont &font) | 设置字体 |
实例:设置画笔
// 定义绘制函数
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
// 画点
dc.SetPen(*wxRED_PEN);
dc.DrawPoint(wxPoint(10, 10));
// 画线
dc.SetPen(*wxBLUE_PEN);
dc.DrawLine(wxPoint(15, 15), wxPoint(75, 75));
// 画矩形
dc.SetPen(*wxGREEN_PEN);
dc.DrawRectangle(wxPoint(80, 35),wxSize(50,45));
// 画多边形
const wxPoint points[] = {
wxPoint(120,120),
wxPoint(120,160),
wxPoint(140,160)
};
dc.SetPen(wxColour(255,255,0));
dc.DrawPolygon(3,points);
// 画圆
dc.SetPen(wxColour(59, 128, 59));
dc.DrawCircle(wxPoint(280,100),80);
// 画文字
dc.DrawText(wxT("测试文字"), wxPoint(200, 160));
}
颜色设置有两种方式: 1、使用内置的宏定义。例如:wxRED_PEN,wxGREEN_PEN,wxBLUE_PEN 等 2、使用wxColour 定义颜色,使用RGB 模型。 注:SetPen() 不能改变文字的颜色,需要下面的使用SetFont() 。
实例:设置字体
// 画文字
dc.SetTextForeground(wxColour(255,0 , 255)); // 设置字体颜色
dc.SetFont(wxFontInfo(12).Bold(2).FaceName(wxT("MS yahei"))); // 设置字体大小,粗细,字体
dc.DrawText(wxT("测试文字"), wxPoint(200, 160));
注:设置字体颜色要使用SetTextForeground()方法。
1.4.3 绘制图片
绘制图片需要用到如下两个函数:
函数 | 功能 |
---|
void wxInitAllImageHandlers() | 初始化图片处理器 | void DrawBitmap (const wxBitmap &bmp, const wxPoint &pt) | 绘制图片 |
实例:
// 绘制图片
wxInitAllImageHandlers();
dc.DrawBitmap(wxBitmap(wxT("logo.png"),wxBITMAP_TYPE_ANY),wxPoint(30,30));
1.5 鼠标事件
界面上的图像有一部分使用代码生成,也有一部分使用鼠标创建。添加鼠标事件方式与绘制事件一样。需要新建鼠标处理函数并且绑定到事件中。但是鼠标事件种类要比绘图事件多,常用的有如下几个。
事件 | 触发动作 |
---|
wxEVT_LEFT_DOWN | 鼠标左键按下 | wxEVT_LEFT_UP | 鼠标左键弹起 | wxEVT_LEFT_DCLICK | 鼠标左键双击 | wxEVT_MIDDLE_DOWN | 鼠标中键按下 | wxEVT_MIDDLE_UP | 鼠标中键弹起 | wxEVT_MIDDLE_DCLICK | 鼠标中键双击 | wxEVT_RIGHT_DOWN | 鼠标右键按下 | wxEVT_RIGHT_UP | 鼠标右键弹起 | wxEVT_RIGHT_DCLICK | 鼠标右键双击 | wxEVT_MOVE | 鼠标移动 |
实例:鼠标移动
#include <wx/wx.h>
class Move : public wxFrame {
public:
Move(const wxString& title): wxFrame(NULL, wxID_ANY, title) {
wxPanel* panel = new wxPanel(this, -1);
st1 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 10));
st2 = new wxStaticText(panel, -1, wxT(""), wxPoint(10, 30));
panel->Bind(wxEVT_MOTION,&Move::OnMove,this);
}
void OnMove(wxMouseEvent & event){
wxPoint size = event.GetPosition();
st1->SetLabel(wxString::Format(wxT("x: %d"), size.x ));
st2->SetLabel(wxString::Format(wxT("y: %d"), size.y ));
event.Skip();
Update();
}
private:
wxStaticText *st1;
wxStaticText *st2;
};
class MyApp : public wxApp {
public:
virtual bool OnInit(){
Move *move = new Move(wxT("Move event"));
move->Show(true);
return true;
}
};
IMPLEMENT_APP(MyApp)
实例2:鼠标画线
class Board : public wxPanel {
public:
Board(wxFrame *parent): wxPanel(parent){
// 绑定绘制事件
Bind(wxEVT_PAINT, &Board::OnPaint,this);
// 绑定鼠标事件
Bind(wxEVT_LEFT_DOWN, &Board::OnLeftDown,this);
Bind(wxEVT_LEFT_UP, &Board::OnLeftUp,this);
}
// 定义绘制函数
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
dc.DrawLine(startPos,endPos);
}
// 定义鼠标左键按下函数
void OnLeftDown(wxMouseEvent &event) {
startPos = event.GetPosition();
Refresh();
}
// 定义鼠标右键弹起函数
void OnLeftUp(wxMouseEvent &event) {
endPos = event.GetPosition();
Refresh();
}
private:
wxPoint startPos;
wxPoint endPos;
};
注:在wxMouseEvent 中包含了一个很重要的信息–事件出发时鼠标的位置。可以通过调用事件的方法GetPosition() 获取。
1.6 键盘事件
class Board : public wxPanel {
public:
Board(wxFrame *parent): wxPanel(parent){
// 绑定绘制事件
Bind(wxEVT_PAINT, &Board::OnPaint,this);
// 绑定键盘事件
Bind(wxEVT_KEY_DOWN,&Board::OnKeyDown,this);
startPos = wxPoint(10,10);
endPos = wxPoint(50,50);
}
// 定义绘制函数
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
dc.DrawLine(startPos,endPos);
}
void OnKeyDown(wxKeyEvent &event) {
case WXK_RIGHT:
startPos.x += 10;
endPos.x += 10;
break;
case WXK_LEFT:
startPos.x -= 10;
endPos.x -= 10;
break;
case WXK_UP:
startPos.y -= 10;
endPos.y -= 10;
break;
case WXK_DOWN:
startPos.y += 10;
endPos.y += 10;
break;
default:
break;
}
Refresh();
}
private:
wxPoint startPos;
wxPoint endPos;
};
1.7 定时器事件
class Board : public wxPanel {
public:
Board(wxFrame *parent): wxPanel(parent){
// 绑定绘制事件
Bind(wxEVT_PAINT, &Board::OnPaint,this);
// 绑定事件
Bind(wxEVT_TIMER,&Board::OnTimer,this);
startPos = wxPoint(150,50);
endPos = wxPoint(50,50);
timer = new wxTimer(this,wxID_ANY);
timer->Start(1000);
}
// 定义绘制函数
void OnPaint(wxPaintEvent &event) {
wxPaintDC dc(this);
dc.DrawLine(startPos,endPos);
}
void OnTimer(wxTimerEvent &event) {
static int i = 0;
i++;
i%=60;
double angle = M_PI/30*i;
startPos = endPos + wxPoint(100*cos(angle),100*sin(angle));
Refresh();
}
private:
wxPoint startPos;
wxPoint endPos;
wxTimer* timer;
};
实例:
#include <wx/wx.h>
#include <vector>
using namespace std;
//面板类
class SimplePanel:public wxPanel{
//vector<wxPoint> vec;
vector<pair<wxPoint,wxPoint>> lines;
wxPoint startPoint,endPoint;
bool draw = false;
public:
SimplePanel(wxFrame* pframe):wxPanel(pframe){
//将面板与绘图绑定
Bind(wxEVT_PAINT,&SimplePanel::OnPaint,this);
Bind(wxEVT_MOTION,&SimplePanel::OnMove,this);
Bind(wxEVT_LEFT_DOWN,&SimplePanel::OnLeftDown,this);
Bind(wxEVT_LEFT_UP,&SimplePanel::OnLeftUp,this);
}
void OnLeftDown(wxMouseEvent& event){
draw = true;
startPoint = event.GetPosition();
}
void OnLeftUp(wxMouseEvent& event){
endPoint = event.GetPosition();
lines.push_back({startPoint,endPoint});
draw = false;
Refresh();
}
void OnMove(wxMouseEvent& event){
endPoint = event.GetPosition();
Refresh();
}
void OnPaint(wxPaintEvent&){
//定义画笔
wxPaintDC dc(this);
//设置画笔颜色
dc.SetPen(*wxRED_PEN);
//设置填充颜色
dc.SetBrush(*wxBLUE_BRUSH);
dc.DrawLine(wxPoint(0,0),wxPoint(100,100));
dc.DrawCircle(wxPoint(100,100),50);
dc.SetPen(*wxYELLOW_PEN);
dc.SetBrush(*wxGREEN_BRUSH);
dc.DrawRectangle(wxPoint(100,100),wxSize(200,300));
//设置文字前景色
dc.SetTextForeground(*wxRED);
dc.DrawText("Text",wxPoint(100,100));
for(auto [s,e]:lines){
dc.DrawLine(s,e);
}
if(draw) dc.DrawLine(startPoint,endPoint);
}
};
//框架类
//框架类中添加面板类
class SimpleFrame:public wxFrame{
public:
SimpleFrame(const char* title):wxFrame(nullptr,wxID_ANY,title){
wxPanel* p = new SimplePanel(this);
}
};
//应用程序类
//应用程序类中添加框架类
class SimpleApp:public wxApp{
public:
bool OnInit()override{
SimpleFrame* pframe = new SimpleFrame("Name");
pframe->Show();
return true;
};
};
wxIMPLEMENT_APP(SimpleApp);
|