我们将GUI编写为1C RAC,或者再次写为Tcl / Tk

当我深入研究在Linux中使用1C产品的主题时,我发现了一个缺点-缺乏用于管理1C服务器群集的便捷的图形化多平台工具。 并且决定通过为控制台实用程序rac编写GUI来解决此缺陷。 在我看来,选择tcl / tk作为开发语言是最适合此任务的。 现在,我想在本材料中介绍该解决方案的一些有趣方面。

对于工作,您需要tcl / tk和1C发行版。 由于我决定在不使用第三方软件包的情况下,充分利用基本tcl / tk交付的功能,因此我需要版本8.6.7,其中包括ttk-一个带有其他图形元素的软件包,我们主要需要ttk :: TreeView,它允许以树结构形式和表(列表)形式显示数据。 另外,在新版本中,已重做了例外处理(try命令,在运行外部命令时在项目中使用)。

一个项目包含几个文件(尽管没有什么可以阻止一个文件完成所有操作):

rac_gui.cfg-默认配置
rac_gui.tcl-主要启动脚本
lib目录包含在启动时自动加载的文件:
function.tcl-具有过程的文件
gui.tcl-主GUI
images.tcl-base64中的图像库

实际上,rac_gui.tcl文件会启动解释器,初始化变量,加载模块,配置等。 带有注释的文件内容:

rac_gui.tcl
#!/bin/sh exec wish "$0" -- "$@" #    set dir(root) [pwd] #   ,      set dir(work) [file join $env(HOME) .rac_gui] if {[file exists $dir(work)] == 0 } { file mkdir $dir(work) } #    set dir(lib) "[file join $dir(root) lib]" #   ,   ,    if {[file exists [file join $dir(work) rac_gui.cfg]] ==0} { file copy [file join [pwd] rac_gui.cfg] [file join $dir(work) rac_gui.cfg] } source [file join $dir(work) rac_gui.cfg] #    rac       #             #         if {[file exists $rac_cmd] == 0} { set rac_cmd [tk_getOpenFile -initialdir $env(HOME) -parent . -title "   rac" -initialfile rac] file copy [file join $dir(work) rac_gui.cfg] [file join $dir(work) rac_gui.cfg.bak] set orig_file [open [file join $dir(work) rac_gui.cfg.bak] "r"] set file [open [file join $dir(work) rac_gui.cfg] "w"] while {[gets $orig_file line] >=0 } { if {[string match "set rac_cmd*" $line]} { puts $file "set rac_cmd $rac_cmd" } else { puts $file $line } } close $file close $orig_file #return "$host:$port" file delete [file join $dir(work) 1c_srv.cfg.bak] } else { puts "Found $rac_cmd" } set cluster_user "" set cluster_pwd "" set agent_user "" set agent_pwd "" ## LOAD FILE ## #    gui.tcl       foreach modFile [lsort [glob -nocomplain [file join $dir(lib) *.tcl]]] { if {[file tail $modFile] ne "gui.tcl"} { source $modFile puts "Loaded module $modFile" } } source [file join $dir(lib) gui.tcl] source [file join $dir(work) rac_gui.cfg] #      1 #     if [file exists [file join $dir(work) 1c_srv.cfg]] { set f [open [file join $dir(work) 1c_srv.cfg] "RDONLY"] while {[gets $f line] >=0} { .frm_tree.tree insert {} end -id "server::$line" -text "$line" -values "$line" } } 


下载所需的所有内容并检查rac实用程序的可用性之后,将启动图形窗口。 程序界面包含三个元素:

工具栏,树和列表

我使“树”的内容尽可能类似于1C中的标准Windows快照。

图片

构成该窗口的主要代码包含在文件中
lib / gui.tcl
 #       #     topLevelGeometry    if {[info exists topLevelGeometry]} { wm geometry . $topLevelGeometry } else { wm geometry . 1024x768 } #   wm title . "1C Rac GUI" wm iconname . "1C Rac Gui" #   (   lib/imges.tcl) wm iconphoto . tcl wm protocol . WM_DELETE_WINDOW Quit wm overrideredirect . 0 wm positionfrom . user ttk::style theme use clam #   set frm_tool [frame .frm_tool] pack $frm_tool -side left -fill y ttk::panedwindow .panel -orient horizontal -style TPanedwindow pack .panel -expand true -fill both pack propagate .panel false ttk::button $frm_tool.btn_add -command Add -image add_grey_32 ttk::button $frm_tool.btn_del -command Del -image del_grey_32 ttk::button $frm_tool.btn_edit -command Edit -image edit_grey_32 ttk::button $frm_tool.btn_quit -command Quit -image quit_grey_32 pack $frm_tool.btn_add $frm_tool.btn_del $frm_tool.btn_edit -side top -padx 5 -pady 5 pack $frm_tool.btn_quit -side bottom -padx 5 -pady 5 #     set frm_tree [frame .frm_tree] ttk::scrollbar $frm_tree.hsb1 -orient horizontal -command [list $frm_tree.tree xview] ttk::scrollbar $frm_tree.vsb1 -orient vertical -command [list $frm_tree.tree yview] set tree [ttk::treeview $frm_tree.tree -show tree \ -xscrollcommand [list $frm_tree.hsb1 set] -yscrollcommand [list $frm_tree.vsb1 set]] grid $tree -row 0 -column 0 -sticky nsew grid $frm_tree.vsb1 -row 0 -column 1 -sticky nsew grid $frm_tree.hsb1 -row 1 -column 0 -sticky nsew grid columnconfigure $frm_tree 0 -weight 1 grid rowconfigure $frm_tree 0 -weight 1 #      bind $frm_tree.tree <ButtonRelease> "TreePress $frm_tree.tree" #    () set frm_work [frame .frm_work] ttk::scrollbar $frm_work.hsb -orient horizontal -command [list $frm_work.tree_work xview] ttk::scrollbar $frm_work.vsb -orient vertical -command [list $frm_work.tree_work yview] set tree_work [ ttk::treeview $frm_work.tree_work \ -show headings -columns "par val" -displaycolumns "par val"\ -xscrollcommand [list $frm_work.hsb set] \ -yscrollcommand [list $frm_work.vsb set] ] #       $tree_work tag configure dark -background $color(dark_table_bg) $tree_work tag configure light -background $color(light_table_bg) #     grid $tree_work -row 0 -column 0 -sticky nsew grid $frm_work.vsb -row 0 -column 1 -sticky nsew grid $frm_work.hsb -row 1 -column 0 -sticky nsew grid columnconfigure $frm_work 0 -weight 1 grid rowconfigure $frm_work 0 -weight 1 pack $frm_tree $frm_work -side left -expand true -fill both #.panel add $frm_tool -weight 1 .panel add $frm_tree -weight 1 .panel add $frm_work -weight 1 


使用该程序的算法如下:

1.首先,您需要添加主集群服务器(即集群管理服务器(在Linux中,该命令以命令“ /opt/1C/v8.3/x86_64/ras cluster --daemon”启动))

为此,请单击“ +”按钮,然后在打开的窗口中输入服务器地址和端口:

图片

之后,我们的服务器通过单击出现在树中,然后打开集群列表或显示连接错误。

2.单击群集名称,将打开一个可用功能列表。

3. ...

等等,即 要添加新集群,请在列表中选择任何可用集群,然后按工具栏中的+按钮,将显示用于添加新集群的对话框:

图片

工具栏上的按钮根据上下文执行功能,即 从树或列表的哪个元素中选择,将执行此过程。

以添加按钮(“ +”)为例:

按钮生成代码:

 ttk::button $frm_tool.btn_add -command Add -image add_grey_32 

在这里,我们看到按下按钮时,将执行Add过程及其代码:

 proc Add {} { global active_cluster host #     set id [.frm_tree.tree selection] #     set values [.frm_tree.tree item [.frm_tree.tree selection] -values] set key [lindex [split $id "::"] 0] #           if {$key eq "" || $key eq "server"} { set host [ Add::server ] return } Add::$key .frm_tree.tree $host $values } 

因此,挠痒痒的优点之一是显而易见的-您可以将变量的值作为过程的名称传递:

 Add::$key .frm_tree.tree $host $values 

也就是说,例如,如果我们在主服务器上戳并按“ +”,则将启动Add ::服务器过程,如果集群是Add :: cluster等(我会写一些关于必要的“键”来自何处的信息)。下面),列出的过程将绘制适合于上下文的图形元素。

您可能已经注意到,表单的样式相似-这并不奇怪,因为它们显示在一个过程中,更确切地说是表单的主框架(窗口,按钮,图像,标签),过程的名称
AddTopLevel
 proc AddToplevel {lbl img {win_name .add}} { set cmd "destroy $win_name" if [winfo exists $win_name] {destroy $win_name} toplevel $win_name wm title $win_name $lbl wm iconphoto $win_name tcl #    ttk::label $win_name.lbl -image $img #     set frm [ttk::labelframe $win_name.frm -text $lbl -labelanchor nw] grid columnconfigure $frm 0 -weight 1 grid rowconfigure $frm 0 -weight 1 #    set frm_btn [frame $win_name.frm_btn -border 0] ttk::button $frm_btn.btn_ok -image ok_grey_24 -command { } ttk::button $frm_btn.btn_cancel -command $cmd -image quit_grey_24 grid $win_name.lbl -row 0 -column 0 -sticky nw -padx 5 -pady 10 grid $frm -row 0 -column 1 -sticky nw -padx 5 -pady 5 grid $frm_btn -row 1 -column 1 -sticky se -padx 5 -pady 5 pack $frm_btn.btn_cancel -side right pack $frm_btn.btn_ok -side right -padx 10 return $frm } 


调用参数:标题,库中图标的图像名称(lib / images.tcl)和可选的窗口名称参数(默认.add)。 因此,如果我们采用上述示例添加主服务器和集群,则调用将相应地为:

 AddToplevel "  " server_grey_64 



 AddToplevel " " cluster_grey_64 

好了,继续这些示例,我将展示显示服务器或集群的添加对话框的过程。

添加::服务器
 proc Add::server {} { global default #    set frm [AddToplevel "  " server_grey_64] #         label $frm.lbl_host -text " " entry $frm.ent_host label $frm.lbl_port -text "" entry $frm.ent_port $frm.ent_port insert end $default(port) grid $frm.lbl_host -row 0 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_host -row 0 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_port -row 1 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_port -row 1 -column 1 -sticky nsew -padx 5 -pady 5 grid columnconfigure $frm 0 -weight 1 grid rowconfigure $frm 0 -weight 1 #set frm_btn [frame .add.frm_btn -border 0] #     .add.frm_btn.btn_ok configure -command { set host [SaveMainServer [.add.frm.ent_host get] [.add.frm.ent_port get]] .frm_tree.tree insert {} end -id "server::$host" -text "$host" -values "$host" destroy .add return $host } return $frm } 


添加::集群
 proc Add::cluster {tree host values} { global default lifetime_limit expiration_timeout session_fault_tolerance_level global max_memory_size max_memory_time_limit errors_count_threshold security_level global load_balancing_mode kill_problem_processes \ agent_user agent_pwd cluster_user cluster_pwd auth_agent if {$agent_user ne "" && $agent_pwd ne ""} { set auth_agent "--agent-user=$agent_user --agent-pwd=$agent_pwd" } else { set auth_agent "" } #    () set lifetime_limit $default(lifetime_limit) set expiration_timeout $default(expiration_timeout) set session_fault_tolerance_level $default(session_fault_tolerance_level) set max_memory_size $default(max_memory_size) set max_memory_time_limit $default(max_memory_time_limit) set errors_count_threshold $default(errors_count_threshold) set security_level [lindex $default(security_level) 0] set load_balancing_mode [lindex $default(load_balancing_mode) 0] set frm [AddToplevel " " cluster_grey_64] label $frm.lbl_host -text "  " entry $frm.ent_host label $frm.lbl_port -text "" entry $frm.ent_port $frm.ent_port insert end $default(port) label $frm.lbl_name -text " " entry $frm.ent_name label $frm.lbl_secure_connect -text " " ttk::combobox $frm.cb_security_level -textvariable security_level -values $default(security_level) label $frm.lbl_expiration_timeout -text "   :" entry $frm.ent_expiration_timeout -textvariable expiration_timeout label $frm.lbl_session_fault_tolerance_level -text " " entry $frm.ent_session_fault_tolerance_level -textvariable session_fault_tolerance_level label $frm.lbl_load_balancing_mode -text "  " ttk::combobox $frm.cb_load_balancing_mode -textvariable load_balancing_mode \ -values $default(load_balancing_mode) label $frm.lbl_errors_count_threshold -text "    , %" entry $frm.ent_errors_count_threshold -textvariable errors_count_threshold label $frm.lbl_processes -text " :" label $frm.lbl_lifetime_limit -text " , ." entry $frm.ent_lifetime_limit -textvariable lifetime_limit label $frm.lbl_max_memory_size -text "  , " entry $frm.ent_max_memory_size -textvariable max_memory_size label $frm.lbl_max_memory_time_limit -text "    , ." entry $frm.ent_max_memory_time_limit -textvariable max_memory_time_limit label $frm.lbl_kill_problem_processes -justify left -anchor nw -text "   " checkbutton $frm.check_kill_problem_processes -variable kill_problem_processes -onvalue yes -offvalue no grid $frm.lbl_host -row 0 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_host -row 0 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_port -row 1 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_port -row 1 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_name -row 2 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_name -row 2 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_secure_connect -row 3 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.cb_security_level -row 3 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_expiration_timeout -row 4 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_expiration_timeout -row 4 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_session_fault_tolerance_level -row 5 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_session_fault_tolerance_level -row 5 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_load_balancing_mode -row 6 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.cb_load_balancing_mode -row 6 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_errors_count_threshold -row 7 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_errors_count_threshold -row 7 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_processes -row 8 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.lbl_lifetime_limit -row 9 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_lifetime_limit -row 9 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_max_memory_size -row 10 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_max_memory_size -row 10 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_max_memory_time_limit -row 11 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.ent_max_memory_time_limit -row 11 -column 1 -sticky nsew -padx 5 -pady 5 grid $frm.lbl_kill_problem_processes -row 12 -column 0 -sticky nw -padx 5 -pady 5 grid $frm.check_kill_problem_processes -row 12 -column 1 -sticky nw -padx 5 -pady 5 #   .add.frm_btn.btn_ok configure -command { RunCommand "" "cluster insert \ --host=[.add.frm.ent_host get] \ --port=[.add.frm.ent_port get] \ --name=[.add.frm.ent_name get] \ --expiration-timeout=$expiration_timeout \ --lifetime-limit=$lifetime_limit \ --max-memory-size=$max_memory_size \ --max-memory-time-limit=$max_memory_time_limit \ --security-level=$security_level \ --session-fault-tolerance-level=$session_fault_tolerance_level \ --load-balancing-mode=$load_balancing_mode \ --errors-count-threshold=$errors_count_threshold \ --kill-problem-processes=$kill_problem_processes \ $auth_agent $host" Run::server $tree $host "" destroy .add } return $frm } 


比较这些过程的代码时,肉眼可以看到差异,我将重点介绍“确定”按钮的处理程序。 在Tk中,可以在运行时使用configure选项重新定义图形元素的属性。 例如,初始按钮输出命令:

 ttk::button $frm_btn.btn_ok -image ok_grey_24 -command { } 

但是在我们的表单中,命令取决于所需的功能:

  .add.frm_btn.btn_ok configure -command { RunCommand "" "cluster insert \ --host=[.add.frm.ent_host get] \ --port=[.add.frm.ent_port get] \ --name=[.add.frm.ent_name get] \ --expiration-timeout=$expiration_timeout \ --lifetime-limit=$lifetime_limit \ --max-memory-size=$max_memory_size \ --max-memory-time-limit=$max_memory_time_limit \ --security-level=$security_level \ --session-fault-tolerance-level=$session_fault_tolerance_level \ --load-balancing-mode=$load_balancing_mode \ --errors-count-threshold=$errors_count_threshold \ --kill-problem-processes=$kill_problem_processes \ $auth_agent $host" Run::server $tree $host "" destroy .add } 

在上面的示例中,“已阻塞”按钮开始添加群集的过程。

在这里值得一提的是,在Tk中使用图形元素-对于各种数据输入元素(输入,组合框,复选按钮等),引入了诸如文本变量(textvariable)之类的参数:

 entry $frm.ent_lifetime_limit -textvariable lifetime_limit 

此变量在全局名称空间中定义,并包含输入的当前值。 即 为了从字段中获取输入的文本,您只需要读取对应于变量的值(当然,只要在创建元素时已定义该值即可)。

获取输入的文本(用于类型为entry的元素)的第二种方法是使用get命令:

 .add.frm.ent_name get 

这两种方法都可以在上面的代码中看到。

在这种情况下,单击此按钮将使用生成的命令行启动RunCommand过程,以按照rac的方式添加集群:

 /opt/1C/v8.3/x86_64/rac cluster insert --host=localhost --port=1540 --name=dsdsds --expiration-timeout=0 --lifetime-limit=0 --max-memory-size=0 --max-memory-time-limit=0 --security-level=0 --session-fault-tolerance-level=0 --load-balancing-mode=performance --errors-count-threshold=0 --kill-problem-processes=no localhost:1545 

因此,我们来到了主命令,该命令使用所需的参数控制rac的启动,还将命令的输出解析为列表,并在必要时返回:

运行命令
 proc RunCommand {root par} { global dir rac_cmd cluster work_list_row_count agent_user agent_pwd cluster_user cluster_pwd puts "$rac_cmd $par" set work_list_row_count 0 #      # $rac -     # $par -      set pipe [open "|$rac_cmd $par" "r"] try { set lst "" set l "" #       while {[gets $pipe line]>=0} { #puts $line if {$line eq ""} { lappend l $lst set lst "" } else { lappend lst [string trim $line] } } close $pipe return $l } on error {result options} { #    ErrorParcing $result $options return "" } } 


输入主服务器的数据后,它将被添加到树中,为此,在上面的“添加:服务器”过程中,以下代码负责:

 .frm_tree.tree insert {} end -id "server::$host" -text "$host" -values "$host" 

现在,单击树中的服务器名称,我们将获得该服务器管理的集群的列表,然后单击集群,将获得集群元素(服务器,信息库等)的列表。 这是在TreePress过程(文件lib / function.tcl)中实现的:

 proc TreePress {tree} { global host server active_cluster infobase #    set id [$tree selection] #     SetGlobalVarFromTreeItems $tree $id #    , ..     set values [$tree item $id -values] set key [lindex [split $id "::"] 0] #            #    Run Run::$key $tree $host $values } 

因此,将为主服务器启动Run ::服务器(对于群集,将启动Run ::集群,对于生产服务器,将运行Run :: work_server等)。 即 $键变量的值是-id选项指定的树元素名称的一部分。

注意程序

运行::服务器
 proc Run::server {tree host values} { #      set lst [RunCommand server::$host "cluster list $host"] if {$lst eq ""} {return} set l [lindex $lst 0] #puts $lst #     .frm_work.tree_work delete [ .frm_work.tree_work children {}] #   foreach cluster_list $lst { #     InsertItemsWorkList $cluster_list #   ()      foreach i $cluster_list { #puts $i set cluster_list [split $i ":"] if {[string trim [lindex $cluster_list 0]] eq "cluster"} { set cluster_id [string trim [lindex $cluster_list 1]] lappend cluster($cluster_id) $cluster_id } if {[string trim [lindex $cluster_list 0]] eq "name"} { lappend cluster($cluster_id) [string trim [lindex $cluster_list 1]] } } } #     foreach x [array names cluster] { set id [lindex $cluster($x) 0] if { [$tree exists "cluster::$id"] == 0 } { $tree insert "server::$host" end -id "cluster::$id" -text "[lindex $cluster($x) 1]" -values "$id" #     InsertClusterItems $tree $id } } if { [$tree exists "agent_admins::$id"] == 0 } { $tree insert "server::$host" end -id "agent_admins::$id" -text "" -values "$id" #InsertClusterItems $tree $id } } 


此过程处理通过RunCommand命令从服务器收到的内容,并将各种内容添加到树中-群集,各种根元素(数据库,生产服务器,会话等)。 如果仔细观察,您会在内部注意到对InsertItemsWorkList过程的调用。 它用于将元素添加到图形列表中,处理控制台实用程序rac的输出,该输出以前作为列表返回给变量$ lst。 这是一个列表列表,其中包含用冒号分隔的成对元素。

例如,群集连接列表:

 svk@svk ~]$ /opt/1C/v8.3/x86_64/rac connection list --cluster=783d2170-56c3-11e8-c586-fc75165efbb2 localhost:1545 connection : dcf5991c-7d24-11e8-1690-fc75165efbb2 conn-id : 0 host : svk.home process : 79de2e16-56c3-11e8-c586-fc75165efbb2 infobase : 00000000-0000-0000-0000-000000000000 application : "JobScheduler" connected-at : 2018-07-01T14:49:51 session-number : 0 blocked-by-ls : 0 connection : b993293a-7d24-11e8-1690-fc75165efbb2 conn-id : 0 host : svk.home process : 79de2e16-56c3-11e8-c586-fc75165efbb2 infobase : 00000000-0000-0000-0000-000000000000 application : "JobScheduler" connected-at : 2018-07-01T14:48:52 session-number : 0 blocked-by-ls : 0 

在图形形式下,它将如下所示:

图片

上面的过程将标识标题元素的名称以及填充表的数据:

InsertItemsWorkList
 proc InsertItemsWorkList {lst} { global work_list_row_count #      if [expr $work_list_row_count % 2] { set tag dark } else { set tag light } #      -  foreach i $lst { if [regexp -nocase -all -- {(\D+)(\s*?|)(:)(\s*?|)(.*)} $i match param v2 v3 v4 value] { lappend column_list [string trim $param] lappend value_list [string trim $value] } } #   .frm_work.tree_work configure -columns $column_list -displaycolumns $column_list .frm_work.tree_work insert {} end -values $value_list -tags $tag .frm_work.tree_work column #0 -stretch #   foreach j $column_list { .frm_work.tree_work heading $j -text $j } incr work_list_row_count } 


在这里,而不是简单的命令[split $ str“:”],该命令将字符串分成由“:”分隔的元素并返回列表,而是应用了正则表达式,因为某些元素还包含冒号。

InsertClusterItems过程(几个类似的过程之一)仅将带有相应标识符的子元素列表添加到树中所需的集群元素上
InsertClusterItems
 proc InsertClusterItems {tree id} { set parent "cluster::$id" $tree insert $parent end -id "infobases::$id" -text " " -values "$id" $tree insert $parent end -id "servers::$id" -text " " -values "$id" $tree insert $parent end -id "admins::$id" -text "" -values "$id" $tree insert $parent end -id "managers::$id" -text " " -values $id $tree insert $parent end -id "processes::$id" -text " " -values "workprocess-all" $tree insert $parent end -id "sessions::$id" -text "" -values "sessions-all" $tree insert $parent end -id "locks::$id" -text "" -values "blocks-all" $tree insert $parent end -id "connections::$id" -text "" -values "connections-all" $tree insert $parent end -id "profiles::$id" -text " " -values $id } 


您可以考虑使用两个以上的选项来实现此过程,其中将清晰可见如何优化并消除重复的命令:

在此过程中,添加和检查在额头上得到解决:

InsertBaseItems
 proc InsertBaseItems {tree id} { set parent "infobase::$id" if { [$tree exists "sessions::$id"] == 0 } { $tree insert $parent end -id "sessions::$id" -text "" -values "$id" } if { [$tree exists "locks::$id"] == 0 } { $tree insert $parent end -id "locks::$id" -text "" -values "$id" } if { [$tree exists "connections::$id"] == 0 } { $tree insert $parent end -id "connections::$id" -text "" -values "$id" } } 


这里的方法更正确:

InsertProfileItems
 proc InsertProfileItems {tree id} { set parent "profile::$id" set lst { {dir " "} {com " COM-"} {addin " "} {module "   "} {app " "} {inet " "} } foreach i $lst { append item [lindex $i 0] "::$id" if { [$tree exists $item] == 0 } { $tree insert $parent end -id $item -text [lindex $i 1] -values "$id" } unset item } } 


它们之间的区别是使用执行重复命令的周期。 开发人员可以自行决定使用哪种方法。

我们考虑过添加元素并接收数据;现在该停止编辑了。 由于基本上使用相同的参数进行编辑和添加(信息库除外),因此对话框形式相同。 添加的过程调用过程如下所示:

添加:: $ key-> AddToplevel

对于这样的编辑:

编辑:: $ key->添加:: $ key-> AddTopLevel

例如,编辑一个群集,即 通过单击树中的集群名称,按工具栏中的编辑按钮(铅笔),将显示相应的表单:

图片
编辑::集群
 proc Edit::cluster {tree host values} { global default lifetime_limit expiration_timeout session_fault_tolerance_level global max_memory_size max_memory_time_limit errors_count_threshold security_level global load_balancing_mode kill_problem_processes active_cluster \ agent_user agent_pwd cluster_user cluster_pwd auth if {$cluster_user ne "" && $cluster_pwd ne ""} { set auth "--cluster-user=$cluster_user --cluster-pwd=$cluster_pwd" } else { set auth "" } #     set frm [Add::cluster $tree $host $values] #     $frm configure -text " " set active_cluster $values #      set lst [RunCommand cluster::$values "cluster info --cluster=$active_cluster $host"] #   FormFieldsDataInsert $frm $lst #  ,    $frm.ent_host configure -state disable $frm.ent_port configure -state disable #   .add.frm_btn.btn_ok configure -command { RunCommand "" "cluster update \ --cluster=$active_cluster $auth \ --name=[.add.frm.ent_name get] \ --expiration-timeout=$expiration_timeout \ --lifetime-limit=$lifetime_limit \ --max-memory-size=$max_memory_size \ --max-memory-time-limit=$max_memory_time_limit \ --security-level=$security_level \ --session-fault-tolerance-level=$session_fault_tolerance_level \ --load-balancing-mode=$load_balancing_mode \ --errors-count-threshold=$errors_count_threshold \ --kill-problem-processes=$kill_problem_processes \ $auth $host" $tree delete "cluster::$active_cluster" Run::server $tree $host "" destroy .add } } 


根据代码中的注释,从原理上讲,所有内容都很清楚,只是重新定义了按钮处理程序代码,并且存在FormFieldsDataInsert过程,该过程用数据填充字段并初始化变量:

FormFieldsDataInsert
 proc FormFieldsDataInsert {frm lst} { foreach i [lindex $lst 0] { #      if [regexp -nocase -all -- {(\D+)(\s*?|)(:)(\s*?|)(.*)} $i match param v2 v3 v4 value] { #   regsub -all -- "-" [string trim $param] "_" entry_name #   if [winfo exists $frm.ent_$entry_name] { $frm.ent_$entry_name delete 0 end $frm.ent_$entry_name insert end [string trim $value "\""] } if [winfo exists $frm.cb_$entry_name] { global $entry_name set $entry_name [string trim $value "\""] } #     if [winfo exists $frm.check_$entry_name] { global $entry_name if {$value eq "0"} { set $entry_name no } elseif {$value eq "1"} { set $entry_name yes } else { set $entry_name $value } } } } } 


在此过程中,出现了另一个加号tcl-将其他变量的值替换为变量名。 为了自动填写表格和初始化变量,字段和变量的名称与rac实用程序的命令行开关相对应,并且命令的输出参数的名称与某些例外(破折号由下划线代替)相对应。例如,schedule-jobs-deny对应于ent_scheduled_jobs_deny字段schedule_jobs_deny变量

添加和编辑的形式可能在字段的组成方面有所不同,例如,使用信息库:

添加IB

图片

编辑IB

图片

在Edit ::信息库编辑过程中,必填字段被添加到了表单中,因此我没有为此提供代码。

以此类推,实现了其他元素的添加,编辑,删除过程。

由于该实用程序涉及无限数量的服务器,群集,信息库等,以确定服务器或信息安全性属于哪个群集,因此已输入几个全局变量,每次单击树元素时都将设置其值。 该过程以递归方式遍历所有父元素并设置变量:

SetGlobalVarFromTreeItems
 proc SetGlobalVarFromTreeItems {tree id} { global host server active_cluster infobase set parent [$tree parent $id] set values [$tree item $id -values] set key [lindex [split $id "::"] 0] switch -- $key { server {set host $values} work_server {set server $values} cluster {set active_cluster $values} infobase {set infobase $values} } if {$parent eq ""} { return } else { SetGlobalVarFromTreeItems $tree $parent } } 


1C群集可让您使用或不使用授权。有两种类型的管理员-群集代理管理员和群集管理员。因此,为了进行正确的操作,引入了另外4个全局变量,其中包含管理员登录名和密码。如果群集中存在管理员帐户,将显示一个对话框,用于输入登录名和密码,数据将存储在内存中,并插入到相应群集的每个命令中。

错误处理过程对此负责。

错误配对
 proc ErrorParcing {err opt} { global cluster_user cluster_pwd agent_user agent_pwd switch -regexp -- $err { "Cluster administrator is not authenticated" { AuthorisationDialog " " .auth_win.frm_btn.btn_ok configure -command { set cluster_user [.auth_win.frm.ent_name get] set cluster_pwd [.auth_win.frm.ent_pwd get] destroy .auth_win } #RunCommand $root $par } "Central server administrator is not authenticated" { AuthorisationDialog "  " .auth_win.frm_btn.btn_ok configure -command { set agent_user [.auth_win.frm.ent_name get] set agent_pwd [.auth_win.frm.ent_pwd get] destroy .auth_win } } "   " { AuthorisationDialog " " .auth_win.frm_btn.btn_ok configure -command { set cluster_user [.auth_win.frm.ent_name get] set cluster_pwd [.auth_win.frm.ent_pwd get] destroy .auth_win } #RunCommand $root $par } "    " { AuthorisationDialog "  " .auth_win.frm_btn.btn_ok configure -command { set agent_user [.auth_win.frm.ent_name get] set agent_pwd [.auth_win.frm.ent_pwd get] destroy .auth_win } } (.+) { tk_messageBox -type ok -icon error -message "$err" } } } 


根据命令返回的内容,会有相应的反应。

目前,已经有95%的功能已实现,但仍需要使用安全配置文件和test =)来实现。仅此而已。对于抱歉的旁白,我深表歉意。

该代码传统上可在此处获得

更新:安全配置文件已完成。现在,该功能已100%实现。

更新2:添加了英语和俄语的本地化,检查了win7中的工作
图片

Source: https://habr.com/ru/post/zh-CN415835/


All Articles