Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Tulipoingia kwenye mada ya jinsi bidhaa za 1C zinavyofanya kazi katika mazingira ya Linux, kikwazo kimoja kiligunduliwa - ukosefu wa zana rahisi ya picha ya majukwaa mengi ya kudhibiti kundi la seva za 1C. Na iliamuliwa kusahihisha upungufu huu kwa kuandika GUI kwa matumizi ya koni ya rac. Tcl/tk ilichaguliwa kama lugha ya maendeleo kama, kwa maoni yangu, inayofaa zaidi kwa kazi hii. Na hivyo, ningependa kuwasilisha baadhi ya vipengele vya kuvutia vya suluhisho katika nyenzo hii.

Ili kufanya kazi utahitaji usambazaji wa tcl/tk na 1C. Na kwa kuwa niliamua kutumia vyema uwezo wa utoaji wa msingi wa tcl/tk bila kutumia vifurushi vya mtu wa tatu, nitahitaji toleo la 8.6.7, ambalo ni pamoja na ttk - kifurushi kilicho na vitu vya ziada vya picha, ambavyo tunahitaji ttk. ::TreeView, inaruhusu data kuonyesha katika mfumo wa muundo wa mti na katika mfumo wa jedwali (orodha). Pia, katika toleo jipya, kazi bila ubaguzi imefanywa upya (amri ya kujaribu, ambayo hutumiwa katika mradi wakati wa kuendesha amri za nje).

Mradi huo una faili kadhaa (ingawa hakuna kinachokuzuia kufanya kila kitu kwa moja):

rac_gui.cfg - usanidi chaguo-msingi
rac_gui.tcl - hati kuu ya uzinduzi
Saraka ya lib ina faili ambazo hupakiwa kiatomati wakati wa kuanza:
function.tcl - faili iliyo na taratibu
gui.tcl - kiolesura kikuu cha picha
images.tcl - maktaba ya picha ya base64

Faili ya rac_gui.tcl, kwa kweli, huanza mkalimani, inaanzisha vigezo, moduli za mizigo, configs, na kadhalika. Yaliyomo kwenye faili na maoni:

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"
    }    
}

Baada ya kupakua kila kitu kinachohitajika na kuangalia uwepo wa matumizi ya rac, dirisha la picha litazinduliwa. Kiolesura cha programu kina vipengele vitatu:

Upau wa vidhibiti, mti na orodha

Nilifanya yaliyomo ya "mti" sawa iwezekanavyo na vifaa vya kawaida vya Windows kutoka 1C.

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Nambari kuu inayounda dirisha hili iko kwenye faili
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

Algorithm ya kufanya kazi na programu ni kama ifuatavyo.

1. Kwanza, unahitaji kuongeza seva kuu ya nguzo (yaani, seva ya usimamizi wa nguzo (katika Linux, usimamizi unazinduliwa kwa amri "/opt/1C/v8.3/x86_64/ras cluster -daemon").

Ili kufanya hivyo, bonyeza kitufe cha "+" na kwenye dirisha linalofungua, ingiza anwani ya seva na bandari:

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Baadaye, seva yetu itaonekana kwenye mti kwa kubofya juu yake, orodha ya makundi itafungua au hitilafu ya uunganisho itaonyeshwa.

2. Kubofya jina la kundi kutafungua orodha ya vitendaji vinavyopatikana kwa ajili yake.

3.…

Na kadhalika, i.e. ili kuongeza kikundi kipya, chagua chochote kinachopatikana kwenye orodha na ubonyeze kitufe cha "+" kwenye upau wa vidhibiti na kidirisha kipya cha kuongeza kitaonyeshwa:

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Vifungo katika upau wa zana hufanya kazi kulingana na muktadha, i.e. Kulingana na kipengele gani cha mti au orodha iliyochaguliwa, utaratibu mmoja au mwingine utafanyika.

Wacha tuangalie mfano wa kitufe cha kuongeza (“+”):

Msimbo wa kutengeneza kitufe:

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

Hapa tunaona kwamba wakati kifungo kinaposisitizwa, utaratibu wa "Ongeza" utatekelezwa, msimbo wake:

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
}

Hapa kuna faida moja ya tickle: unaweza kupitisha thamani ya kutofautisha kama jina la utaratibu:

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

Hiyo ni, kwa mfano, ikiwa tunaelekeza kwenye seva kuu na bonyeza "+", basi utaratibu wa Ongeza::seva utazinduliwa, ikiwa kwenye nguzo - Ongeza:: nguzo na kadhalika (Nitaandika juu ya wapi "funguo" muhimu hutoka chini kidogo), taratibu zilizoorodheshwa huchora vipengele vya picha vinavyofaa kwa muktadha.

Kama unaweza kuwa umegundua tayari, fomu ni sawa kwa mtindo - hii haishangazi, kwa sababu zinaonyeshwa kwa utaratibu mmoja, kwa usahihi sura kuu ya fomu (dirisha, vifungo, picha, lebo), jina la utaratibu. 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
}

Vigezo vya kupiga simu: kichwa, jina la picha ya ikoni kutoka kwa maktaba (lib/images.tcl) na kigezo cha hiari cha jina la dirisha (chaguo-msingi .ongeza). Kwa hivyo, ikiwa tutachukua mifano hapo juu ya kuongeza seva kuu na nguzo, simu itakuwa ipasavyo:

AddToplevel "Добавление основного сервера" server_grey_64

au

AddToplevel "Добавление кластера" cluster_grey_64

Naam, kuendelea na mifano hii, nitaonyesha taratibu zinazoonyesha kuongeza mazungumzo kwa seva au nguzo.

Ongeza::seva

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
}

Ongeza:: nguzo

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
}

Wakati wa kulinganisha kanuni za taratibu hizi, tofauti inaonekana kwa jicho la uchi; Nitazingatia kidhibiti cha kitufe cha "Ok". Katika Tk, sifa za vipengele vya picha zinaweza kubatilishwa wakati wa utekelezaji wa programu kwa kutumia chaguo configure. Kwa mfano, amri ya awali ya kuonyesha kifungo:

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

Lakini katika fomu zetu, amri inategemea utendaji unaohitajika:

  .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
    }

Katika mfano hapo juu, kifungo "kilichofungwa" huanza utaratibu wa kuongeza kikundi.

Hapa inafaa kufanya uamuzi kuelekea kufanya kazi na vipengee vya picha katika Tk - kwa vitu anuwai vya kuingiza data (ingizo, kisanduku cha kuchana, kitufe cha kuangalia, n.k.) parameta imeanzishwa kama kigezo cha maandishi:

entry  $frm.ent_lifetime_limit -textvariable lifetime_limit

Tofauti hii inafafanuliwa katika nafasi ya majina ya kimataifa na ina thamani iliyoingizwa kwa sasa. Wale. ili kupata maandishi yaliyoingia kutoka kwenye shamba, unahitaji tu kusoma thamani inayofanana na kutofautiana (bila shaka, mradi inafafanuliwa wakati wa kuunda kipengele).

Njia ya pili ya kupata maandishi yaliyoingizwa (kwa vipengee vya aina ya kiingilio) ni kutumia get amri:

.add.frm.ent_name get

Njia hizi zote mbili zinaweza kuonekana katika nambari iliyo hapo juu.

Kubofya kitufe hiki, katika kesi hii, huzindua utaratibu wa RunCommand na mstari wa amri uliozalishwa wa kuongeza nguzo kulingana na 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

Sasa tunakuja kwa amri kuu, ambayo inadhibiti uzinduzi wa rac na vigezo tunavyohitaji, pia huchanganua matokeo ya amri katika orodha na kurudi, ikiwa inahitajika:

RunCommand

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 ""
    }
}

Baada ya kuingiza data kuu ya seva, itaongezwa kwenye mti, kwa hili, katika Ongezeko la juu: utaratibu wa seva, nambari ifuatayo inawajibika:

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

Sasa, kwa kubofya jina la seva kwenye mti, tunapata orodha ya makundi yanayosimamiwa na seva hiyo, na kwa kubofya kwenye kikundi, tunapata orodha ya vipengele vya makundi (seva, infobases, nk). Hii inatekelezwa katika utaratibu wa TreePress (faili 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
}

Ipasavyo, Run::server itazinduliwa kwa seva kuu (kwa nguzo - Run::cluster, kwa seva inayofanya kazi - Run::work_server, n.k.). Wale. thamani ya utofauti wa $key ni sehemu ya jina la kipengee cha mti kilichoainishwa na chaguo -kitambulisho.

Hebu makini na utaratibu

Endesha::seva

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
    }
}

Utaratibu huu unashughulikia kile kilichopokelewa kutoka kwa seva kupitia amri ya RunCommand na huongeza kila aina ya vitu kwenye mti - nguzo, vipengele mbalimbali vya mizizi (besi, seva za kufanya kazi, vikao, na kadhalika). Ukitazama kwa makini, utagundua wito kwa utaratibu wa InsertItemsWorkList ndani. Inatumika kuongeza vipengee kwenye orodha ya picha kwa kuchakata matokeo ya matumizi ya dashibodi ya rac, ambayo hapo awali ilirejeshwa kama orodha kwenye kigezo cha $lst. Hii ni orodha ya orodha iliyo na jozi za vipengele vilivyotenganishwa na koloni.

Kwa mfano, orodha ya miunganisho ya nguzo:

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

Katika fomu ya picha itaonekana kitu kama hiki:

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Utaratibu ulio hapo juu huchagua majina ya vitu vya kichwa na data ya kujaza jedwali:

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
}

Hapa, badala ya amri rahisi [split $str ":"], ambayo inagawanya kamba katika vipengele vilivyotenganishwa na ":" na kurudisha orodha, usemi wa kawaida hutumiwa, kwani baadhi ya vipengele pia vina koloni.

Utaratibu wa InsertClusterItems (mojawapo ya kadhaa zinazofanana) huongeza tu orodha ya vitu vya watoto vilivyo na vitambulisho vinavyolingana kwenye mti wa kipengele cha nguzo kinachohitajika.
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
}

Unaweza kuzingatia chaguzi mbili zaidi za kutekeleza utaratibu kama huo, ambapo itaonekana wazi jinsi unaweza kuongeza na kuondoa amri zinazojirudia:

Katika utaratibu huu, kuongeza na kuangalia hutatuliwa moja kwa moja:

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"
    }
}

Hapa kuna mbinu sahihi zaidi:

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 
    }
}

Tofauti kati yao ni matumizi ya kitanzi, ambayo amri zinazorudiwa zinatekelezwa. Njia ipi ya kutumia ni kwa hiari ya msanidi programu.

Tumeshughulikia kuongeza vipengele na kurejesha data, sasa ni wakati wa kuzingatia kuhariri. Kwa kuwa, kimsingi, vigezo sawa hutumiwa kwa kuhariri na kuongeza (isipokuwa msingi wa habari), fomu za mazungumzo sawa hutumiwa. Algorithm ya taratibu za kupiga simu za kuongeza inaonekana kama hii:

Ongeza::$key->AddToplevel

Na kwa kuhariri kama hii:

Hariri::$key->Ongeza::$key->AddTopLevel

Kwa mfano, hebu tuchukue kuhariri nguzo, i.e. Baada ya kubofya jina la nguzo kwenye mti, bonyeza kitufe cha kuhariri kwenye upau wa vidhibiti (penseli) na fomu inayolingana itaonyeshwa kwenye skrini:

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk
Hariri:: nguzo

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
    }
}

Kulingana na maoni kwenye msimbo, kimsingi, kila kitu kiko wazi, isipokuwa kwamba nambari ya kidhibiti cha kitufe imebatilishwa na kuna utaratibu wa FormFieldsDataInsert ambao hujaza sehemu na data na kuanzisha anuwai:

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
                }
            }
        }
    }
}

Katika utaratibu huu, faida nyingine ya tcl ilijitokeza - maadili ya vigezo vingine hubadilishwa kama majina ya kutofautiana. Wale. ili kuorodhesha ujazaji wa fomu na uanzishaji wa anuwai, majina ya uwanja na anuwai yanahusiana na swichi za mstari wa amri ya matumizi ya rac na majina ya vigezo vya pato la amri bila ubaguzi fulani - dashi inabadilishwa na kusisitiza. Mfano iliyopangwa-kazi-kukataa inalingana na uwanja ent_scheduled_jobs_kataa na kutofautiana kunyimwa_kazi_zilizopangwa.

Fomu za kuongeza na kuhariri zinaweza kutofautiana katika muundo wa uwanja, kwa mfano, kufanya kazi na msingi wa habari:

Kuongeza usalama wa habari

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Kuhariri usalama wa habari

Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Katika utaratibu wa kuhariri Hariri::infobase, sehemu zinazohitajika huongezwa kwenye fomu; msimbo ni mwingi, kwa hivyo siuwasilishi hapa.

Kwa mfano, taratibu za kuongeza, kuhariri, kufuta zinatekelezwa kwa vipengele vingine.

Kwa kuwa uendeshaji wa shirika unamaanisha idadi isiyo na kikomo ya seva, nguzo, besi za habari, nk, ili kuamua ni nguzo gani ya seva au mfumo wa usalama wa habari, anuwai kadhaa za ulimwengu zimeanzishwa, maadili ambayo yamewekwa kila moja. wakati bonyeza juu ya mambo ya mti. Wale. utaratibu hupitia tena vitu vyote vya mzazi na huweka vijiti:

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
    }
}

Kundi la 1C hukuruhusu kufanya kazi na au bila idhini. Kuna aina mbili za wasimamizi-msimamizi wa wakala wa nguzo na msimamizi wa nguzo. Ipasavyo, kwa ajili ya uendeshaji sahihi, vigezo 4 zaidi vya kimataifa vilianzishwa vyenye kuingia kwa msimamizi na nenosiri. Wale. ikiwa kuna akaunti ya msimamizi katika kikundi, mazungumzo yataonyeshwa ili kuingia kuingia kwako na nenosiri, data itahifadhiwa kwenye kumbukumbu na kuingizwa katika kila amri kwa nguzo inayofanana.

Hili ni jukumu la utaratibu wa kushughulikia makosa.

ErrorParcing

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"
        }
    }
}

Wale. kulingana na kile amri inarudi, majibu yatakuwa ipasavyo.

Kwa sasa, karibu asilimia 95 ya utendaji imetekelezwa, yote iliyobaki ni kutekeleza kazi na wasifu wa usalama na kuijaribu =). Ni hayo tu. Ninaomba radhi kwa hadithi iliyokunjwa.

Msimbo unapatikana jadi hapa.

Sasisha: Nilimaliza kufanya kazi na wasifu wa usalama. Sasa utendaji unatekelezwa 100%.

Sasisha 2: ujanibishaji kwa Kiingereza na Kirusi umeongezwa, kazi katika win7 imejaribiwa
Kuandika GUI kwa 1C RAC, au tena kuhusu Tcl/Tk

Chanzo: mapenzi.com

Kuongeza maoni