C言語DB入門|コンソールアプリからGUIアプリへ

C言語DB入門|コンソールアプリからGUIアプリへ

第4章では、C言語とSQLiteを組み合わせて、書籍の登録・一覧表示・変更・削除ができるコンソール版の書籍管理アプリを完成させました。

ここから始まるPartⅡでは、そのアプリにGTK 4を組み合わせ、入力欄やボタンを使って操作できるGUIアプリへ発展させていきます。

これまで学んだSQLやSQLiteの知識は、GUIアプリでも活躍します。新しく学ぶ中心は、利用者の操作を受け取り、処理を実行して、画面へ結果を表示する仕組みです。

この記事では、コンソールアプリとGUIアプリの違いを確認しながら、GUIの基本となるイベント駆動型プログラミングとコールバック関数の考え方を、書籍管理アプリを例に学びます。

コンソール版の書籍管理アプリを振り返ろう

第4章で作成したbook_manager.cでは、画面に表示されたメニューから番号を入力して、実行する操作を選びました。

たとえば、書籍を登録するときは、次の順番で操作しました。

  1. メニューで1を入力する。
  2. タイトルを入力する。
  3. 著者名を入力する。
  4. 登録結果を確認する。

プログラム側では、main関数がメニュー番号を受け取り、switch文で呼び出す関数を選んでいました。

利用者が入力する番号呼び出す関数実行する処理
1add_book書籍を登録する
2list_books書籍を一覧表示する
3update_book書籍を変更する
4delete_book書籍を削除する
0メニューの繰り返しを終了するデータベースを閉じて終了する

また、入力にはfgetsなどを利用し、結果の表示にはprintfなどを利用しました。

このように、第4章のアプリは、プログラムが入力を求め、利用者が文字や番号を入力して操作を進める仕組みになっています。

GUIアプリでは入力欄やボタンで操作する

GUIは、Graphical User Interfaceの略です。

ウィンドウ、入力欄、ボタン、一覧などの画面部品を使って、アプリを操作する仕組みを指します。

書籍管理アプリをGUIにすると、利用者はタイトルと著者名を入力欄に入力し、登録ボタンを押して書籍を登録できるようになります。

操作第4章のコンソール版これから作るGUI版
登録する操作を選ぶメニュー番号を入力する登録ボタンを押す
タイトルを入力する入力を求めるメッセージに続けて入力するタイトルの入力欄に入力する
著者名を入力する入力を求めるメッセージに続けて入力する著者名の入力欄に入力する
書籍一覧を確認する一覧表示のメニューを選ぶ画面の一覧を確認する
変更・削除する対象を指定する書籍のIDを入力する一覧から書籍を選択する
処理結果を確認するコンソールのメッセージを読む画面上のメッセージや一覧を確認する

GUIでも、タイトルや著者名を入力するときにはキーボードを使います。ボタンも、マウスだけでなくキーボードで操作できる場合があります。

大切なのは、使う入力機器だけの違いではありません。画面上の部品を通じて、操作や結果を分かりやすく示せることがGUIの特徴です。

図1:コンソール版とGUI版の操作の違い

この図から分かること

コンソール版とGUI版では、利用者が操作する画面の形が変わります。

一方で、入力する書籍情報や、書籍を登録するという目的は共通しています。GUI化では、これまでのデータベース処理に、入力欄やボタンを使う操作方法を組み合わせていきます。

GTK 4が画面を作る役割を担当する

本教材では、GUIを作るためにGTK 4を使用します。

GTK 4には、ウィンドウやボタン、文字の入力欄などを作るための機能が用意されています。このような画面部品をウィジェットと呼びます。GTKでは、ウィンドウに部品を配置して画面を組み立てます。GTK公式入門資料

書籍管理アプリでは、主に次のように役割を分けて考えます。

要素主な役割書籍管理アプリでの例
GTK 4画面を作り、操作を受け付ける入力欄、登録ボタン、書籍一覧
自分で書くC言語の処理入力確認や処理の呼び出しを行う空欄の確認、登録処理の呼び出し
SQLiteSQLを実行し、データを保存・取得する書籍の登録、検索、変更、削除

GTK 4を使って登録ボタンを表示しても、それだけで書籍が保存されるわけではありません。

ボタンが押されたときに、入力内容を確認し、SQLiteへ登録する処理を呼び出す必要があります。

そこで登場するのが、イベントとコールバック関数です。

イベント駆動型プログラミングとは

GUIアプリでは、利用者がいつ、どの操作を行うかがあらかじめ決まっているわけではありません。

書籍管理アプリを起動したあと、利用者は次のようにさまざまな操作を行います。

  • タイトルの入力欄を選択する。
  • 著者名を入力する。
  • 一覧から書籍を選択する。
  • 登録ボタンを押す。
  • ウィンドウを閉じる。

このような操作などによって起こる出来事を、イベントと呼びます。

イベント駆動型プログラミングは、起きたイベントに応じて、必要な処理を実行する考え方です。

たとえば、登録ボタンが押されたら登録の処理を実行し、削除ボタンが押されたら削除の処理を実行します。

操作のきっかけアプリが行う処理の例
登録ボタンが押される入力内容を確認して書籍を登録する
一覧の書籍が選択される選択した書籍の情報を入力欄へ表示する
変更ボタンが押される選択した書籍の情報を更新する
削除ボタンが押される選択した書籍を削除する
クリアボタンが押される入力欄や選択状態を初期状態へ戻す

ここで覚えておきたいのは、処理が動く順番は、利用者の操作によって変わるということです。

もちろん、登録処理が始まったあとの「入力を確認する」「SQLを実行する」といった手順は、C言語のプログラムに書いた順序に従います。

イベント駆動という考え方は、主に「いつ、どの処理を始めるか」に関わっています。

コールバック関数は操作に応じて呼び出される関数

コールバック関数は、あるタイミングで呼び出してもらうために、あらかじめ登録しておく関数です。

GTK 4では、たとえば「登録ボタンが押されたときに、この関数を呼び出してほしい」という関係を設定します。

第4章では、main関数のswitch文からadd_bookなどを呼び出していました。

GUI版では、ボタン操作に対応づけたコールバック関数が呼び出され、その中から必要なデータベース処理を呼び出す構成にします。

イベント、シグナル、コールバック関数の関係

GTK 4を学ぶと、イベントに加えてシグナルという言葉も出てきます。

まずは、次のように整理すると分かりやすいでしょう。

用語意味登録ボタンでの例
イベント入力操作などによって起きる出来事マウスなどでボタンを操作する
シグナル部品などが、何か起きたことを知らせる仕組みボタンがclickedシグナルを発行する
コールバック関数通知に対応づけられ、呼び出される関数入力確認と登録処理を進める関数

GtkButtonには、ボタンがクリックされたことを知らせるclickedシグナルがあります。このシグナルに処理を対応づけることで、ボタン操作に反応するアプリを作れます。

シグナルは、マウスやキーボードの操作だけに使われるものではありません。アプリや部品の状態変化を知らせる用途にも使われます。

今は、ボタンからの通知と、自分で作る関数を結び付けるというイメージを持てれば大丈夫です。

図2:ボタン操作からコールバック関数が動く流れ

この図から分かること

GUIアプリは、操作を受け付けると、その操作に対応するコールバック関数を呼び出します。

処理が終わると、引き続き次の操作に対応します。登録、変更、削除などの操作ごとに呼び出す処理を用意することで、利用者の操作に反応するアプリになります。

GUIアプリでもmain関数は必要

「ボタンから関数が呼ばれるなら、main関数は使わなくなるのかな」と感じるかもしれません。

C言語で作るGUIアプリにもmain関数はあります。

ただし、本教材のコンソール版とGUI版では、main関数を中心とした処理の組み立て方が変わります。

比較する点第4章のコンソール版GtkApplicationを使うGUI版
起動時の準備データベースを開き、メニューを表示するアプリの管理に必要な準備をし、起動時の処理を登録する
操作を受け付ける仕組み自分で書いた繰り返しの中で入力を読むGTK側のイベント処理の仕組みを利用する
処理の振り分け入力された番号をswitch文で判定するシグナルに対応づけた関数が呼び出される
終了時の処理繰り返しを抜け、後片付けを行うアプリの実行が終わったあと、必要な後片付けを行う

GtkApplicationを使う基本的な構成では、main関数でアプリを準備し、g_application_runを呼び出します。この関数はメインループを実行し、終了するまでアプリの動作を支えます。

メインループがイベントを処理する

メインループとは、入力などの出来事を受け取り、それに対応する処理を進めるための仕組みです。

初心者のうちは、アプリの中に次のような役割を持つ仕組みがあると考えてみてください。

  • 利用者の操作などを受け取る。
  • 必要な処理を呼び出す。
  • 画面の描画などを進める。
  • 続けて次の出来事に対応する。

GTK 4では、この仕組みを利用するため、ボタンが押されたかどうかを自分で何度も調べる必要はありません。

また、GUI全体の処理の流れは、ソースコードに書かれた関数の並び順だけでは決まりません。どのシグナルにどの関数を対応づけたかが、動作を理解するうえで大切になります。

コールバック関数の中で長く待たない

GUIの操作や描画を担当する処理の途中で長時間待ち続けると、画面が反応しにくくなります。

たとえば、登録ボタンのコールバック関数の中で、fgetsを使ってコンソールからの入力を待つ構成は避けます。

GUI版では、すでに画面の入力欄に入っている文字列を読み取り、必要な処理を進めます。

第4章の入力処理をそのままボタンの中へ移すのではなく、GUIの入力欄から値を受け取る形へ変更することが必要です。

データベース処理の知識はそのまま生かせる

GUI化しても、書籍データの保存先としてSQLiteを使うことは変わりません。

書籍の登録にはINSERT、取得にはSELECT、変更にはUPDATE、削除にはDELETEを使います。

操作使用するSQLGUI版で追加する主な処理
登録INSERT入力欄からタイトルと著者名を取得する
一覧表示SELECT取得した書籍を画面の一覧へ反映する
変更UPDATE選択された書籍のIDと入力欄の値を取得する
削除DELETE選択された書籍のIDを取得する

第4章で学んだ、次のようなSQLiteの処理も引き続き利用できます。

  • sqlite3_openによるデータベース接続
  • sqlite3_prepare_v2によるSQLの準備
  • sqlite3_bind_textやsqlite3_bind_int64による値の設定
  • sqlite3_stepによるSQLの実行や行の取得
  • sqlite3_finalizeによるステートメントの解放
  • sqlite3_closeによる接続の終了

プリペアドステートメントを使ってSQL文と入力値を分ける考え方も、GUI版で大切にしていきます。

既存の関数は入力・表示とDB処理に分けていく

ここで、再利用について少し具体的に確認しておきましょう。

第4章のadd_bookには、主に次の処理が含まれていました。

  1. コンソールからタイトルを入力する。
  2. コンソールから著者名を入力する。
  3. SQLiteへ書籍を登録する。
  4. コンソールに登録結果を表示する。

GUI版では、このうち入力と結果表示の部分を画面に合わせて変更します。

処理の役割コンソール版GUI版
入力を受け取るコンソールから文字列を読む入力欄から文字列を取得する
入力を確認する空文字などを確認する入力欄の値が空かどうかなどを確認する
データを登録するSQLiteでINSERTを実行するSQLiteでINSERTを実行する
結果を伝えるprintfなどで表示するメッセージ表示や一覧更新で伝える

再利用する中心は、SQLやSQLiteを操作する処理です。

既存の関数にはコンソール専用の入力・表示も含まれるため、GUIで呼び出しやすいように役割を整理します。この作業は、第6章の「データベース処理を関数に分ける」で進めていきます。

図3:GUIを組み合わせてもSQLiteの仕組みは共通

イラスト作成用プロンプト

この図から分かること

コンソール版とGUI版は、利用者とのやり取りを行う部分が異なりますが、SQLiteでデータを保存・取得する仕組みは共通です。

入力と表示をデータベース処理から分けておくと、画面の形式が変わっても、SQLや保存処理を生かしやすくなります。

なお、既存の書籍データをGUI版でも利用するには、同じbooks.dbを開く必要があります。章ごとの作業ディレクトリで単にbooks.dbという相対パスを指定すると、それぞれ別のファイルを開く可能性があります。実際に組み合わせる段階で、使用するファイルの場所も確認していきます。

GUIでは保存したあとに画面も更新する

GUI版の書籍管理アプリには、もう1つ意識しておきたい点があります。

それは、データベースの変更と、画面表示の変更は別の処理だということです。

SQLiteに書籍を登録しても、画面に表示中の一覧へ自動的に行が追加されるわけではありません。本教材では、登録などが成功したあとに書籍を読み直し、一覧へ反映する構成にしていきます。

登録ボタンを押した場合の流れは、次のようになります。

  1. タイトルと著者名を入力欄から取得する。
  2. 入力内容を確認する。
  3. INSERTを実行して書籍を保存する。
  4. 保存に成功したことを確認する。
  5. SELECTで書籍一覧を取得し直す。
  6. 画面の一覧とメッセージを更新する。

入力に問題があれば、登録処理へ進む前に画面へ案内を表示します。SQLiteの処理に失敗した場合も、成功したときとは別のメッセージを表示します。

利用者が操作結果を判断できるように、データの状態と画面の表示をそろえることが大切です。

第5章では小さなGUIから始めよう

最終的な書籍管理アプリには、入力欄、複数のボタン、一覧、SQLiteの処理などが必要になります。

まずは、ウィンドウを表示し、ボタン操作に反応する小さなGUIから慣れていきましょう。

第5章では、次の順番で準備を進めます。

学習する内容身につけること
GTK 4の基本を確認するアプリの管理や画面部品の役割を知る
最初のGTK 4プログラムを作成するウィンドウと文字表示を組み立てる
コンパイルして実行するGTK 4を使うプログラムの動かし方を理解する
ボタンとコールバック関数を使う操作に応じて処理を実行する
構造体でデータを管理する複数の画面部品をまとめて扱う

第4章で身につけた、関数を作ること、入力を確認すること、処理結果に応じて動作を変えることは、GUIでも役立ちます。

次の記事「GTK 4の基本を確認する」では、GtkApplicationやGtkApplicationWindow、GtkLabel、GtkEntry、GtkButtonなど、書籍管理アプリにつながる基本要素を見ていきましょう。

Follow me!