Delphi: Result への代入で、DCC ヒントが出るコードと出ないコードがある

Delphi, TIPS, プログラム, 開発 3 Comments »

ちょっとした動作についてのお話なんですけどね。

変数の型が違うことで、ヒントが出るコードと出ないコードがあったんですよ。

まずヒントが出ないコード。

function TForm1.f: string;
begin
  Result := '0';
  Result := '1';
end;

続いてヒントが出るコード。

function TForm1.f: Integer;
begin
  Result := 0;
  Result := 1;
end;

違いは、戻り値の型だけ。
後者は「’TFrorm1.f’ に代入された値は使われていません」DCC ヒントが3行目(Result := 0;)に対して出ます。
確かに代入した「0」は使われていませんわ。

どちらも複数回 Result に対して値を代入していますので、両方にヒントが出るのなら納得もできるのですが・・

何となく微妙な気持ちが消えません。

*

2010/08/03 追記

月夜見命さんのコメントで、値型と参照型の違いでは無いかとのこと。

下記のコードで試してみました。

type
  TMyClass = class
    public
      i: Integer;
  end;

implementation

function TForm1.f: string;
var
  MyClass: TMyClass;
begin
  MyClass := TMyClass.Create;

  MyClass.i := 10;

  Result := IntToStr(MyClass.i);
  Result := IntToStr(MyClass.i);
end;

確かにクラス型で参照させると、やはりヒントは出ないようです。
と言うことは、内部ででも参照が入るコードについてはヒントを出さない仕様と考えても良さそうでしょうかね。

月夜見命さん、ありがとうございます。

  • Share/Bookmark

Delphi: TField.OnGetText イベントの DisplayText パラメータについて

Delphi, TIPS, プログラム, 開発 No Comments »

Delphi でデータベースを扱う場合、表示系のコンポーネントには TField クラスが項目コンポーネントとして利用されています。

そして、この TField クラスの OnGetText イベントには DisplayText パラメータがあるのですが、その解釈がちょっとわかりづらかったのでメモしておきます。

*

何がわかりづらかったかと言うと、TField クラスには DisplayText というプロパティが存在するんです。

引数ではなく、プロパティ。

一緒だと思うと混乱します。

何せ前者は Boolean 型、後者は string 型を扱うプロパティですから。

*

まず TField は、

  1. 編集中で無い時は DisplayText プロパティの値を表示し、
  2. 編集中の時は Text プロパティの値を表示します。

そして、1. の<編集中で無い場合>の表示について、独自の書式などを適用したい場合に使うのが、OnGetText イベントなんですね。

たとえばこんな感じで、通常なら数値が直接表示される項目の表示を変えることができるわけです。

procedure TMyQuery.XXXGetText(Sender: TField;
  var Text: String; DisplayText: Boolean);
begin
  if Sender.AsInteger = 0 then begin
    Text := 'nothing'
  end else begin
    Text := 'not zero';
  end;
end;

表示したい値を Text パラメータに代入します。

ただし、DisplayText パラメータが True の時 Text パラメータに代入した値が有効になります(と言っても DisplayText パラメータは、デフォルト値 True ですが)。

DisplayText パラメータが False の場合(自分で値を代入した場合)、AsString の値が採用されます。

ちなみに、DisplayText を True にセットするのみのコードを記述すると、「’DisplayText’ に代入された値は使われていません」DCC 警告が出ます。

  • Share/Bookmark

Delphi: x2269: オーバーライドされた仮想メソッド ‘%s.%s’ の可視性が %s となり基本クラス ‘%s’ での可視性 (%s) より低くなりました

Delphi, TIPS, プログラム, 開発 No Comments »

「x2269: オーバーライドされた仮想メソッド ‘%s.%s’ の可視性が %s となり基本クラス ‘%s’ での可視性 (%s) より低くなりました」

現在、あるプロジェクト(他の会社製)の修正を行っているのですが、上記警告がかなり出ます。

この警告は、オーバーライドしたメソッドについて、基本クラスよりも派生クラスの可視性が低い場合に表示されるやつですね。

つまり、
基本クラスのメソッドが protected,public,published で宣言されているのに、
派生クラスのメソッドがで private,protected で宣言された場合です。

Delphi では、可視性の範囲が次の通りだからですね。

private < protected < public, published, automated

ヘルプには解決方法として3つありましたが、基本クラスに合わせるのが一番まっとうな解決策だと思います。

というか、無視するって言う解決方法って解決なのか?(笑

  • Share/Bookmark

PHP で twitter のツイートを検索してみる

PHP, TIPS, プログラム, 開発 No Comments »

PHP を用いて、特定のキーワードを含むツイートを twitter 上で探すプログラムを組んでみました。

↓こんな感じのプログラム
twitter search test

Twitter API 仕様書 (勝手に日本語訳シリーズ)を参考にしています。

CodeIgniter 用に Controller クラスで書いちゃってますが、中身は単純ですね。

class Twitter_test extends Controller {

    function Twitter_test()
    {
        parent::Controller();
        $this->output->set_header('Content-type: text/html; charset=utf-8');
    }

    function index()
    {
        echo '<style type="text/css">table,td,tr{border:1px solid gray;border-collapse:collapse;}</style>';
        echo form_open('twitter_test/');
        echo form_input('query', $this->input->post('query') ? $this->input->post('query') : '');
        echo form_submit('submit', 'twitter検索');
        echo '<br />';

        echo '<table>';
        echo '<tr><td>ユーザ名</td><td>つぶやき</td></tr>';
        if ($this->input->post('query')) {
            $query_url = 'http://search.twitter.com/search.atom?q=' . rawurlencode($this->input->post('query'));
            $contents = file_get_contents($query_url);
            $xml = simplexml_load_string($contents);

            foreach ($xml->entry as $entry) {
                $temp = array(
                    'id' => $entry->id,
                    'title' => $entry->title,
                    'content' => $entry->content,
                    'updated' => $entry->updated,
                    'link' => $entry->link['href'],
                    'author' => $entry->author->name,
                    'uri' => $entry->author->uri,
                );
                echo "<tr><td><a href='{$temp['uri']}' target='_blank'>{$temp['author']}</a></td><td>{$temp['updated']}<br /><a href='{$temp['link']}' target='_blank'>{$temp['title']}</a></td></tr>";
            }
        }
        echo '</table>';

        echo form_close();
    }

}

要は URL エンコードした検索ワードを REST 形式で API 呼び出しすればよい、と言うことですね。

来月(2010/07)からユーザー認証関係は変わってしまいますが、ここら辺の API は大丈夫そうですね。

  • Share/Bookmark

Delphi Prism (.NET Framework) を使って任意の形式の文字列を日付型(DateTime)に変換する方法

Delphi, TIPS, プログラム, 開発 No Comments »

Delphi Prism 2010 (というか .NET Framework) で、任意の形式の文字列を日付型(DateTime)に変換する方法についてのメモ。

何でこんな記事を書いているかと言うと、twitter の取得したデータの日付のフォーマットがこんな「Mon Jan 01 00:00:00 +0000 2010」だったんですね。

で、Parse メソッドでは対応していなかったので、その ParseExact メソッドを利用するという流れになりました。

ということで、次の様なコードを書いてみました。

var dt := DateTime.ParseExact('Mon Jan 01 00:00:00 +0000 2010', 'ddd MMM dd HH:mm:ss +0000 yyyy');

※ParseExact メソッドは、第1引数が変換対象の文字列、第2引数が書式、です

これで dt が作成されるかと思いきや、(おそらく)例外が発生します。

これは、たとえば「ddd」の部分はカルチャ固有の文字列が入るからなんですね。
※英語環境で動かしていれば、例外は発生しないでしょう

次のコードなどで確認できます。

var dt := new DateTime;
画面上のコントロール := dt.ToString('ddd MMM dd HH:mm:ss +0000 yyyy');

実行すると、「月 1 01 00:00:00 +0000 0001」と表示されるので、日本語のロケールで動いていることが判ります。

じゃぁどうすれば良いか。
カルチャを指定すれば良いです。

ParseExact メソッドの第3引数で指定します。

指定の仕方は簡単なのですが、カルチャ指定用の CultureInfo クラスが System.Globalization 名前空間にありますので、uses に追加するのを忘れないようにしましょう。

追加したら、先ほどのコードに第3引数を追加します。

var dt := new DateTime;
画面上のコントロール := dt.ToString('ddd MMM dd HH:mm:ss +0000 yyyy', CultureInfo.CreateSpecificCulture("en-US"));

画面には「Mon Jan 01 00:00:00 +0000 0001」と表示され、US のカルチャが適用されていることが確認できるでしょう。

これで、最初のコードも次の様にカルチャ指定をすることで、望みの結果を得ることができるようになります。

var dt := DateTime.ParseExact('Mon Jan 01 00:00:00 +0000 2010', 'ddd MMM dd HH:mm:ss +0000 yyyy', CultureInfo.CreateSpecificCulture("en-US"));
  • Share/Bookmark

Delphi Prism を使って HTTP 経由でデータを取得する方法

Delphi, TIPS, プログラム, 開発 2 Comments »

Delphi Prism 2010 を使い、HTTP 経由でデータを取得する方法についてのメモです。

いろいろ方法があるかと思いますが、.NET Framework の持つ System.Net 名前空間の WebRequest/WebResponse クラスを使うと簡単でした。

1点手間取った部分がありましたが・・

  var req : WebRequest := WebRequest.&Create('http://url.to/');
  var res : WebResponse := req.GetResponse;
  var st : Stream := res.GetResponseStream;
  if st <> nil then begin
    var reader := new StreamReader(st, System.Text.Encoding.GetEncoding('文字コードの指定'));
    //主処理
    st.Close;
  end;

コードは至ってシンプルです。

WebRequest クラスで接続先を指定し、WebReposnse クラスにその結果を読み込ませます。
後は、受け取った結果を Stream として処理するだけです。

reader.ReadToEnd; で全部読み込んでも良いですし、reader.ReadLine; を while でループしても良いでしょう。

手間取った部分というのは、WebRequest クラスの Create コンストラクタの呼び出し方法です。
表示の通り、「&」がメソッド名の前に付いていますね。

これは、Delphi Prism の構文において、Create メソッドはコンストラクタの扱いになるのですが、.NET Framework 上では通常のメソッドとして扱われるので、その扱いの違いでエラーしてしまうんですね。

だから、「&Create」と書くことで、キーワードの扱いにしてあげているんです。

参考:Prism Wiki

本家でもここら辺で語られています。

  • Share/Bookmark

Windows 7 の環境で Delphi 2010 に RemObjects Pascal Script をインストールしてみる

Delphi, TIPS, プログラム, 環境設定, 開発 No Comments »

Windows 7 の環境で、Delphi 2010 に RemObjects Pascal Script をインストールして使ってみました。

RemObjects Pascal Script とは、Delphi で作ったアプリケーションに、Pascal 形式のスクリプト実行機能を追加できるコンポーネントです。

次の画像の様に、自分で書いたスクリプトを実行することができます。

Delphi Pascal Script

とりあえずダウンロードします。

2010/03/02 版は Delphi 2010 をサポートしています。

インストールは、ダウンロードしたバイナリを実行すれば問題ありません。

ただし、コンポーネントを初めて使う際、Program Files 下にインストールされたプロジェクトファイルをコンパイルするため、Windows Vista/7 の一般ユーザで動作させた Delphi 2010 では、ファイルが書き込めないことが原因で致命的エラーが発生します。

回避策としては、Pascal Script のプロジェクトのバイナリ出力先を変更するか、管理者権限で Delphi 2010 を動かすことになるかと思います。

自分は後者を選択しました。
スタートメニューから実行する際、シフトキーを押しながら右クリックし、「管理者として実行」を選択します。

*

これ以降は、本家の記事を元に書きました。

ソースを入力する用の TMemo、実行イベント用の TButton、今回のメイン コンポーネントである TPSScript を配置します。

↓こんな感じ
コンポーネントの配置

で、このサンプルでは Delphi の ShowMessage() を、Pascal Script から呼び出す機能を作っています。

手順としては次の通り。

  1. Delphi 側で呼び出される関数(ShowNewMessage())を作成
  2. TPSScript コンポーネントに呼び出す関数を登録(ShowNewMessage())

あとは、TPSScript.Execute するだけです。

実際のコードです。

  1. Delphi 側で呼び出される関数(ShowNewMessage())を作成

    procedure TForm1.ShowNewMessage(const Message: string);
    begin
      ShowMessage('ShowNewMessage invoked:'#13#10 + Message);
    end;
    
  2. TPSScript コンポーネントに呼び出す関数を登録(ShowNewMessage())

    procedure TForm1.PSScript1Compile(Sender: TPSScript);
    begin
      Sender.AddMethod(
        Self,
        @TForm1.ShowNewMessage,
        'procedure ShowNewMessage(const Message: string);'
      );
    end;
    

Delphi で作成した ShowNewMessage() を Pascal Script から呼べるように、TPSScript の Compile イベント内で AddMethod() していることが読み取れます。

準備ができたら、ボタンをクリックした際に Memo1 内に書かれたスクリプトが実行されるようにイベントハンドラを記述します。

ボタンのイベントハンドラ

procedure TForm1.Button1Click(Sender: TObject);
begin
  PSScript1.Script.Text := Memo1.Lines.Text;

  if PSScript1.Compile then begin
    PSScript1.Execute;
  end else begin
    ShowMessage('error');
  end;
end;

Memo1 に書いた、Pascal Script

begin
  ShowNewMessage('This is it!');
end.

参考までに、このプロジェクトの宣言部を残しておきます。

type
  TForm1 = class(TForm)
    PSScript1: TPSScript;
    Memo1: TMemo;
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure PSScript1Compile(Sender: TPSScript);
  private
    { Private 宣言 }
  public
    procedure ShowNewMessage(const Message: string);
    { Public 宣言 }
  end;

以上でおしまいです。

自分のアプリケーションにスクリプト機能を追加できるというのは、なかなか面白いですね。

なお、同じ PC にインストールしている Delphi 2007 にも同時にインストールされました。

  • Share/Bookmark

PHP で複数行の文字列を扱う方法について

PHP, TIPS, プログラム No Comments »

PHP では文字列型として string が存在していますが、その扱いは次の4種類に分かれています。

  • 引用符
  • 二重引用符
  • ヒアドキュメント構文
  • nowdoc 構文(PHP 5.3.0~)

この中で、複数行の文字列を扱う方法については一般的にヒアドキュメントが有名なのでは無いかと思います。

しかし、用途によっては(二重)引用符を利用した場合の方が記述が簡単な場合もあるので、メモしておきます。

引用符、二重引用符

PHP では、この2種類の引用符で囲われた内容を文字列として扱います。

前者は「変数」や「特殊文字(エスケープシーケンス)」を展開せず、後者は展開しますね。

ここでポイントとなるのが、内容に含められる文字は空白や改行文字も対象となることです。

ですので、次のソースは問題なく動作します。

$a = '変数です!';

$var1 = '
    $a
    1つめ
    echo だよ。
';
echo $var1;

$var2 = "
    $a
    2つめ
    print だよ。
";
print($var2);

ただし、HTML としての改行(br タグ)は含まれていないので、ブラウザで表示しても下記のように1行に見えます。

$a 1行目 echo だよ。 変数です! 2行目 print だよ。

2つめはきちんと変数 $a が展開されていることもわかりますね。

ヒアドキュメント

ヒアドキュメントとは、上記の2つめの表記方法(二重引用符)の別バージョンと考えても良いでしょう。

ですので、次のコードはきちんと動作します。

$var3 =< <<_EOT_
    $a
    3つめ
    Heredoc だよ。
_EOT_;
print($var3);

表示は次の通り。

変数です! 3つめ Heredoc だよ。

Newdoc
PHP 5.3.0 以降では、Newdoc 表記が追加されました。
引用符として扱うこと以外は、ヒアドキュメントとすべて同じ条件で利用することが可能です。

たとえば次のコードです。

$var4 =< <<'_EOT_'
    $a
    4つめ
    Newdoc だよ。
_EOT_;
print($var4);

表示は次の通りになるはずです(これだけ未検証)。

$a 4つめ Newdoc だよ。

HTML や SQL を PHP 内部で記述したいぐらいの記述には、ヒアドキュメントで無くても、引用符を使うので十分かもしれませんね。
※本来入れるべきでは無いなどの話は横に置いておいて・・

*

参考:PHP: 文字列

  • Share/Bookmark

PHP CodeIgniter と xajax でファイルをアップロードする方法について考察してみる

PHP, TIPS, プログラム, 開発 1 Comment »

ある案件で、JavaScript でポップアップ表示させたフォームから、ファイルのアップロードを行うシステムを構築することになりました。

しかし、JavaScript では、セキュリティの都合によりファイルをアップロードすることができません。
xajax でも当然その制限を受けることになります。

なんとか実現できないか方法を探してみたところ、次の2方法が考えられるようです。

  • iframe でファイルアップロード用のフォームを作り、そこからアップロードさせる方法
  • flash などのアップロード用のプラグインを利用する方法

とりあえずは、iframe を利用した方法を検証してみました。

以下コードです。
パスは環境に合わせて適当に読み替えてください。

file_upload.php

< ?php

class File_upload extends Controller {

    /*
     * コンストラクタ
     */
    function File_upload()
    {
        parent::Controller();
        $this->load->library('useXajax');
        $this->xa->register(XAJAX_FUNCTION, array(&amp;amp;$this, 'do_file_up'));
        $this->xa->processRequest();
    }

    /*
     * フォームの表示
     */
    function index()
    {
        echo $this->xa->getJavascript(base_url() . '../js/');
        echo < <<_EOT_
<form id="form1" name="form1" method="post" action="">
    <iframe src="file_upload/upload_form/"></iframe>
    <input type="button" value="test" onclick="parent.frames[0].submitform;xajax_do_file_up(xajax.getFormValues(), parent.frames[0].document.userform.userfile.value);"/>
    <input type="hidden" value="" name="filename"/>
    <div id="dump"></div>

_EOT_;
    }

    /*
     * ファイルアップロード用フォームの表示
     */
    function upload_form() {
        //CodeIgniter のファイルアップロードクラスを利用
        $config['upload_path'] = './uploads/';
        $config['allowed_types'] = 'gif|jpg|png';
        $config['max_size'] = '100';
        $this->load->library('upload', $config);

        if ( ! $this->upload->do_upload()) {
            //初回でもエラーが表示されます
            echo 'error:' . $this->upload->display_errors();
        } else {
            echo 'success:' . var_dump($this->upload->data());
        }

        echo < <<_EOT_
<html>
<head>
<title></title>
<script type="text/javascript">
function submitform() {
    document.userform.submit();
}
</script>
</head>
<body>
<form id="userform" name="userform" method="post" enctype="multipart/form-data" action="">
    <input type="file" name="userfile" />
</form>
</body>

_EOT_;
    }

    /*
     * ファイルアップロード後の処理
     */
    function do_file_up($formValues, $filename)
    {
        $xr = new xajaxResponse;
        //ファイルアップロード用のフォームを submit させる
        $xr->call("parent.frames[0].submitform");
        //アップロードしたファイル名を表示
        $xr->assign('dump', 'innerHTML', date('H:i:s') . print_r($formValues, True) . $filename);
        return $xr;
    }
}
?>

上記のコードでは、親フレームではファイル名しか取得できませんし、IE/firefox などのブラウザの互換性の問題(ファイル名の扱いにパスを含めるかどうかなど)もあります。
実際のシステムでは、セッションなどを使ったファイル情報のやりとりをする必要が出てくるかと思います。

とりあえず、情報が少ないので参考になれば、のコードだと思ってください。

  • Share/Bookmark

bat ファイルでファイルを結合する

TIPS, プログラム, 開発 No Comments »

複数の CSV ファイルを結合する場面に出会ったので、思い出してみると・・
これだけでした。。

copy *.csv all.csv
  • Share/Bookmark
WP Theme & Icons by N.Design Studio
Entries RSS Comments RSS ログイン