在我们的工具管理类ToolManager中,创建工具条的代码有很多是重复的。每一个工具条的按钮的创建都经过了下面几个步骤
其中的创建工具激活命令对象,可以很复杂,例如设置图标、提示文本、状态栏文本等。
如果对这些操作进行简单分类,可以把创建工具激活命令对象提取出来放到每个工具中来做,包括创建命令对象、设置图标等。因为每个工具应该知道自己应该表现成什么样的按钮,这属于“个体”内容。工具管理对象则不需要关注这些,它只处理创建几个什么名字的工具条,工具应该添加到哪个工具条的什么位置就可以了,这属于“群体”内容。因此,我们可以把工具类和工具管理类改造一下,使我们添加工具可以更方便灵活。
工具类的改造主要涉及两部分内容:
工具管理类中应该只关注工具创建的命令对象,为了统一处理,我们应该在工具中添加一个共同的接口来获取工具的命令对象,这可以通过ruby的混入模块或类继承来实现,为了灵活,我们这里使用混入模块的方式。首先,需要定义一个工具命令的模块,模块中实现一个方法用于创建工具激活命令对象。
# 工具命令模块
module ToolCommand
# 获取SketchUp命令
def command
cmd = UI::Command.new('工具名称') do
Sketchup.active_model.select_tool(self)
end
end
end
然后在每个工具中混入该模块使每个工具都有command方法来创建激活自身的命令
require 'free_wall/tool/tool_command'
class DrawWallTool
include ToolCommand
...
对于一个完整的插件来说,工具应该都自己的图标、提示文本等个性化的信息,所以我们应该在创建命令的时候把这些信息都设置好,而这些信息则应该在每个工具中来定义。
class DrawWallTool
include ToolCommand
def initialize
@menu_text = '画墙工具'
@large_icon = File.join(File.dirname(__dir__), 'resource/img/draw_wall_tool.jpg')
@small_icon = File.join(File.dirname(__dir__), 'resource/img/draw_wall_tool.jpg')
@status_bar_text = '画墙工具'
@tooltip = '绘制线生成一堵墙'
end
...
然后在创建命令时统一应用这些信息
def command
menu_text = @menu_text ? @menu_text : '未命名工具'
cmd = UI::Command.new(menu_text) do
Sketchup.active_model.select_tool(self)
end
cmd.large_icon = @large_icon if @large_icon
cmd.small_icon = @small_icon if @small_icon
cmd.status_bar_text = @status_bar_text if @status_bar_text
cmd.tooltip = @tooltip if @tooltip
cmd
end
这样,我们就可以创建出针对工具的个性化的命令,在添加到工具条时就可以看到不同的工具有不同的显示效果。
工具管理类中首先要加载工具类的定义,由于我们的工具都定义在tool目录下,所以实际上我们可以遍历该目录来加载所有的ruby文件。
tool_dir = File.join(__dir__, 'tool')
Dir.entries(tool_dir).each { |file|
file_path = File.join(tool_dir, file)
next unless File.file?(file_path)
require(file_path)
}
之后,我们应该定义出创建的工具条名称以及工具条中应该如何布局具体的工具,这实际可以通过一个哈希表来定义
TOOLBAR_LIST = { '墙工具条' => [DrawWallTool, CreateHoleTool] }.freeze
key为工具条名称,value为工具列表。这样就可以通过一次遍历,创建出所有的工具。
其中的工具列表中还可以添加特殊元素来标记为分隔符,比如在以上两个工具之间添加一个nil元素,在遍历创建工具按钮时,如果遇到nil元素,则创建分隔符。
# 创建工具条
def create_toolbar
TOOLBAR_LIST.each { |name, tools_klass|
tool_bar = UI::Toolbar.new(name)
tools_klass.each { |tool_klass|
if tool_klass
tool = tool_klass.new
tool_bar.add_item(tool.command)
else
tool_bar.add_separator
end
}
}
end
如果想要在创建工具条时,对点击按钮的行为进行控制,还可以把创建工具时激活工具的命令替换成对块的执行,在创建工具条获取工具命令的时候再添加具体的行为
...
cmd = UI::Command.new(menu_text) do
yield
end
...
...
cmd = tool.command {
Sketchup.active_model.select_tool(tool)
}
...
经过这样的改造,在添加新工具时,只需要把新工具的类定义添加到TOOLBAR_LIST中特定工具条的特定位置即可。而且即使是同一个工具,我们也可以添加到不同的工具条中,在每个工具条中的行为都可以进行控制。