关于XToolBox

从零开始

XToolBox 是在开发一个工具的时候,偶然得到的。

为了满足在Ubuntu和Windwos上都能够使用需求,采用了跨平台的Qt做为框架来开发。代码只需要一份,就能编译出两个系统上的可执行文件。

开发时,业务逻辑并不十分明确,用户会有一些个性化的定制要求,于是就引入了lua脚本语言来做业务逻辑定制。根据业务逻辑的不同,界面元素也会有所不同,因此在脚本中需要能够定制界面元素。这里采用luabind将Qt的界面类绑定到了lua中,这样便能在lua脚本中定制界面了。

在那个工具开发完工后,突然想到,如果我把界面和逻辑全用lua实现会如何,宿主程序只提供一个框架,并不实现任何业务逻辑。在这样的思路下,XToolBox诞生了。

信号和槽

信号和槽是Qt中最好用的一个特性,通过信号和槽能够关联两个不同的对象。最典型的场景就是将一段过程处理代码绑定到按钮的点击信号上,当点击事件发生时,触发相应的代码。在Qt中,用connect将信号和槽关联起来,在XToolBox中,信号是一个属性,槽就是普通的lua函数(closure),连接信号和槽看起来是下面这样的。

btn.clicked = function(arg)
    -- do something after button clicked
end

这里的槽看起来没有绑定到某一个特定对象上,和Qt中有点不太一样。因为在lua中,一个函数实际上是一个闭包,在函数中用到的对象会自动保存在函数的上下文中(upvalue),所以我们在绑定时,不用刻意去指定槽的对象,直接在函数中引用即可。实际上槽函数是绑定到了整个lua状态机上,在lua中所有可见的对象都能在槽中使用。

界面元素的布局

Qt中的界面元素可以通过QxxxLayout进行布局,在布局中的元素会自动调整位置,并在界面调整时保持相对关系。在Qt上可以通过界面设计器或者代码来设置布局。在XToolBox中可以用Qt风格的代码来设置布局,看起来是这样的

frame = QFrame()
text1 = QTextEdit()
text2 = QTextEdit()
button = QPushButton("&Copy")
layout = QVBoxLayout()
layout:addWidget(text1)
layout:addWidget(text2)
layout:addWidget(button)
frame.layout = layout
button.clicked = function()
    text2.plainText = text1.plainText
end
mdiArea:addSubWindow(frame):show()

 

不过更方便的是用XToolBox特有的风格来进行布局,像下面这样

frame = QFrame()
text1 = QTextEdit()
text2 = QTextEdit()
button = QPushButton("&Copy")
frame.layout = QVBoxLayout{
text1,
text2,
button,
stretch = "1,0,0"
}
button.clicked = function()
text2.plainText = text1.plainText
end
mdiArea:addSubWindow(frame):show()

 

这样的风格设置布局看起来更像是在写一个配置文件,更加的方便和直观。

上面的代码执行后的结果如下: