Forum und email

Hello World (上級)

このチュートリアルでは、最初の hello world チュートリアルより もうすこし高度な機能を扱います。ここではログイン画面を作成し、 ユーザ名とパスワードを入力してもらうようにします。 ユーザがログインボタンをクリックした際にテキストフィールドの内容をチェックし、 ユーザ名やパスワードが入力されていない場合にエラーメッセージを表示します。

これが、最終的なプログラムの実行画面です。

まず最初にウィンドウを作成し、タイトルを設定します。 そして、ウィンドウが破棄された際にメインループを終了させるようにします。 これらについては最初のチュートリアルで説明しました。

$wnd = new GtkWindow();
$wnd->set_title('Login');
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));

次に行うことは、このダイアログで必要な全ウィジェットを作成することです。 最初に、二つのテキスト入力フィールドを作成します。 それぞれユーザ名とパスワードを入力するためのものです。

$txtUsername = new GtkEntry();
$txtPassword = new GtkEntry();

ユーザに対して、 そのテキストフィールドがユーザ名用なのかパスワード用なのかを説明しなければなりませんね。 そこで、説明用のラベルが必要になります。

//The second parameter says that the underscore should be parsed as underline
$lblUsername = new GtkLabel('_Username', true);
$lblPassword = new GtkLabel('_Password', true);

最後に、二つのボタンが必要です。まずログイン用のボタン、 そしてキャンセル用のボタンです。

$btnLogin    = new GtkButton('_Login');
$btnCancel   = new GtkButton('_Cancel');

GtkLabel のコンストラクタに二番目のパラメータを渡していることにお気づきでしょうか。 これは、_ をその次の文字のアンダーラインとして表示させるものです。 しかし、GtkButton のコンストラクタにはこのパラメータがありません。 ボタンのコンストラクタは、この処理を自動的に行います。 一方、ラベルは自動的には行いません。 ちょっと不思議に感じられるかもしれません。 しかし、ボタンのラベルにニモニックを指定することは多いでしょうが、 単なるラベルの場合にはそれほど多くはないですよね。

さて、ラベルのニモニックが入力された際に どのウィジェットをアクティブにするかを指定しなければなりません。 このように指定します。

$lblUsername->set_mnemonic_widget($txtUsername);
$lblPassword->set_mnemonic_widget($txtPassword);

さらに、ボタンがクリックされた際にどのアクションが実行されるのかを決める必要があります。 キャンセルボタンを押すとウィンドウを破棄 (アプリケーションを終了) し、ログインボタンを押すと、 テキストフィールドの内容をチェックしてその先に進むようにします。

$btnCancel->connect_simple('clicked', array($wnd, 'destroy'));
$btnLogin ->connect_simple('clicked', 'login', $wnd, $txtUsername, $txtPassword);

三つのウィジェット $wnd$txtUsername および $txtPassword を、(後で定義する) login 関数のオプションパラメータとして渡します。なぜなら、そこでこれらが必要になるからです。 テキストフィールドの値を取得したり、 すべてが正常に進んだ場合にウィンドウを破棄したりする際に使用します。

必要なウィジェットがすべてそろったので、それをウィンドウに追加します。 GtkWindow は bin コンテナなので、 ウィジェットをひとつだけしか保持することができません。そこで、 複数のウィジェットを保持でき、それらをきれいに並べることのできるコンテナが必要となります。 ここでは GtkTable を使用します。 これを使用すると、ひとつのカラムにラベルをおき、 その隣に入力フィールドをおいたりすることができるからです。

$tbl = new GtkTable(3, 2);
$tbl->attach($lblCredit, 0, 2, 0, 1);
$tbl->attach($lblUsername, 0, 1, 1, 2);
$tbl->attach($txtUsername, 1, 2, 1, 2);
$tbl->attach($lblPassword, 0, 1, 2, 3);
$tbl->attach($txtPassword, 1, 2, 2, 3);

($lblCredit は、メッセージを表示するためのラベルです)。 ボタンには GtkHButtonBox を使用します。 このクラスを使用すると、複数のボタンをうまい具合に配置することができるからです。

$bbox = new GtkHButtonBox();
$bbox->set_layout(Gtk::BUTTONBOX_EDGE);
$bbox->add($btnCancel);
$bbox->add($btnLogin);

配置の最後の仕上げは、テーブルとボタンボックスをウィンドウに追加することです。 直接これを行うことはできません。なぜなら GtkWindowGtkBin であり、ウィジェットをひとつだけしか保持できないからです。 そこで別のコンテナ、今回は GtkVBox を使用します。

$vbox = new GtkVBox();
$vbox->pack_start($tbl);
$vbox->pack_start($bbox);

これで完了です。ウィンドウを表示しましょう。

$wnd->add($vbox);
$wnd->show_all();
Gtk::main();

最後に残ったのが login 関数です。 これは、ユーザがログインボタンをクリックした際にコールされます。 この関数は、ユーザ名とパスワードの入力値をチェックします。 その長さが 0 (何も入力していなかった) の場合にエラーメッセージを表示します。 すべてが正常だった場合は、ウィンドウが破棄され、 メインウィンドウを読み込みます。

ウィジェットからテキストを取得するのは簡単です。 GtkEntryget_text() メソッドを使用します。

$strUsername = $txtUsername->get_text();
$strPassword = $txtPassword->get_text();

入力のチェックには、PHP の strlen 関数を使用します。 エラーが発生した場合には、メッセージボックスでメッセージを表示します。 このような場合には GtkMessageDialog が最適です。 これは自動的にアイコンとボタン (Ok, Yes/No) を作成します。

$dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, $errors);
$dialog->set_markup("The following errors occured:\r\n<span foreground='red'>" . $errors . "</span>");
$dialog->run();
$dialog->destroy();

login 関数はメインループの前に (!) 書くようにし、メインループを実行します。

例 3.1. 完全なプログラム

<?php
/**
*   Here we create a login window.
*   It has a username and a password field, and a
*   Cancel and Login button. Some error checking
*   is being done when the user clicks "Login".
*/

if (!class_exists('gtk')) {
    die("Please load the php-gtk2 module in your php.ini\r\n");
}

/**
*   This function gets called as soon as the user 
*   clicks on the Login button.
*
*   @param GtkWindow $wnd           The login window, needed to close it
*                                    when all is ok
*   @param GtkEntry $txtUsername    The username text field, used to get
*                                    the username
*   @param GtkEntry $txtPassword    The password widget to retrieve the
*                                    password
*/
function login(GtkWindow $wnd, GtkEntry $txtUsername, GtkEntry $txtPassword)
{
    //fetch the values from the widgets into variables
    $strUsername = $txtUsername->get_text();
    $strPassword = $txtPassword->get_text();

    //Do some error checking
    $errors = null;
    if (strlen($strUsername) == 0) {
        $errors .= "Username is missing.\r\n";
    }
    if (strlen($strPassword) == 0) {
        $errors .= "No password given.\r\n";
    }

    if ($errors !== null) {
        //There was at least one error.
        //We show a message box with the errors
        $dialog = new GtkMessageDialog($wnd, Gtk::DIALOG_MODAL,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, $errors);
        $dialog->set_markup(
            "The following errors occured:\r\n"
            . "<span foreground='red'>" . $errors . "</span>"
        );
        $dialog->run();
        $dialog->destroy();
    } else {
        //No error. You would need to hide the dialog now
        //instead of destroying it (because when you destroy it,
        //Gtk::main_quit() gets called) and show the main window
        $wnd->destroy();
    }
}

//Create the login window
$wnd = new GtkWindow();
$wnd->set_title('Login');
//Close the main loop when the window is destroyed
$wnd->connect_simple('destroy', array('gtk', 'main_quit'));


//Set up all the widgets we need
$lblCredit   = new GtkLabel('Please provide your data');
//The second parameter says that the underscore should be parsed as underline
$lblUsername = new GtkLabel('_Username', true);
$lblPassword = new GtkLabel('_Password', true);
$txtUsername = new GtkEntry();
$txtPassword = new GtkEntry();
$btnLogin    = new GtkButton('_Login');
$btnCancel   = new GtkButton('_Cancel');


//Which widget should be activated when the 
// mnemonic (Alt+U or Alt+P) is pressed?
$lblUsername->set_mnemonic_widget($txtUsername);
$lblPassword->set_mnemonic_widget($txtPassword);
//Hide the password
//$txtPassword->set_invisible_char('*');

//Destroy the window when the user clicks Cancel
$btnCancel->connect_simple('clicked', array($wnd, 'destroy'));
//Call the login function when the user clicks on Login
$btnLogin->connect_simple('clicked', 'login', $wnd, $txtUsername, $txtPassword);


//Lay out all the widgets in the table
$tbl = new GtkTable(3, 2);
$tbl->attach($lblCredit, 0, 2, 0, 1);
$tbl->attach($lblUsername, 0, 1, 1, 2);
$tbl->attach($txtUsername, 1, 2, 1, 2);
$tbl->attach($lblPassword, 0, 1, 2, 3);
$tbl->attach($txtPassword, 1, 2, 2, 3);


//Add the buttons to a button box
$bbox = new GtkHButtonBox();
$bbox->set_layout(Gtk::BUTTONBOX_EDGE);
$bbox->add($btnCancel);
$bbox->add($btnLogin);


//Add the table and the button box to a vbox
$vbox = new GtkVBox();
$vbox->pack_start($tbl);
$vbox->pack_start($bbox);

//Add the vbox to the window
$wnd->add($vbox);
//Show all widgets
$wnd->show_all();
//Start the main loop
Gtk::main();
?>