0

この質問で与えられたアドバイスに従って、コマンドラインCプログラムのオプションを取得し、それらを処理するように既に設定されているCプログラムに渡すための小さなGUIを作成しました。思った通りに表示されます。

ただし、変数に格納されている値が正しいことを確認したいと思います。 値を印刷するのは、私に多くの悲しみを与えています(ハードウェアの問題により、現在in vivo でテストすることはできません)。私は何が欠けていますか?

  1. 変数名の先頭に「$」を付けると、変数の値ではなく「$variableName」が得られます。
  2. これらの変数を配列に追加して呼び出すarray get arrと、インデックスと配列の値が出力されるはずです。変数名を取得します。
  3. pathName cget optionを試しましたが、明らかにオプション-valueではなく、オプションを省略しても有効なオプションのリストが表示されません。

これは、機能しなかったさまざまな事柄を含むすべてのコードです (オプション #1 から、これが最も簡単な方法です。他の方法は、私が回避策を試みただけです)。それらはすべて、「「::」を読み取れません: そのような変数はありません」または「「比色」を読み取ることができません: そのような変数はありません」という行に沿ってエラーを生成します。

#!/opt/ActiveTcl-8.5/bin/wish8.5

wm title . "Gretag"

ttk::frame .f -borderwidth 5 -relief sunken -padding "5 10"

# next line part of the "puts" tests at the bottom
global colorimetric
ttk::label .f.dataLabel -text "Data Type"
ttk::label .f.colorimetricLabel -text "Colorimetric"
ttk::checkbutton .f.colorimetric -onvalue "-c" -offvalue "" -command getFilename1
ttk::label .f.spectralLabel -text "Spectral"
ttk::checkbutton .f.spectral -onvalue "-s" -offvalue "" -command getFilename2 

ttk::label .f.gretagNumLabel -text "Gretag #"
ttk::label .f.gretagLabel0 -text "1"
ttk::radiobutton .f.gretagRadio0 -variable gretagNum -value "/dev/ttyS0" 
ttk::label .f.gretagLabel1 -text "2"
ttk::radiobutton .f.gretagRadio1 -variable gretagNum -value "/dev/ttyS1"
ttk::label .f.gretagLabel2 -text "3"
ttk::radiobutton .f.gretagRadio2 -variable gretagNum -value "/dev/ttyS2" 
ttk::label .f.gretagLabel3 -text "4"
ttk::radiobutton .f.gretagRadio3 -variable gretagNum -value "/dev/ttyS3" 
ttk::label .f.gretagLabel4 -text "5"
ttk::radiobutton .f.gretagRadio4 -variable gretagNum -value "/dev/ttyS4" 

ttk::label .f.sampleSize -text "Sample Size"
ttk::label .f.samplex -text "X"
ttk::label .f.sampley -text "Y"
ttk::entry .f.x -textvariable x -width 5 
ttk::entry .f.y -textvariable y -width 5 

ttk::label .f.filterLabel -text "Filter Type"
ttk::label .f.filterLabel0 -text "D50"
ttk::radiobutton .f.filterRadio0 -variable filter -value "-d50" 
ttk::label .f.filterLabel1 -text "D65"
ttk::radiobutton .f.filterRadio1 -variable filter -value "-d65" 
ttk::label .f.filterLabel2 -text "Unfiltered"
ttk::radiobutton .f.filterRadio2 -variable filter -value "-U" 
ttk::label .f.filterLabel3 -text "Polarized"
ttk::radiobutton .f.filterRadio3 -variable filter -value "-p" 

ttk::label .f.baudLabel -text "Baud Rate"
ttk::label .f.baudLabel0 -text "4800"
ttk::radiobutton .f.baudRadio0 -variable baud -value "B4800" 
ttk::label .f.baudLabel1 -text "9600"
ttk::radiobutton .f.baudRadio1 -variable baud -value "B9600" 
ttk::label .f.baudLabel2 -text "19200"
ttk::radiobutton .f.baudRadio2 -variable baud -value "B19200" 
ttk::label .f.baudLabel3 -text "38400"
ttk::radiobutton .f.baudRadio3 -variable baud -value "B38400" 
ttk::label .f.baudLabel4 -text "57600"
ttk::radiobutton .f.baudRadio4 -variable baud -value "B57600" 

ttk::button .f.submitBtn -text "Submit" -command finish

grid columnconfigure . 0 -weight 1
grid rowconfigure . 0 -weight 1
grid .f -column 0 -row 0 -columnspan 11 -rowspan 5

grid .f.dataLabel -column 0 -row 0 -sticky we
grid .f.colorimetricLabel -column 1 -row 0 -sticky e
grid .f.colorimetric -column 2 -row 0 -sticky w
grid .f.spectralLabel -column 3 -row 0 -sticky e
grid .f.spectral -column 4 -row 0 -sticky w

grid .f.gretagNumLabel -column 0 -row 1 -sticky we
grid .f.gretagLabel0 -column 1 -row 1 -sticky e
grid .f.gretagRadio0 -column 2 -row 1 -sticky w
grid .f.gretagLabel1 -column 3 -row 1 -sticky e
grid .f.gretagRadio1 -column 4 -row 1 -sticky w
grid .f.gretagLabel2 -column 5 -row 1 -sticky e
grid .f.gretagRadio2 -column 6 -row 1 -sticky w
grid .f.gretagLabel3 -column 7 -row 1 -sticky e
grid .f.gretagRadio3 -column 8 -row 1 -sticky w
grid .f.gretagLabel4 -column 9 -row 1 -sticky e
grid .f.gretagRadio4 -column 10 -row 1 -sticky w

grid .f.sampleSize -column 0 -row 2 -sticky we
grid .f.samplex -column 1 -row 2 -sticky e
grid .f.x -column 2 -row 2 -sticky w
grid .f.sampley -column 3 -row 2 -sticky e
grid .f.y -column 4 -row 2 -sticky w

grid .f.filterLabel -column 0 -row 3 -sticky we
grid .f.filterLabel0 -column 1 -row 3 -sticky e
grid .f.filterRadio0 -column 2 -row 3 -sticky w
grid .f.filterLabel1 -column 3 -row 3 -sticky e
grid .f.filterRadio1 -column 4 -row 3 -sticky w
grid .f.filterLabel2 -column 5 -row 3 -sticky e
grid .f.filterRadio2 -column 6 -row 3 -sticky w
grid .f.filterLabel3 -column 7 -row 3 -sticky e
grid .f.filterRadio3 -column 8 -row 3 -sticky w

grid .f.baudLabel -column 0 -row 4 -sticky we
grid .f.baudLabel0 -column 1 -row 4 -sticky e
grid .f.baudRadio0 -column 2 -row 4 -sticky w
grid .f.baudLabel1 -column 3 -row 4 -sticky e
grid .f.baudRadio1 -column 4 -row 4 -sticky w
grid .f.baudLabel2 -column 5 -row 4 -sticky e
grid .f.baudRadio2 -column 6 -row 4 -sticky w
grid .f.baudLabel3 -column 7 -row 4 -sticky e
grid .f.baudRadio3 -column 8 -row 4 -sticky w
grid .f.baudLabel4 -column 9 -row 4 -sticky e
grid .f.baudRadio4 -column 10 -row 4 -sticky w

grid .f.submitBtn -column 1 -row 5 -columnspan 7 -sticky we

foreach w [winfo children .f] {grid configure $w -padx 5 -pady 5}
focus .f.colorimetric
.f.colorimetric state selected
.f.filterRadio1 state selected
.f.baudRadio1 state selected
bind . <Return> {finish}

proc getFilename1 {} {
set filename1 [tk_getSaveFile]
}

proc getFilename2 {} {
set filename2 [tk_getSaveFile]
}

proc finish {} {
.f.x insert 0 "-x"
.f.y insert 0 "-y"
# Pick one
# puts $colorimetric
# puts colorimetric
# puts "$colorimetric"
# puts $::colorimetric
# puts .f.colorimetric
# puts $.f.colorimetric
# puts $::.f.colorimetric
# puts "$::colorimetric"
exec ./gretag .f.colorimetric filename1 .f.spectral filename2 .f.gretagNum .f.x .f.y .f.filter .f.baud
}

編集: 一部ではなくすべてのコードを投稿しました。最後の行から次の行には、変数に渡される前に変数の値を表示するために試したオプション #1 のさまざまな構文があります。次のプログラム。これらのどれも機能しておらず、その理由や修正方法がわかりません。別の目が間違っていることを見つけてくれることを願っています。

4

6 に答える 6

5

変数の基本

他の人が指摘しているように、$表記にするかしないかの混乱は、次の規則によって単純化できます。

varは変数自体への参照であり、その値ではありません

$varは、変数に保持されている値を生成します

Tcl のすべてを文字列と考え始めると (実際にはそうではありませんが、十分に近いものです)、少し混乱する可能性があるため、ある変数の名前を別の変数に格納し、その値を参照によって復元できます。

% set foo "hi"
hi
% set bar "foo"
foo
% set $foo
can't read "hi": no such variable
% set $bar
hi

ここで、表記法set $fooはステップで評価されます。最初$fooにその値が生成されhi、次にset式が (3 番目の引数なしで実行された場合) 変数に保持されている値を返そうとしますhi。これは失敗します。表記法set $barは同じ手順を踏むが、今回setは の値である を操作できるため、 の値であるbarfoo返す。(「設定」API へのリンク)foohi

初期化

このスクリプトで発生する問題の 1 つは、初期化です。Tcl では、変数は値が割り当てられるまで存在しません。set $foovariable がなかったため、上記を試してもうまくいかなかったのは明らかですhi

スクリプトの先頭で、変数を宣言しようとすると、

global colorimetric

すでにグローバルスコープで操作しているため、これは機能しません。グローバルは「proc本体のコンテキストで実行されない限り効果がありません。」(「グローバル」API へのリンク)実際には、setコマンドを使用して変数を初期化する必要があります。colorimetricこれが、印刷しようとする試みがどれもproc finishうまくいかなかった理由です。

範囲

このスクリプトのもう 1 つの問題は、スコープです。特に、グローバル スコープと手続き型/ローカル スコープが混在している場合はそうです。colorimetricおっしゃるとおり、コードを正しく初期化していれば、

puts $::colorimetric ;# print the value of the global variable colorimetric

うまくいったでしょう。これを達成する別の方法は、

global colorimetric ;# reference a global variable into the local scope
puts $colorimetric  ;# print the value of colorimetric in the local scope

私の解決策

私の解決策を紹介したいと思います。多くのコードを移動したことは認めます。より簡潔にするために実装した変更について簡単に説明します。

#!/usr/bin/env wish

# --- default configuration --- #
array set CONF {
    colorimetric "-c"
    spectral     ""
    cfilename    "/path/to/defaultCI.txt"
    sfilename    ""
    x            0
    y            0
    gretagnum    "/dev/ttyS0"
    filter       "-d65"
    baud         "B9600"
}

# --- build the interface --- #
wm title . "Gretag"
ttk::frame .f -borderwidth 5 -relief sunken -padding "5 10"
grid columnconfigure . 0 -weight 1
grid rowconfigure    . 0 -weight 1
grid .f


ttk::label .f.dataLabel -text "Data Type: "
foreach {dtname dttag dtfile} {
    colorimetric "-c" cfilename
    spectral     "-s" sfilename
} {
    lappend mygrid [
        ttk::checkbutton .f.$dtname -text [string totitle $dtname] \
        -variable CONF($dtname) -onvalue $dttag -offvalue "" \
        -command [list getFilename $dtname $dttag $dtfile ]
    ]
}
grid .f.dataLabel {*}$mygrid -sticky w ; set mygrid { }


ttk::label .f.gretagNumLabel -text "Gretag #: "
for {set tty 0} {$tty < 5} {incr tty} {
    lappend mygrid [
        ttk::radiobutton .f.gretagRadio$tty -text [expr $tty + 1] \
        -variable CONF(gretagnum) -value "/dev/ttyS$tty" 
    ]
}
grid .f.gretagNumLabel {*}$mygrid -sticky w ; set mygrid { }


ttk::label .f.sampleSize -text "Sample Size: "
ttk::label .f.samplex -text "X"
ttk::label .f.sampley -text "Y"
ttk::entry .f.x -textvariable CONF(x) -width 5 
ttk::entry .f.y -textvariable CONF(x) -width 5 
grid .f.sampleSize .f.samplex .f.x .f.sampley .f.y


ttk::label .f.filterLabel -text "Filter Type: "
foreach {ftname ftval} {
    D50        "-d50"
    D65        "-d65"
    Unfiltered "-U"
    Polarized  "-P"
} {
    lappend mygrid [
        ttk::radiobutton .f.filterRadio$ftname -text $ftname \
        -variable CONF(filter) -value $ftval
    ]
}
grid .f.filterLabel {*}$mygrid -sticky w ; set mygrid { }


ttk::label .f.baudLabel -text "Baud Rate: "
foreach {baud} {
    4800 9600 19200 38400 57600
} {
    lappend mygrid [
        ttk::radiobutton .f.baudRadio$baud -text $baud \
        -variable CONF(baud) -value "B$baud"
    ]
}
grid .f.baudLabel {*}$mygrid -sticky w ; set mygrid { }


ttk::button .f.submitBtn -text "Submit" -command submit
grid .f.submitBtn -columnspan 6 -sticky we

foreach w [winfo children .f] {
    grid configure $w -padx 5 -pady 5
}
focus .f.colorimetric
bind . <Return> submit

# --- callbacks --- #
proc getFilename {type tag file} {
    global CONF

    if {$CONF($type) eq $tag} {
        set CONF($file) [tk_getOpenFile]
        if {$CONF($file) eq ""} { .f.$type invoke }
    } else {
        set CONF($file) ""
    }
}

proc submit { } {
    global CONF

    exec ./gretag $CONF(colorimetric) $CONF(cfilename) \
        $CONF(spectral) $CONF(sfilename) $CONF(gretagnum) \
        $CONF(x) $CONF(y) $CONF(filter) $CONF(baud)
}

変更の議論

1.最初に行った変更は、およびの-textオプションを使用することでした。確かに、これらに追加のラベルを使用すると、ボタンの前にテキストを配置できますが、これは非標準であり、より多くのコードが必要になります。ttk::checkbuttonttk::radiobutton

ttk::label .f.colorimetricLabel -text "Colorimetric"
ttk::checkbutton .f.colorimetric -onvalue "-c" -offvalue "" -command getFilename1

になる

ttk::checkbutton .f.colorimetric -text "Colorimetric" -onvalue "-c" -offvalue "" -command getFilename1

2.次に、これら 2 つのチェックボタンの類似性を利用して、作成を foreach に抽象化しました。(私はこれを仕事用の Tcl コードで常に行っています。) これにより、はるかに読みやすいコードが生成され、ウィジェットの名前とタグの追加/削除/交換が可能になります。これにより、わずかに多くの汎用性の高いコードが生成されます。

ttk::checkbutton .f.colorimetric -text "Colorimetric" -onvalue "-c" -offvalue "" -command getFilename1
ttk::checkbutton .f.colorimetric -text "Spectral" -onvalue "-s" -offvalue "" -command getFilename2

になる

foreach {dtname dttag dtcommand} {
    colorimetric "-c" getFilename1
    spectral     "-s" getFilename2
} {
        ttk::checkbutton .f.$dtname -text [string totitle $dtname] -onvalue $dttag -offvalue "" -command $dtcommand
}

3.次の変更は、getFilename1andgetFilename2を 1 つのgetFilenameプロシージャにマージすることでした。この関数に引数を渡して、誰が呼び出しているかを判断できます。コマンドを使用してlist、この新しい関数の呼び出しを生成します。(「リスト」API へのリンク)

gridまた、コマンドをウィジェット コード自体に結合し始めました。ここでmygridは、GUI の行ごとにグリッド化する必要があるもののリストを保持し、各セクションの最後で評価して、その場で GUI を伝播します。(「グリッド」API へのリンク)

前のコードは最終的なリビジョンを取得し、次のようになります。

foreach {dtname dttag dtfile} {
    colorimetric "-c" cfilename
    spectral     "-s" sfilename
} {
    lappend mygrid [
        ttk::checkbutton .f.$dtname -text [string totitle $dtname] -variable CONF($dtname) -onvalue $dttag -offvalue "" -command [list getFilename $dtname $dttag $dtfile ]
    ]
}

その後、gridコマンドを評価して、mygrid使用するたびに変数をクリアできます!


4.注意を払っている場合は、-variableオプションも追加しました。ttk::checkbuttonこの時点で、ボタンの状態をグローバル変数に保存し始めましたCONF。これは大きな変化です。

Tk はグローバル名前空間を汚染するのが大好きで、反撃することをお勧めします。私は通常、すべての構成状態をグローバル配列に配置し、それをコードのすぐ上に設定して、コードを掘り下げたり、検索/置換呼び出しなどを実行したりすることなく、誰でもアクセスしてコードのデフォルト状態を変更できるようにしますそれ。いい練習になるので、変数をどこにでも移動して一番上CONFに移動CONFしました。

array set CONF {
    colorimetric "-c"
    spectral     ""
    cfilename    "/path/to/defaultCI.txt"
    sfilename    ""
    x            0
    y            0
    gretagnum    "/dev/ttyS0"
    filter       "-d65"
    baud         "B9600"
}

5.次に、これらの変更をコード全体に反映させました。ほとんどすべてのウィジェットの作成は、これらの改訂の影響を受けやすいものでした。ウィジェットの作成に関しては、独立したコード セクションが大きくなることがありました。しかし、グリッド セクション全体を削除して、前述のようにこのコードをウィジェット コードにマージすることもできました。これにより、コードのサイズと混乱が大幅に減少しましたが、複雑さが増しました。


6.私が行った最後の変更は、関数コードに対するものでした。コードにいくつかのマイナーなバグがgetFilename1ありgetFilename2ます。tk_getOpenFile最初のバグは、既存のファイル名を取得してに渡すだけだと思う​​ので、呼び出したいということでしたgretag('tk_getOpenFile' API へのリンク)ダイアログを使用tk_getOpenFileすると、ファイルが存在することを確認します。

2 つ目のバグgetFilename1は、ダイアログにCancelボタンがあり、ユーザーがこのキャンセル ボタンをクリックすると、ダイアログが空の文字列を返すことです。この場合、 のチェックを外し、変数ttk::checkbuttonの設定を解除する必要があります。CONF(colorimetric)または、より正確にはCONF(colorimetric)、ボタンの に設定する必要があります-offvalue。クリック イベントを現在のボタンに送信することで、これらの両方を一度に行うことができます。

proc getFilename1 {} {
set filename1 [tk_getSaveFile]
}

になる

proc getFilename {type tag file} {
    global CONF

    if {$CONF($type) eq $tag} {
        set CONF($file) [tk_getOpenFile]
        if {$CONF($file) eq ""} { .f.$type invoke }
    } else {
        set CONF($file) ""
    }
}

あなたのfinish関数では、関数の名前を(申し訳ありません)に変更し、新しい変数submitを使用するように書き直しました。CONF

答え

もちろん、これのほとんどは不要でした。問題を解決すると同時に、考えるべき興味深い Tcl/Tk コードを提供したいと思います。ただし、この時点で、あなたの質問に答える語彙が必要です。

変数が出力されなかった理由は、初期化とスコープが原因でした。後で参照する必要があるウィジェットでは、常に-variableまたはを使用する必要があります。-textvariable通常、変数を含むウィジェットを構築する前に、参照する変数を初期化します。したがって、ファイルの先頭にある場合は、

set colorimetric "-c"
ttk::checkbutton .f.colorimetric -variable colorimetric [...]

次に、finish関数で、

puts $::colorimetric
于 2009-05-05T19:00:26.267 に答える
0

「#Justhere」コメントに追加してみてください

$::gretagNumを置きます

::はグローバル変数を意味し、ウィジェットの-variableオプションは常にグローバルです。

于 2008-12-26T10:26:25.780 に答える
0

何をしたいのかわかりません。変数の内容ではなく変数名の出力を終了する場合は、関数としてsetコマンドを使用してください。

コンテンツを「こんにちは」に設定

何とかコンテンツを設定する

もし、するなら:

puts $blah 

..コンテンツであるblah変数のコンテンツを取得します。

blahを介して可変コンテンツのコンテンツを取得するには、次を使用します。

puts [set $blah]
于 2009-01-20T21:33:02.677 に答える
0

このルールを覚えておけば、いつでも正しく理解できます。

$foo is shorthand for [set foo]

[set foo] でコードを書き直してみてください。

特に、

$$foo  ;# not what you think

に置き換えられます

[set [set foo]]   ;# does what you think
于 2009-01-21T07:53:13.953 に答える
0

ここに小さな tcl スニペットがあります - tclsh または Wish から実行します

[nigel@rose ~]$ wish
% set foo /dev/ttys0
/dev/ttys0
% puts $foo
/dev/ttys0
% puts "$foo"
/dev/ttys0
% puts [$foo]
invalid command name "/dev/ttys0"
% puts ($foo)
(/dev/ttys0)
% puts {$foo}
$foo
% 

Tcl での引用:

  • ""(二重引用符): 置換の評価 ($variable)

  • {}{波括弧): 文字列全体を置換なしのリテラルとして扱います

  • [](角括弧): 文字列を置換付きのコマンドとして実行します

別の方法として、ダイアログ ボックスに診断をポップアップ表示することもできます。

% set mb [tk_messageBox -message "Port is $foo" -type ok -icon info]
ok
% 
于 2008-12-24T22:57:34.610 に答える