カテゴリー別アーカイブ: Curlにて実現したい動作について

Curlに対する要求仕様について、過去にお問い合わせの多かった事例を紹介いたします。記載日時点での状況(最新or問い合わせ時指定バージョンにおける仕様)を元に回答したものです。
 

特定コントロールをTab遷移対象外にする方法

【ご質問】
特定のコントロールをTAB(Shift+TAB)の遷移対象外とすることは可能でしょうか。

【回答】
非ローカルオプションである”active-traversal-container”にnullを設定することで実現可能です。

詳細は以下のサンプルをご参照ください。

{curl 6.0,7.0,8.0 applet}

{let
    text1:TextField = {TextField},
    text2:TextField = {TextField
                                 active-traversal-container = null
                             },
    text3:TextField = {TextField}
}

{VBox
    text1,
    text2,
    text3
}

また、Curl開発者ガイドの
[グラフィカル ユーザー インターフェイス]-[ダイアログとコントロール]-[ダイアログの使用]
の項をご参照ください。 

Enterキーによるフォーカス移動

◆ご質問◆
Enterキー、Shift+Enterキーでフォーカス遷移させることは可能でしょうか。

◆回答◆
コントロールで特定のキーが押された時にフォーカスを遷移させることは可能です。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{define-class public MyTextField {inherits TextField}

  {constructor public {default …}
    {construct-super …}
  }

  {method public {on-key-press e:KeyPress}:void
    {if e.value == KeyPressValue.enter then
        {if-non-null self.active-traversal-container then
            {self.active-traversal-container.traverse forward? = not e.shift?}
        }
    }
    {super.on-key-press e}
  }
}
{value
    {VBox spacing = 10pt,
        {MyTextField width = 200pt},
        {MyTextField width = 200pt},
        {MyTextField width = 200pt}
    }
}

RecordGridの自動計算

【ご質問】
RecordGridにて値を入力して別のセルにカーソルが移動したときに
累積値を再計算して表示することは可能でしょうか?

【回答】
カスタムセルを使用し、”note-grid-focus-out”メソッド内で
計算を行うロジックを呼び出すことで実現可能です。

詳細は以下のサンプルをご参照ください。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let price:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField
                “value”, domain = float
            },
            {RecordField
                “number”, domain = float
            },
            {RecordField
                “price”, domain = float
            }
        },
        {RecordData value = 1000, number = 2, price = 2000},
        {RecordData value = 1000, number = 3, price = 3000},
        {RecordData value = 1000, number = 4, price = 4000}
    }
}

{let rg:RecordGrid =
    {RecordGrid
        height = 5cm,
        width = 9.75cm,
        record-source = price,
        {RecordGridColumn “value”, editable? = true, cell-spec = ControlCell},
        {RecordGridColumn “number”, editable? = true, cell-spec = ControlCell},
        {RecordGridColumn “price”, editable? = false, cell-spec = ControlCell}
    }
}

{define-proc public {calc index:int}:void
    let r:#Record = rg.records[index]
    let value:float = r[“value”]
    let number:float = r[“number”]
    set r[“price”] = value * number
}

{define-class public ControlCell {inherits StandardStringCell}

  field index:int

  {constructor public {default}
    {construct-super}
    set self.index = 0
  }

  {method public {note-grid-focus-in}:void
    {super.note-grid-focus-in}
    set self.index = rg.current-index
  }

  {method public {note-grid-focus-out}:void
    {super.note-grid-focus-out}
    {calc self.index}
  }
}

{value
    {VBox
        rg
    }
}

Recordの入れ替え

【ご質問】
RecordGridの1行目と2行目の情報を入れ替えることはできるのでしょうか?

【回答】
レコード自身を入れ替えることは困難ですが、
中身のデータ自身を入れ替えることで、レコードを入れ替えたように見せることは可能です。 

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let people:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField
                “First”, caption = “first name”, domain = String
            },
            {RecordField
                “Last”, caption = “last name”, domain = String
            },
            {RecordField
                “Age”, caption = “age”, domain = int
            }
        },
        {RecordData First = “First1”, Last = “Last1”, Age = 10},
        {RecordData First = “First2”, Last = “Last2”, Age = 20},
        {RecordData First = “First3”, Last = “Last3”, Age = 30}
    }
}
{let rg:RecordGrid =
    {RecordGrid
        height = 3cm, width = 9.75cm, record-source = people
    }
}
{value
    {VBox
        rg,
        {CommandButton
            width = {make-elastic},
            label = “change”,
            {on Action do
                let record1:Record = rg.records[0]
                let record2:Record = rg.records[1]

                ||1行目のデータを保持させる
                let new-record:Record = {people.new-record}
                set new-record[“First”] = record1[“First”]
                set new-record[“Last”] = record1[“Last”]
                set new-record[“Age”] = record1[“Age”]

                ||1行目 ← 2行目
                set record1[“First”] = record2[“First”]
                set record1[“Last”] = record2[“Last”]
                set record1[“Age”] = record2[“Age”]

                ||2行目 ← 保持していたデータ
                set record2[“First”] = new-record[“First”]
                set record2[“Last”] = new-record[“Last”]
                set record2[“Age”] = new-record[“Age”]

                ||保持用レコードの削除
                {new-record.delete}
            }
        }
    }
}

Dialogの座標取得

【ご質問】
現在表示しているDialogの左上の座標(X,Y)を
Windowの左上隅基準で取得する方法はあるのでしょうか?。

【回答】
{Dialog.get-view}.get-window-position}でDialogの座標を取得することが可能です。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let btn:CommandButton = {CommandButton
                                              label = “ポップアップ表示”
                                       }
}
{let btn2:CommandButton = {CommandButton
                                              label = “座標を表示”
                                         }
}
{let from-window:VBox = {VBox}}
{let v:VBox = {VBox
                        {Fill height = 0.1cm},
                        btn2,
                        {Fill height = 0.1cm},
                        “Windowからの座標は・・・”,
                        from-window
                    }
}
{let myDialog:Dialog = {Dialog
                                     width = 5cm,
                                     height = 5cm,
                                     v
                                 }
}

{btn.add-event-handler
    {on Action do
        {myDialog.show}
    }
}
{btn2.add-event-handler
    {on Action do
        {from-window.clear}
        {let (x:Distance, y:Distance) = {{myDialog.get-view}.get-window-position}}
        {from-window.add
            {VBox
                {HBox “X = “, x},
                {HBox “Y = “, y}
            }
        }
    }
}

{VBox
    btn
}

RecordGridのヘッダー列のコピー

【ご質問】
レコードグリッドで特定の行を選択しコピーした際、ヘッダー列名も合わせて
コピーすることはできますでしょうか。

【回答】
RecordGridCopyの”execute”メソッドを改変することで実現可能となります。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{import * from CURL.DESKTOP.CLIPBOARD}

{define-class public MyRecordGridCopy {inherits RecordGridCopy}
  {constructor public {default …}   
    {construct-super …}
  }
   
  {method protected open {execute}:void 
    {super.execute}

    let constant line-delimiter:char = ‘\n’
    let constant cell-delimiter:char = ‘\t’
   
    let (value:String, valid?:bool) = {{Clipboard.get-system-clipboard}.get-string}
    let new-string:StringBuf = {StringBuf}
    {for r:RecordGridColumn in self.context.columns do
        {new-string.concat r.field-name}
        {new-string.append cell-delimiter}
    }
    {new-string.remove (new-string.size – 1), error-if-missing? = false}
    {new-string.append line-delimiter}
    {new-string.concat value}

    {{Clipboard.get-system-clipboard}.set-string new-string}
  }
}

{define-class public MyRecordGrid {inherits RecordGrid}
  {constructor public {default …}
    {construct-super …}
  }
  {method public open {create-command name:String}:#Command
    {return
        {switch name
         case “copy”  do {MyRecordGridCopy self}
         else
            {super.create-command name}
        }
    }
  }
}

{let people:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField “First”, domain = String},
            {RecordField “Last”, domain = String},
            {RecordField “Age”, domain = int}
        },
        {RecordData First = “John”, Last = “Smith”, Age = 25},
        {RecordData First = “Jane”, Last = “Smith”, Age = 29},
        {RecordData First = “Jane”, Last = “Jones”, Age = 28}
    }
}
{let rg:MyRecordGrid = {MyRecordGrid
                           record-source = people,
                           height = 13cm,
                           automatic-columns? = false,
                           {RecordGridColumn  “First”},
                           {RecordGridColumn  “Last”},
                           {RecordGridColumn  “Age”}
                       }
}
{value
    rg
}

ComboBoxの自動展開

【ご質問】
コンボボックスにてテキスト部分に値を入力した時、ドロップダウンリスト部分を
自動で展開することは可能でしょうか?

【回答】
SkinnableComboBoxUIクラスの{show-dropdown}メソッドを呼び出すことで
選択一覧の展開が可能です。

詳細は以下のサンプルをご参照ください。

{curl 7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let cb1:ComboBox = {ComboBox width=3cm,
                        “Red”, “Yellow”, “Green”
                    }
}
{let cb2:ComboBox = {ComboBox width=3cm,
                        “Red”, “Yellow”, “Green”
                    }
}

{cb1.add-event-handler
    {on ValueChanged at cb:ComboBox do
        {(cb.ui-object asa SkinnableComboBoxUI).show-dropdown}
    }
}
{cb2.add-event-handler
    {on FocusIn at cb:ComboBox do
        {(cb.ui-object asa SkinnableComboBoxUI).show-dropdown}
    }
}

{VBox
    {text font-weight = “bold”, 1.ValueChanged発生時にリスト展開するComboBox},
    cb1,
    {Fill height = 3cm},
    {text font-weight = “bold”, 2.FocusIn発生時にリスト展開するComboBox},
    cb2,
    {Fill height = 3cm},
    {CommandButton
        label = “2のComboBoxのリストを展開する”,
        {on Action do
            {(cb2.ui-object asa SkinnableComboBoxUI).show-dropdown}
        }
    }
}

また、APIリファレンスの
[CURL.GUI.CONTROL-UI-SKINNABLE]-[SkinnableComboBoxUI]
の項をご参照ください。

ファイル保存ダイアログのデフォルト表示について

【ご質問】
ファイル保存ダイアログで、デフォルトのファイル名を表示する方法はありますか。

【回答】
choose-fileプロシージャ等にあるオプション default-location に絶対パスを指定することで、
デフォルトのファイル名・ロケーションを任意に設定することができます。

また、get-working-directory-url、get-host-working-directory-urlを使用することで
「OS自身で持っている作業ディレクトリ」、
「アプリケーションプロセスの作業ディレクトリ(通常はアプリケーションがあるディレクトリ)」
を指定することが出来ます。

以下のサンプルをご参照ください。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{import * from CURL.RUNTIME.HOST-ENVIRONMENT}

{let filters:{Array-of FileDialogFilter} =
    {new
        {Array-of FileDialogFilter},
        {FileDialogFilter
            “Text files”,
            {new
                {Array-of FileDialogTypeFilter},
                {FileDialogTypeFilter “txt”}
            }
        },
        {FileDialogFilter
            “All Files”,
            {new
                {Array-of FileDialogTypeFilter},
                {FileDialogTypeFilter “*”}
            }
        }
    }
}

{VBox
    {CommandButton
        label = “default-location = get-host-working-directory-url”,
        {on Action do
            {choose-file
                style=FileDialogStyle.save-as,
                filters=filters,
                default-location={url {get-host-working-directory-url}&“/text.txt”}
            }
        }
    },
    {CommandButton
        label = “default-location = get-working-directory-url”,
        {on Action do
            {choose-file
                style=FileDialogStyle.save-as,
                filters=filters,
                default-location={url {get-working-directory-url}&“/text.txt”}
            }
        }
    },
    “「保存」を押してもファイルは作成されません”
}

キーボードショートカットについて

【ご質問】
画面上で、ファンクションキー(F1など)が押された場合に、
画面上の特定のボタンのActionイベントを実行することはできますでしょうか?

【回答】
GuiManagerに対してRawKeyPress等のイベントを設定し、
処理を行う条件にKeycodeを指定することで実現可能です。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let dsp-msg-btn:CommandButton = {CommandButton
                                     label=“メッセージを表示(F1)”,
                                     {on Action do
                                         {popup-message “TEST”}
                                     }
                                 }
}

{let gm:GuiManager = {get-gui-manager}}

{gm.add-event-handler
    {on raw-key-event:RawKeyPress do
        {if raw-key-event.keycode == Keycode.f1 then
            {dsp-msg-btn.take-action}
        }
    }
}

{value
    dsp-msg-btn
}

TextFieldの背景色の変更

【ご質問】
テキストフィールドの背景色を変更することは可能でしょうか?

【回答】
“control-content-background”を設定することで、コントロールの背景色を変更することが可能です。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “utf8”}

{View
    {Frame
        width = 8cm,
        height = 8cm,
        control-appearance-changeable?=true,
        control-content-background=“yellow”,
        {TextField
            value=“Curl Developer Center”
        }
    },
    visibility = “normal”,
    {on WindowClose do
        {exit}
    }
}

編集不可時の文字色の設定

【ご質問】
enabled?=false を指定して編集不可にすると、文字がグレーになって読みにくくなってしまいます。
文字をグレーにせずにコントロールを編集不可にするにはどうすればよいのでしょうか?

【回答】
編集不可(enabled? = false)に設定した際の文字の色は、
disabled-colorで定義した色が表示されます。
disabled-colorのデフォルト値は”gray”のため、グレーで表示されます。

任意の色に設定したい場合はdisabled-colorを変更すれば可能となります。 

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let text1:TextField =
    {TextField
        value = “Curl Developer Center”,
        enabled? = false,
        disabled-color = “blue”,
        disabled-text-sunken? = false
    }
}

{let text2:TextField =
    {TextField
        value = “Curl Developer Center”,
        enabled? = false
    }
}

{VBox
    text1,
    text2
}

DropdownListの選択肢幅の調整

【ご質問】
コントロールの幅と選択肢の幅を違うサイズで表示したいのですが、
どうすればよいでしょうか?

【回答】
カスタムコントロールUIの作成を行うことで実現可能です。
StandardLookAndFeelのインスタンスを作成し、
オプション値を変更することでコントロールの外観を変更できます。

※尚、Ver 7以降はカスタムコントロールUIを作成する必要はありません。
 何も設定しなくても自動で選択肢の幅を調整します。

{curl 6.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{define-class public MyDropdownListUI {inherits StandardDropdownListUI}

  {constructor public {default control:#DropdownList=null, …}
    {construct-super control = control, …}
  }

  {getter protected open {dropdown-width}:Distance
    {return 300pt}
  }
}

{let standard-look-and-feel:StandardLookAndFeel = {StandardLookAndFeel}}

{let registered:bool = {standard-look-and-feel.register-ui
                           DropdownList,
                           MyDropdownListUI
                       }
}

{let list:DropdownList = {DropdownList
                             look-and-feel = standard-look-and-feel,
                             width = 3cm,
                             “sample1”,
                             “sample2”,
                             “sample3”,
                             “sample_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4”,
                             value = “sample1”
                         }
}

{value
    list
}

ツールチップの表示・非表示

【ご質問】
テキストフィールドにツールチップの設定を行っていると、
対象フィールドの値が空の場合、小さい「□」が表示されてしまいますが、
値が空の場合は、それを非表示にする事はできないのでしょうか?

【回答】
対象フィールドの値が空の場合、TextField.tooltipにnullを設定することで、
ツールチップを非表示にすることができます。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let text:TextField =
    {TextField width = 3cm,
        {on e:ValueChanged at t:TextField do
            set t.tooltip = {if t.value == “” then
                                    null
                                 else
                                    {Tooltip style = “immediate”, t.value}
                                 }
        }
    }
}

{value
    text
}

CommandButtonで中央寄せで表示する方法

【ご質問】
CommandButtonで、text-breakable?をtrueにセットし、2行で表示時に
左寄せで文字が表示されます。
中央寄せで表示する方法を教えてください。

【回答】
“paragraph-justify=center”を指定したTextFlowBoxを
CommandButton.labelに設定することで実現可能となります。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let text:TextFlowBox = {TextFlowBox
                            paragraph-justify = “center”,
                            “あああああいいいいいうううううええ”
                        }
}

{let btn:CommandButton = {CommandButton
                             width = 60pt,
                             text-breakable? = true,
                             label = (text asa Label)
                         }
}

{VBox
    btn
}

詳細は、APIリファレンスの
[CURL.GUI.BASE]-[TextFlowBox]の項と
上記項内のプロパティ[paragraph-justify]の項をご参照ください。

Dialogの派生クラスで、shiftキーが押されたイベントを取得する方法

【ご質問】
Dialogの派生クラスで、shiftキーが押されたイベントを取得するには
どのような方法があるでしょうか?(on-raw-key-pressメソッドで取得できない?)

【回答】
特定のDialogのみで”キー押下時のイベント”を取得することはできません。

もし、アプレット全体でイベントを取得することが許されるのであれば、
GuiManagerにイベントを追加することで可能となります。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let frame:Frame = {Frame}}
{let dialog:Dialog = {Dialog
width = 5cm,
height = 5cm,
{VBox
“↓実行されたイベントを表示”,
frame
}
}
}
{let btn:CommandButton = {CommandButton
label = “ポップアップ表示”,
{on Action do
{dialog.show}
}
}
}

{let gm:GuiManager = {get-gui-manager}}
{gm.add-event-handler
{on raw-key-event:RawKeyPress do
{if raw-key-event.shift? == true then
{frame.add
replace? = true,
raw-key-event
}
{dump “TEST—“}
}
}
}

{VBox
btn
}

 

 

フォーカスアウトした場合に必ずValueFinished イベントを発生させたい

【ご質問】
TextFieldのValueFinished イベントについて、
TextFieldのAPIで以下の記載があります。
「イベントは、value が最後の ValueFinished から変化した場合に必ず発生しますが、
value が変化しなかった場合でも発生することがあります。」

値が変更されていない場合においても
フォーカスアウトした場合に必ずValueFinished イベントを発生させることはできますでしょうか。

【回答】
FocusOutイベント実行時にset-value-with-eventsメソッドを
使用することで実現可能です。

{curl 6.0,7.0,8.0 applet}

{let tf1:TextField = {TextField
                         width = 3cm,
                         value = “Test12345”,
                         {on ValueFinished at tf:TextField do
                             {output “ValueFinished : “& tf.value}
                         },
                         {on e:FocusOut at tf:TextField do
                             {let str:String = tf.value}
                             {tf.set-value-with-events str}
                         }
                    }
}

{let tf2:TextField = {TextField
                         width = 3cm
                     }
}

{VBox
    tf1,
    tf2
}
 

コンピュータ名取得

【ご質問】
Curlアプレットから、クライアント端末のコンピュータ名を取得する方法はあるのでしょうか。

【回答】
標準APIを使った方法としては、get-from-host-environmentプロシージャで
“COMPUTERNAME”を取得する方法があります。

また、標準APIではありませんがspawn-host-shellを使ってWindowsコマンドの
hostnameを使用する方法もあります。
(この方法の場合は一瞬コマンドプロンプトが表示されます。)

以下のサンプルを参考にしてください。

{curl 6.0,7.0,8.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{import * from CURL.RUNTIME.HOST-ENVIRONMENT}
{import * from CURL.RUNTIME.HOST-PROCESS}

{let cb1:CommandButton =
    {CommandButton label = “get-from-host-environmentを使用”,
        {on Action do
            let env:String = {get-from-host-environment “COMPUTERNAME”}
            {popup-message env}
        }
    }
}
{let cb2:CommandButton =
    {CommandButton label = “spawn-host-shellを使用”,
        {on Action do
            def host-process =
                {spawn-host-shell
                    read-stdout? = true,
                    read-stderr? = true,
                    “hostname”
                }
            {with-open-streams
                stream = {host-process.read-open-stdout
                             character-encoding = {get-character-encoding-by-name “shift-jis”}
                         } do
                {while not stream.end-of-stream? do
                    {popup-message {stream.read-line}}
                }
            }
        }
    }
}

{VBox
    spacing = 1cm,
    cb1,
    cb2
}

それぞれのプロシージャの詳細は、APIリファレンスの
[CURL.RUNTIME.HOST-ENVIRONMENT]-[get-from-host-environment]
の項と
[CURL.RUNTIME.HOST-PROCESS]-[spawn-host-shell]
の項をご参照ください。