WindowsでgccでC言語で簡単にGUI(Tcl/Tk)


はじめに

職場でちょっとツール作りたいけど、使う人のことも考えてGUIにしたい、C言語で組みたい、ライセンスとかも考えてgccで作りたい、ライブラリ色々覚えたくない、そんなときにさっと使える手順です

MinGWのインストール

左の「download/installer」でインストーラが手に入ります。
実行してインストール。

インストール後のInstallation Manager
左のBasic Setupを選び

  • mingw32-base-bin
  • mingw32-gcc-g++-bin

をクリックしてMark

左のAll Packages→MinGW→MinGW Contributedを選び

  • mingw32-tcl-bin
  • mingw32-tk-bin

をクリックしてMark

左上のInstallation
Apply Changes
でインストールを実行

MinGWにPATHを通す

システムのPATHにC:\MinGW\binを登録します。

こちらの記事など参考にどうぞ

Windows10で実行ファイルへのパスを通す手順
https://qiita.com/shuhey/items/7ee0d25f14a997c9e285

ソースを作る

適当なフォルダに以下のように作ります。

C言語のソースが以下です。

main.c
/*
 * These codes are licensed under CC0.
 * http://creativecommons.org/publicdomain/zero/1.0/deed.ja
 */
#include <tcl.h>
#include <tk.h>

//独自コマンドの作成
int proc(ClientData clientData, Tcl_Interp* interp, int argc, const char* argv[])
{
    //argc:引数の数
    //argv[0]:自分自身(コマンド名)
    //argv[1]~:引数

    if ( argc != 1 )
    {
        char *retmsg = "argument error";
        Tcl_SetResult(interp, retmsg, TCL_VOLATILE);
        return TCL_ERROR;
    }
    printf("Call!\n");

    char *retvalue = "0";
    Tcl_SetResult(interp, retvalue, TCL_VOLATILE);
    return TCL_OK;

    //終了コードの種類
    //TCL_OK、TCL_ERROR、 TCL_RETURN、TCL_BREAK、またはTCL_CONTINUE

    //応答の種類
    //TCL_STATIC ... データが静的な領域(static char)にあって、関数を抜けてもその領域が上書きされない場合
    //TCL_VOLATILE ... データが揮発する(auto char)スタック領域にあり、関数を抜けると上書きされる場合
    //TCL_DYNAMIC ... データがAPI Tcl_Allocで確保された領域にある場合
}

int main(int argc, char* argv[])
{
    Tcl_Interp *interp = Tcl_CreateInterp(); //インタプリタを作成
    Tcl_FindExecutable(argv[0]); //初期化前準備
    if ( Tcl_Init(interp) == TCL_ERROR ) //Tclを初期化(スタンダートライブラリinit.tclをロード)
    {
        const char *errmsg = Tcl_GetStringResult(interp); //エラーメッセージの取得
        printf("インタプリタの初期化に失敗: %s\n",errmsg);
        return -1;
    }
    if ( Tk_Init(interp) == TCL_ERROR ) //Tkを初期化(GUIライブラリをロード)
    {
        const char *errmsg = Tcl_GetStringResult(interp); //エラーメッセージの取得
        printf("GUIライブラリの初期化に失敗: %s\n", errmsg);
        return -1;
    }

    //コマンドを作る
    Tcl_CreateCommand(interp,"testproc",proc,NULL,NULL);

    if ( Tcl_EvalFile(interp, "script.tcl") == TCL_ERROR )//インタプリタで実行
    {
        const char *errmsg = Tcl_GetStringResult(interp); //エラーメッセージの取得
        printf("実行失敗: エラー内容:%s\n", errmsg);
        return -1;
    }else{
        const char *errmsg = Tcl_GetStringResult(interp); //エラーメッセージの取得
        printf("実行成功:%s\n", errmsg);
    }

    Tk_MainLoop();//Tkのイベントループへ

    Tcl_DeleteInterp(interp); //インタプリタのお片付け
    return 0;
}

TCL言語のソースが以下です。(GUI定義ファイルのようなものと考えてください)

script.tcl
button .b1 -text "Hello World" -command {puts "Hello World"}
button .b2 -text "Call proc" -command {testproc}
pack .b1 .b2

コンパイルする

ソースのあるフォルダでコマンドプロンプトを開き、以下を実行します。

gcc main.c -o test.exe -ltcl86 -ltk86

実行する

test.exeを実行します。
上のボタンを押すとHello Worldが表示され、
下のボタンを押すとC言語のproc関数が実行されます。

配布時の注意

一見EXEファイルとTCLファイルで動くように思えますが、実際にはMinGWフォルダ内のファイルに依存しています。
配布するには、以下のようなフォルダ構成にして配布してください。

配布フォルダ
├─bin
|  ├─test.exe
|  ├─script.tcl
|  ├─libgcc_s_dw2-1.dll ←C:\MinGW\binにあるファイル
|  ├─tcl86.dll ←C:\MinGW\binにあるファイル
|  └─tk86.dll ←C:\MinGW\binにあるファイル
└─lib
    ├─tcl8.6 ←C:\MinGW\libにあるフォルダ
    └─tk8.6 ←C:\MinGW\libにあるフォルダ

Tcl/tkのライセンスにも目を通しておいてください
https://www.tcl.tk/software/tcltk/license.html

おわりに

Tcl/Tkは、見た目は素朴ですがかなり簡単にGUIが書けるツールキット&言語です。
C言語に組み込む前提で作られているため、このようにかなり簡単に使用できます。

TCL言語自体の使い方については以下などを参照してください。

Tcl/Tk GUI Programming
http://www.nct9.ne.jp/m_hiroi/tcl_tk.html

Tcl/Tkのススメ
https://sites.google.com/site/gpsnmeajp/tcl-tk/tcl-tknosusume

Tcl/tk簡易リファレンス
https://sites.google.com/site/gpsnmeajp/tcl-tk/tcl-tk-jian-yirifarensu

Tcl/TkでWindowsプログラミング
http://web.archive.org/web/20160116031827/http://homepage3.nifty.com/kaku-chan/tcl_tk/index.html