


























#include <nana/gui.hpp> // always include this
#include <nana/gui/widgets/button.hpp>
#include <nana/gui/widgets/group.hpp>
#include <nana/gui/widgets/label.hpp>
#include <nana/gui/msgbox.hpp>
int main()
{
using namespace nana;
form fm; // Our main window
fm.caption("My first NANA demo"); // (with this title)
place fm_place{ fm }; // have automatic layout
bool really_quick{ false }; // and a default behavior
label hello{ fm,"Hello World" }; // We put a label on our window
button btn{ fm,"Quit" }; // and a button
btn.tooltip("I will ask first"); // that show a tip upon mouse hover
group act{ fm, "Actions" }; // Add a group of "options"
act.add_option("Quick quickly") // and two options that control quick behavior
.events().click([&]() { really_quick = true;
btn.tooltip("Quick quickly"); });
act.add_option("Ask first")
.events().click([&]() { really_quick = false;
btn.tooltip("I will ask first"); });
btn.events().click([&]() // now the button know how to respond
{
if (!really_quick) // not really quick !
{
msgbox m(fm, "Our demo", msgbox::yes_no);
m.icon(m.icon_question);
m << "Are you sure you want to quick?";
auto response = m();
if (response != m.pick_yes) return; // return to the demo
}
API::exit(); // or really quick
});
act.radio_mode(true); // Set "radio mode" (only one option selected)
// let divide fm into fields to holds the other controls.
// for example, let split fm into two fields separated by a movable vertical barre.
fm_place.div("vertical <label margin=10>|70% <actions>");
fm_place["label"] << hello << btn; // and place the controls there
fm_place["actions"] << act;
fm_place.collocate(); // and collocate all in place
fm.show();
exec();
}
在上述代码中,关于 click 事件的代码中,有一段调用对话框函数 msgbox 的调用方法,表达了 nana 的设计风格。
btn.events().click([&]() // now the button know how to respond
{
if (!really_quick) // not really quick !
{
msgbox m(fm, "Our demo", msgbox::yes_no);
m.icon(m.icon_question);
m << "Are you sure you want to quick?";
auto response = m();
if (response != m.pick_yes) return; // return to the demo
}
API::exit(); // or really quick
});
m() 时,到底发生什么?m() 在这里表示执行并弹出对话框。
在 C++ 中,这种写法利用了运算符重载(Operator Overloading),具体来说是重载了**函数调用运算符 ()**(也称为重载 operator())。
彻底地理解这几行代码,我们可以把它拆解开来看:
m() 背后发生了什么?当你创建了一个 msgbox 对象 m 并设置好它的各种属性(如标题、图标、文本)后,它只是一个存在于内存中的对象,并没有真正显示在屏幕上。
当你调用 m() 时,实际上是触发了类似下面的过程:
m() 会返回一个值,代表用户的选择。auto response = m();
m():显示对话框,等用户点击。auto response:自动推导类型,用来接收 m() 返回的结果(在 Nana 库中,这个返回类型通常是 msgbox::pick_t 或者是它的内部枚举)。if (response != m.pick_yes) return;
m.pick_yes:是 msgbox 预定义的一个常量,代表用户点击了“是”。if 语句:如果用户的选择 response 不是(!=)“是”,说明用户反悔了(点了“否”或者直接关闭了对话框),此时直接 return 退出当前 lambda 函数,取消退出程序,返回到主界面。拓展:为什么不写成 m.show() 呢?
很多 GUI 库(比如 Qt 或 Windows API)通常会使用 m.exec() 或 m.showDialog()。
而 Nana 库选择重载 () 运算符,是一种更偏向现代 C++ 仿函数(Functor) 的设计风格。它把“显示对话框并获取结果”这整个动作,抽象得就像调用一个普通函数一样自然:
"我想从对话框 m 获取一个结果,那我就像调用函数一样调用它:m()"
这是一个非常好的编程习惯问题!你敏锐地察觉到了这里的代码结构。
之所以没有写成常见的 if...else 结构,而是让 API::exit(); 直接“裸奔”在函数底部,背后主要有两层考虑:代码设计的清晰度(提前返回模式) 以及 逻辑的必然结果。
在软件工程中,这种写法被称为卫语句(Guard Clause),或者叫提前返回(Early Return)。
如果按照传统的 if...else 逻辑,代码会写成这样:
// 传统 if...else 结构
btn.events().click([&]() {
if (!really_quick) { // 情况 A:需要确认
msgbox m(fm, "Our demo", msgbox::yes_no);
m.icon(m.icon_question);
m << "Are you sure you want to quick?";
if (m() == m.pick_yes) {
API::exit(); // 真正退出
}
} else { // 情况 B:不需要确认
API::exit(); // 真正退出
}
});
if...else 不够好?if 块和 else 块里面写两次 API::exit();。我们来看看原本的代码逻辑是如何像一个“安检闸机”一样工作的:
btn.events().click([&]()
{
// 拦截层:只有在 "需要弹出提示" 时才进入
if (!really_quick)
{
msgbox m(fm, "Our demo", msgbox::yes_no);
// ... 省略设置 ...
auto response = m();
// 如果用户点了“否”,直接 return 结束这个 lambda 函数!
// 后面所有的代码(包括 API::exit())都会被跳过。
if (response != m.pick_yes) return;
}
// 通关层:能走到这一行的,只有两种清白的情况
// 情况 1: really_quick 为 true,直接跳过了上面的整个 if 块。
// 情况 2: really_quick 为 false,但用户在弹窗里勇敢地点击了“是 (Yes)”。
API::exit();
});
因为 if 块内部的 return 具有强烈的截断性(只要条件不满足,函数直接在这里彻底结束,后面的代码根本没机会执行)。
所以,代码运行到最后一行 API::exit(); 时,在逻辑上已经天然形成了 else 的效果,根本不需要再刻意写一个 else 关键字来包裹它。
这种“先排除异常/反悔情况(通过 return 拦截),最后执行核心动作”的编写背景,是现代 C++(以及绝大多数现代编程语言)非常推崇的干净风格。它让代码:
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。