Nana C++ Library

Jinhao 2009-10-29 01:45:21
Nana C++ Library
版本: 0.1.9

简单来说,就是可以用这个来写界面代码。

网站:stdex.sourceforge.net
Hello, World

上图。。。。。。

有两个Demo,用Dev-C++编译,所以得到的文件有点大。

Demo 1, The FreeMe(有源码,bin目录下还有一个exe)


Demo 2, CodeShow(只有可执行程序)


Demo下载地址:http://download.csdn.net/source/1778461

欢迎大家来玩。。。
...全文
838 37 打赏 收藏 转发到动态 举报
写回复
用AI写文章
37 条回复
切换为时间正序
请发表友善的回复…
发表回复
zzhgb 2012-08-31
  • 打赏
  • 举报
回复
最新下载的始终配置不成功,哪里有中文的图文说明的
gaohoalianga 2012-02-03
  • 打赏
  • 举报
回复
如果能有一份详细的中文文档就好了!
HilerChen 2010-01-08
  • 打赏
  • 举报
回复
向楼主学习!
weworld 2010-01-08
  • 打赏
  • 举报
回复
正要发布的话,类名开始字母改为大写吧。用做GUI库的话,类名小写会很不习惯。
大写首字母的话,和变量名好区分,也很容易用using namespace引入库,写起来省力
masterz 2010-01-07
  • 打赏
  • 举报
回复
Java UI control也不支多线程,需要通过SwingUtilities invokeLater()or invokeAndWait() method来间接通知UI.http://java.sun.com/products/jfc/tsc/articles/threads/threads1.html
楼主可以考虑加入wxWidgets team.这个东西用的人多,而且也需要强人改善。
耍宝王 2010-01-06
  • 打赏
  • 举报
回复
国人牛物,搁置其它,优先学习

P.S 要是有中文手册就好了
sh9264 2010-01-06
  • 打赏
  • 举报
回复
不错!学习!
lgccaa 2009-11-12
  • 打赏
  • 举报
回复
mark

LZ牛
cpp_crab 2009-11-02
  • 打赏
  • 举报
回复

mark
zzw_happy 2009-11-02
  • 打赏
  • 举报
回复
lz真牛人啊。
这个nana我好像3年前看过,还在维护?
jin_yan 2009-10-31
  • 打赏
  • 举报
回复
开源的C++库要怎么推广呢,我也写过这种东西,没几个人用哦。
我也觉得UI库支持多线程,其必要性不大,复杂度太高了,我甚至怀疑系统提供的许多API是否本身就支持多线程。
Jinhao 2009-10-30
  • 打赏
  • 举报
回复
07年时候写的一篇关于实现控件的文,现在这个库和文中提到的有些东西有变化,不过思路都是没变的。

如何实现自己的控件

一. 介绍

本文将以nana::gui::button为例子来讲解如何实现一个控件及相关的基础知识。nana::gui::button是一个比较简单的控件,通过对它的讲解即可以涉及到基本的要素,又不会陷于复杂的概念,从而达到介绍的目的。nana::gui::button的实现分别在 include/nana/gui/widgets/button.hpp
和source/gui/widgets/button.cpp

Nana.GUI为实现控件提供了一个框架。一个完整的具有图形界面的控件由窗口操纵器和绘图触发器这两个部分来组成。所以实现一个控件,就需要实现这两部分。

1. 窗口操纵器
为客户代码提供操作控件的类,对客户代码来说,这是可见的。例如nana::gui::button就是控制器。

2. 绘图触发器
通过绘图触发器的事件回调来驱动绘图操作,这是提供给程序库内部的,对客户代码来说,这是不可见的。

在窗口操纵器和绘图触发器的整个生命期中,Nana.GUI不会去控制绘图触发器的创建与销毁。

二.实现

窗口操纵器

template<typename DrawerTrigger>
class basic_button: public widget_object<category::widget_tag>
{
public:
basic_button(){}
basic_button(nana::gui::widget& widget, int x, int y, unsigned width, unsigned height)
{
this->create(widget.handle(), x, y, width, height);
}
private:
drawer_trigger* get_drawer_trigger() //Important
{
btn_drawer_.set(*this);
return &btn_drawer_;
}
private:
DrawerTrigger btn_drawer_;
};




上面就是整个窗口操纵器的代码。

template<typename DrawerTrigger>


模板参数DrawerTrigger用来指定某种绘图触发器。
basic_button继承自widget_object <category::widget_tag>,其中的widget_tag表明这个button是一个Widget窗口(关于窗口类型的解释参见Nana.GUI)。尽管所有的控件都是派生自nana::gui::widget,但是控件都只能从widget_object <>这个类模板派生。
这个button声明了一个数据成员,btn_drawer_,换句话说,它直接把绘图触发器放置在窗口操纵器的内部。这也是目前程序库简单控件的通常做法。
默认构造函数不会创建这个控件,只有在调用create方法的时候,这个控件才有效,第二个构造函数直接调用了create来创建控件。如果一个控件在创建之前,有客户代码通过窗口操纵器操作了该控件,Nana保证在这个情况下,不会发生任何操作。
接下来的private成员函数很重要。


drawer_trigger* get_drawer_trigger()
{
btn_drawer_.set(*this);
return &btn_drawer_;
}

这个成员函数是nana::gui::widget类层次上的定义的一个接口。当一个控件在创建的时候,Nana.GUI内部会调用这个接口来获得绘图触发器。所有的绘图触发器都派生自nana::gui::drawer_trigger。
btn_drawer_.set(*this);这是给绘图触发器指定当前窗口操纵器。这个函数是自定义的,稍后在介绍这个button的绘图触发器的时候会详细说明。
return &btn_drawer_; 返回绘图触发器的地址。如果返回为空,则说明没有绘图触发器,这个控件也就不会有图形显示。

绘图触发器
绘图触发器比控制器要复杂得多,它会接收到用户的鼠标、键盘事件等等。在这个实现的button中,直接把绘制button的代码实现在绘图触发器中。先来浏览一遍绘图触发器的定义。一个绘图触发器的实现必须派生自drawer_trigger。


class button_drawer: public nana::gui::drawer_trigger
{
public:
button_trigger();
void set(nana::gui::widget&);
private:
void attached(paint::graphics&);
void detached();
void normal(paint::graphics&);
void mouse_leave(paint::graphics&, const eventinfo&);
void mouse_down(paint::graphics&, const eventinfo&);
void mouse_up(paint::graphics&, const eventinfo&);
void focus(paint::graphics&, const eventinfo&);
private:
void _m_draw_title(paint::graphics&, bool is_mouse_down, bool is_focus);
void _m_draw_background(paint::graphics&, bool is_mouse_down);
void _m_draw_border(paint::graphics&, bool is_mouse_down);
private:
nana::gui::widget* widget_;
bool is_ms_down_;
bool is_focus_;
};


button_drawer只有构造函数和set()是public,其余的都是private。
其中非_m_开头的private成员函数是drawer_trigger定义的虚函数,这些虚函数都由程序库内部调用,其中mouse_xxx就是用来响应鼠标操作。实现特定的功能需要重写这些函数。
以_m_开头的private成员函数是自定义的,封装了具体的绘图细节。不难想象,当有鼠标事件产生,则调用以_m_开头的成员函数去绘制窗口。
数据成员widget_保存着与该绘图触发器关联的窗口操纵器。is_ms_down_保存当前鼠标状态是不是被按下的。
现在来仔细看看非_m_开头的成员函数。


button_drawer::button_drawer()
:widget_(0), is_ms_down_(false), is_focus_(false)
{}

初始化数据成员。is_ms_down_将在mouse_down()和mouse_up()中设置状态,is_focus_将在focus()中设置状态。


void button_drawer::set(nana::gui::widget& widget)
{
if(widget_ == 0) widget_ = &widget;
}

设置widget_,这个函数在窗口操纵器的get_drawer_trigger调用的。
接下来的成员函数则是绘图触发器的重点。


void button_drawer::attached(nana::paint::graphics&)
{
using namespace nana::gui::API;
is_ms_down_ = false;
nana::gui::window window = widget_->handle();
make_drawer_event<events::mouse_leave>(window);
make_drawer_event<events::mouse_down>(window);
make_drawer_event<events::mouse_up>(window);
make_drawer_event<events::focus>(window);
}

在创建一个控件的时候,Nana.GUI负责将从窗口操纵器那里得来的绘图触发器附加到窗口管理器中,在此时会调用绘图控制器提供的attached方法,可以说attached是一个绘图触发器附加到窗口管理器中第一个被调用的方法。当绘图触发器被附加到窗口管理器中,它就和与其对应的窗口操纵器所创建的窗口建立了连接,这样窗口触发器才会接收到对应的事件回调。在这个成员函数里,button_drawer用与它相关的窗口操纵器的窗口句柄来注册事件。绘图触发器有专门的事件注册函数(与nana::gui::API::register_event和窗口操纵器提供的make_event不同,register_event和窗口操纵器提供的make_event是相同的),只有注册了对应的事件,Nana.GUI才会负责回调绘图触发器对应的函数。在这个函数里,只注册了mouse_leave(鼠标移出),mouse_down(鼠标按下)和mouse_up(释放鼠标按钮)的事件,当然,如果Button需要更多的特效,可以继续注册需要的事件。attached还有一个参数,引用的一个 nana::paint::graphics对象,这个对象就是该窗口的图形对象,对该对象绘制图形,最后都会表现在显示器上,该对象由 Nana.GUI负责创建和销毁,在attached函数里面,没有对该图形对象进行任何操作。


void button_drawer::detached()
{
nana::gui::API::unregister_drawer_event(widget_->handle());
}

当绘图触发器从窗口管理器中分离出来的时候,例如,控件被销毁,获该控件附加上其它的绘图触发器,Nana.GUI会回调与该窗口对应的绘图触发器的 detached方法。在这里,我们只需要注销掉刚才安装的事件。unregister_drawer_event负责注销掉指定窗口的所有绘图触发器安装的事件。


void button_drawer::normal(paint::graphics& ghc)
{
_m_draw_background(ghc, is_ms_down_);
_m_draw_border(ghc, is_ms_down_);
_m_draw_title(ghc, is_ms_down_, is_focus);
}

绘图触发器定义的normal方法会在窗口创建好之后调用,然后在调用nana::gui::API::refresh_window()的时候也会调用。在normal()里调用了以_m_开头的成员函数,这些都是对graphics对象进行操作。


void button_drawer::mouse_leave(paint::graphics& ghc, const eventinfo&)
{
_m_draw_background(ghc, false);
_m_draw_border(ghc, false);
_m_draw_title(ghc, false, is_focus_);
nana::gui::API::lazy_refresh();
}

当鼠标从控件上移开的时候,Nana.GUI会调用mouse_leave,其中第二个参数为事件信息(参见Nana事件处理中的解释),这里没有使用这个参数。这里值得注意的是,在mouse_leave()里调用了nana::gui::API::lazy_refresh(),这个函数的功能是,在所有的事件处理完成之后,把graphics对象显示到显示器上。lazy_refresh()只有在事件回调的程序里才会有作用,因此,在 normal()里面看不到这个函数的调用。
同理,mouse_down(),mouse_up()和focus()的回调处理和mouse_leave()是类似的。以_m_开头的成员函数的作用就是绘制graphics对象。具体的实现可以参考source/gui/widgets/button.cpp。关于 nana::paint::graphics可以参考Nana.Paint。
cxjddd 2009-10-30
  • 打赏
  • 举报
回复
五体投地的佩服
onemonth 2009-10-30
  • 打赏
  • 举报
回复
奶奶个熊,名字太搓了。换名字吧。
老邓 2009-10-29
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 jinhao 的回复:]
引用 18 楼 pcboyxhy 的回复:
界面看起来挺漂亮,是原生界面还是模拟主题?


全自画。
[/Quote]
强啊!内存占用控制的很好!!
Jinhao 2009-10-29
  • 打赏
  • 举报
回复
[Quote=引用 19 楼 chenyu2202863 的回复:]
牛牛~~

事件就需要Functor麽?
[/Quote]

恩。Functor可以把普通函数和成员函数都集合起来,这样事件里面就只为functor实现,而不必为普通函数和成员函数各实现一套。
Jinhao 2009-10-29
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 pcboyxhy 的回复:]
界面看起来挺漂亮,是原生界面还是模拟主题?
[/Quote]

全自画。
chenyu2202863 2009-10-29
  • 打赏
  • 举报
回复
楼主有6个马甲?
4个都有星星?
chenyu2202863 2009-10-29
  • 打赏
  • 举报
回复
牛牛~~

事件就需要Functor麽?
pcboyxhy 2009-10-29
  • 打赏
  • 举报
回复
界面看起来挺漂亮,是原生界面还是模拟主题?
加载更多回复(17)

24,855

社区成员

发帖
与我相关
我的任务
社区描述
C/C++ 工具平台和程序库
社区管理员
  • 工具平台和程序库社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧