wxWidgets 自绘窗口

前言

​ 目前很多应用程序界面的标题栏都是自绘的,wxWidgets如果想要达到360安全卫士那种效果就需要重新定义一个Frame。

自绘Frame窗口

​ 首先定义一个自定类,这个类继承wxFrame,在里面重写wxFrame:

头文件如下:

#ifndef WXSKINXFRAME_H
#define WXSKINXFRAME_H
#include <wx/wx.h>
#include <wx/image.h>

class wxSkinXFrame : public wxFrame
{
    //构造、析构、初始化
    public:
        wxSkinXFrame();
        wxSkinXFrame(wxWindow* parent,
                    wxWindowID id,
                    const wxPoint& pos = wxDefaultPosition,
                    const wxSize& size = wxDefaultSize,
                    long style = wxNO_BORDER|wxFRAME_SHAPED, //自绘一般默认为无边框
                    const wxString& name = wxFrameNameStr);
        void Create(wxWindow *parent,
					wxWindowID id,
					const wxPoint& pos = wxDefaultPosition,
                    const wxSize& size = wxDefaultSize,
                    long style = wxNO_BORDER|wxFRAME_SHAPED,//自绘一般默认为无边框
                    const wxString& name = wxFrameNameStr);
		void Init();
		~wxSkinXFrame();
    public:
        //设置皮肤
        //
        void SetShapeImage(const wxImage& skin){image_shape = skin;ReSetShape();}
        void SetNormalImage(const wxImage& skin){image_normal = skin;Refresh();}
        void SetOverImage(const wxImage& skin){image_over = skin;Refresh();};
		void SetDisableImage(const wxImage& skin){image_disable = skin;Refresh();};
    public:
        //设置窗口形状
        bool SetShape(const wxImage& img);
    protected:
        void OnErase(wxEraseEvent& e){};//擦除函数
        void OnPaint(wxPaintEvent& e);//绘制函数
        void OnSize(wxSizeEvent& e);//当窗口大小发生改变的时候
        void OnEnterWindow(wxMouseEvent& event);//鼠标进入窗口的时候
        void OnLeaveWindow(wxMouseEvent& event);//鼠标离开窗口的时候
    protected:
        void ReSetShape();
    protected:
        //关于移动窗口的函数
        void OnMotion(wxMouseEvent& event);
		void OnLeftDown(wxMouseEvent& event);
		void OnLeftUp(wxMouseEvent& event);
		void OnMouseLost(wxMouseCaptureLostEvent& event);
    private:
         wxImage image_shape; //窗口形状
        wxImage image_normal; // 窗口皮肤
        wxImage image_over;//鼠标在窗口上面的皮肤
		wxImage image_disable;//窗口被禁用后的皮肤

        bool m_bInside;//鼠标是否在窗口里面

        wxPoint m_offset;//偏移坐标
        wxRect m_rect;
    private:
        //将类加入到RTTI中
        DECLARE_DYNAMIC_CLASS(wxSkinXFrame)
        //定义事件表
        DECLARE_EVENT_TABLE()
};

#endif // WXSKINXFRAME_H

实现文件如下:

#include "wxSkinXFrame.h"
#include <wx/dcbuffer.h>
IMPLEMENT_DYNAMIC_CLASS(wxSkinXFrame,wxFrame)

BEGIN_EVENT_TABLE(wxSkinXFrame,wxFrame)
    //关联擦除背景函数
    EVT_ERASE_BACKGROUND(wxSkinXFrame::OnErase)
    //关联绘制函数
    EVT_PAINT(wxSkinXFrame::OnPaint)
    //关联窗口大小发生改变函数
    EVT_SIZE(wxSkinXFrame::OnSize)
    //关联鼠标进入窗口函数
    EVT_ENTER_WINDOW(wxSkinXFrame::OnEnterWindow)
    //关联鼠标离开窗口函数
	EVT_LEAVE_WINDOW(wxSkinXFrame::OnLeaveWindow)
    //鼠标移动事件
    EVT_LEFT_DOWN(wxSkinXFrame::OnLeftDown)
	EVT_LEFT_UP(wxSkinXFrame::OnLeftUp)
	EVT_MOUSE_CAPTURE_LOST(wxSkinXFrame::OnMouseLost)
	EVT_MOTION(wxSkinXFrame::OnMotion)
END_EVENT_TABLE()
wxSkinXFrame::wxSkinXFrame()
{
     Init();
}
wxSkinXFrame::wxSkinXFrame(wxWindow* parent,
            wxWindowID id,
            const wxPoint& pos,
            const wxSize& size,
            long style,
            const wxString& name)
{
     Init();
    Create(parent,id,pos,size,style,name);
}
void wxSkinXFrame::Create(wxWindow *parent,
            wxWindowID id,
            const wxPoint& pos,
            const wxSize& size,
            long style,
            const wxString& name)
{
    wxFrame::Create(parent,id,"",pos,size,style,name);
}
void wxSkinXFrame::Init()
{
    m_bInside = false;

    m_rect = wxRect(0,0,0,0);
	m_offset = wxPoint(-1,-1);
}
wxSkinXFrame::~wxSkinXFrame()
{

}


bool wxSkinXFrame::SetShape(const wxImage& img)
{
    wxImage m = img;
    if(m.HasAlpha())
    {
        m.ConvertAlphaToMask();
    }
    return wxNonOwnedWindow::SetShape(wxRegion(m));
}
void wxSkinXFrame::OnPaint(wxPaintEvent& e)
{
     //如果窗体长宽有一个为0,则不进行绘制
	int w, h;
	GetSize(&w,&h);
	if(w == 0 || h == 0)
	{
		return;
	}
	//使用双缓冲绘图,防止闪烁
    wxBufferedPaintDC dcp(this);
    //清除背景
    dcp.SetBrush(*wxTRANSPARENT_BRUSH);
    dcp.Clear();
    //在窗口上绘制图片,默认都是按照窗体大小进行等比例绘制
    if(m_bInside && image_over.IsOk())
    {
        //当鼠标在窗口里面的时候
        dcp.DrawBitmap(wxBitmap(image_over.Scale(w, h)),0,0,true);
    }
    else if(IsEnabled() && image_normal.IsOk())
    {
        //当窗口不属于禁用状态并且有正常的皮肤图片时
        dcp.DrawBitmap(wxBitmap(image_normal.Scale(w, h)),0,0,true);
    }
    else if(!IsEnabled() && image_disable.IsOk() )
    {
        //当窗口处于禁用状态时
        dcp.DrawBitmap(wxBitmap(image_disable.Scale(w, h)),0,0,true);
    }else if(image_normal.IsOk())
    {
        //当窗口不属于上面几种条件时,默认绘制正常的皮肤图片
        dcp.DrawBitmap(wxBitmap(image_normal.Scale(w, h)),0,0,true);
    }

}
void wxSkinXFrame::OnSize(wxSizeEvent& e)
{
    ReSetShape();
}
void wxSkinXFrame::OnEnterWindow(wxMouseEvent& event)
{
    m_bInside = true;
	if(image_over.IsOk())
	{
		Refresh();
	}
}
void wxSkinXFrame::OnLeaveWindow(wxMouseEvent& event)
{
    m_bInside = false;
	Refresh();
	//鼠标拖动事件,当鼠标离开窗口时,发送信号告诉窗口
	//这个是为了解决拖动速度过快导致窗口没有跟踪上鼠标
	bool isDown = event.LeftIsDown();
	bool isDragging = event.Dragging();
	if(isDown && isDragging)
	{
		wxCommandEvent ev(wxEVT_MOTION, GetId());
		ev.SetEventObject(this);
    	GetEventHandler()->ProcessEvent(ev);
	}
}
//鼠标移动的时候
void wxSkinXFrame::OnMotion(wxMouseEvent& event)
{
    wxPoint pt = event.GetPosition();
	bool isDown = event.LeftIsDown();

	if (isDown && event.Dragging() && HasCapture())
	{

		wxPoint mouse_pos = ClientToScreen(pt);

		if(m_offset.x != -1)
		{
			wxPoint dp = mouse_pos - m_offset;
			this->Move(dp);
		}

	}
}
//鼠标左键按下的时候
void wxSkinXFrame::OnLeftDown(wxMouseEvent& event)
{
    // 当前鼠标的屏幕坐标
	wxPoint pt = event.GetPosition();

	if(!HasCapture() && !m_rect.Contains(pt))
	{
		CaptureMouse();
	}

	wxPoint mouse_pos = ClientToScreen(pt);


	// 当前主窗口的屏幕坐标
	wxPoint wnd_pos = this->GetPosition();

	// 计算鼠标的坐标点到窗口左上角的偏移量
	m_offset.x = mouse_pos.x - wnd_pos.x;
	m_offset.y = mouse_pos.y - wnd_pos.y;


}
//鼠标左键松开的时候
void wxSkinXFrame::OnLeftUp(wxMouseEvent& event)
{
    m_offset = wxPoint(-1,-1);
	if (HasCapture()) ReleaseMouse();
}
//鼠标丢失的时候
void wxSkinXFrame::OnMouseLost(wxMouseCaptureLostEvent& event)
{
    m_offset = wxPoint(-1,-1);
	if (HasCapture()) ReleaseMouse();
}



void wxSkinXFrame::ReSetShape()
{
        if(image_shape.IsOk())
        {
                //当窗口大小改变是可以改变窗口的形状
                int w, h;
                GetSize(&w,&h);
                if(w != 0 && h != 0)
				{
					SetShape(image_shape.Scale(w,h));
				}
        }

    Layout();
    Refresh();
}

这个窗口并没有绘制最小化按钮和最大化按钮以及关闭按钮,简单的显示一个皮肤界面,下面是调用的示例:

wxInitAllImageHandlers();
wxSkinXFrame* f = new wxSkinXFrame(NULL,wxID_ANY);
//设置窗口皮肤
f->SetNormalImage(wxImage("normal.jpg"));
f->SetShapeImage(wxImage("shape.png"));
f->SetOverImage(wxImage("over.jpg"));
f->SetDisableImage(wxImage("disable.jpg"));
f->SetSize(800,600);
f->Center();

f->Show();

接下来用动态图演示效果:

在这里插入图片描述

总结

​ 自绘窗口有两个关键点,一个是在客户区绘制皮肤,另一个是处理鼠标拖拽事件。其余标题栏的控件可以根据项目需求来排列组合。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
在使用wxWidgets创建的窗口嵌入到GTK创建的独立顶级窗口时,你可以使用`wxGTKPlugin`类来实现。下面是一个简单的示例代码: ```cpp #include <wx/wx.h> #include <wx/gtk/embed.h> class MyEmbeddedWindow : public wxFrame { public: MyEmbeddedWindow(wxWindow* parent) : wxFrame(parent, wxID_ANY, "嵌入窗口示例") { // 在这里添加子窗口的内容和布局 wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL); sizer->Add(new wxButton(this, wxID_ANY, "按钮"), 0, wxALIGN_CENTER); SetSizer(sizer); } }; class MyParentWindow : public wxFrame { public: MyParentWindow() : wxFrame(NULL, wxID_ANY, "父窗口示例") { // 在这里创建父窗口和布局 GtkPlug* plug = gtk_plug_new(0); GtkWidget* plugWidget = GTK_WIDGET(plug); GtkWidget* parentWidget = GetHandle(); gtk_container_add(GTK_CONTAINER(parentWidget), plugWidget); MyEmbeddedWindow* embeddedWindow = new MyEmbeddedWindow(plugWidget); embeddedWindow->Show(); } }; class MyApp : public wxApp { public: virtual bool OnInit() { MyParentWindow* mainWindow = new MyParentWindow(); mainWindow->Show(); return true; } }; wxIMPLEMENT_APP(MyApp); ``` 在上面的示例中,我们使用了`GtkPlug`类型的对象来实现嵌入。首先,我们创建了一个`GtkPlug`对象并将其添加到GTK创建的顶级窗口中。然后,我们将`GtkPlug`对象的句柄传递给wxWidgets创建的子窗口,从而实现了窗口的嵌入。 通过这种方式,你可以在GTK创建的独立顶级窗口中嵌入使用wxWidgets创建的子窗口。请注意,这里使用了GTK的特定函数和类型,所以需要包含相应的头文件,并确保程序正确链接到GTK库。另外,这只是一个简单的示例,实际应用中可能需要更多的处理和布局操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值