アトリエ・エクレア

2DCG&3DCG, プログラミング, 日記などを掲載してます。

Visual C#

Visual C#

※Visual Studio Community 2017

Windowsフォームアプリケーション


<はじめに>

  • Windowsフォームアプリを作成するには、Windows フォーム アプリケーション (.NET Framework ) を選択する。※上部プルダウンでターゲットフレームワークを選択する。
  • プロジェクトの構成は、ソリューションエクスプローラーに表示される。
  • フォームに配置する各種コントロールは、ツールボックスから選択できる。
  • コントロールの各種プロパティは、プロパティウィンドウで設定できる。
  • デザイナー(フォームデザイナー)にて、視覚的にコントロールを配置できる。


<乱数>

Random random = new Random();
int value = random.Next(0, 5);   // 0 <= value < 5


<リソースの追加>

ピクチャーボックスなどで使用するリソースの追加方法

  • 方法1 :  プロパティウィンドウの、Imageプロパティから
  • 方法2 : [プロジェクト]メニュー → (プロジェクト名の)プロパティ → リソース → 素材を、右ペインにドラッグ&ドロップ

リソースの管理

  • ローカルリソース : プロジェクト内で共用せずに単独  ※フォーム名.resx で管理
  • プロジェクトリソース : プロジェクト内で共用  ※PropertiesフォルダーのResources.resx で管理


<イベント>

<イベント設定>

  • プロパティウィンドウで、イベントボタンをクリックして、各種イベントを設定する。
    このとき、イベント名を選択してEnterキーを押すと、自動的に名前を設定してくれる。
  • デザイナーのコントロールをダブルクリックすると、既定のイベントが作成される。
    既に作成されていた場合、そのイベントハンドラーにジャンプする。
    既定のイベントはコントロールによって異なる。(フォームの場合、Loadイベント。ボタンの場合、Clickイベント など)

<イベントの削除>

  • イベントハンドラーの削除は、直接コードエディターで削除するのではなく、プロパティウィンドウで行うのが安全。


<コントロールの複製>

  • 方法1 :  Ctrlキーを押しながらドラッグ
  • 方法2 :  Ctrl+C , Ctrl+V


<主なプロパティ>

コントロールによって使用するプロパティは異なる。
主なプロパティ

  • (Name) :  オブジェクトを識別する、コードで使われる名前
  • Location :  コンテナーの上部左端に相対する、コントロールの上部左端の座標
  • Size :  コントロールのサイズ(ピクセル単位)
  • Enabled :  コントロールの有効/無効の切り替え
  • Font :  サイズは単位に注意
  • TextAlign :  テキストの位置
  • BackColor :  背景色
  • ForeColor :  前景色(テキストの色)
  • Cursor :  ポインターがコントロールに移動したときに表示されるカーソル

※bool型のプロパティは、プロパティ名のところをダブルクリックするたびに値が変わる



<フォーム>

  • フォームは、ソリューションエクスプローラでファイル名を変更すれば、自動的に (Name) プロパティが変更される。※逆は無理。
  • フォームを閉じるには、FormクラスのClose()メソッドが利用できる。※アプリの終了

プロパティ

  • (Name) :  ソリューションエクスプローラでファイル名を変更するのが良さげ。
  • Text :  フォームのタイトル(キャプション)は、Textプロパティで設定する。
  • Icon :  フォームのアイコン
  • AutoScaleMode :  Dpi にするのが良いかも。
  • StartPosition :  CenterScreenで画面中央にできる。
    任意の位置にするには、Manualにして、さらに、Locationでスクリーン左上からの位置を指定する。
  • FormBorderStyle :  Sizable規定値からFixedSingle等に変更するとサイズ変更不可になる。
  • MinimizeBox :  最小化ボタン Falseで無効(非表示)
  • MaximizeBox :  最大化ボタン Falseで無効(非表示)

イベント

  • Loadイベント :  フォームを読み込むときに発生。フォームをダブルクリックで簡単に設定可能。※アプリ起動時の処理を記述できる。


<メッセージボックス>

staticメソッド

MessageBox.Show("Hello, World!");  // クラスメソッド


<コモン コントロール>

<テキストボックス>

string str = myTextBox.text


<ラベル>

プロパティ

  • Text :  表示するテキストを入力 複数行入力した場合は、Ctrl+ Enterで確定
  • BorderStyle :  境界線を加えるかどうか


<ボタン>

イベントハンドラの設定

  • プロパティウィンドウのイベント(稲妻のアイコン)ボタンをクリック → Click と書かれたところをクリックして、Enterキー
プロパティ
  • Image :  表示されるイメージ。無しの場合は、null
  • Enabled コントロールの有効/無効の切り替え
MyButton.Enabled = false;


<ピクチャーボックス>

プロパティ

  • Image :  表示されるイメージ。無しの場合は、null
  • SizeMode : イメージの配置とコントロールサイズの変更をどのように扱うか制御
    • Normal :  拡大縮小無し、規定値
    • StretchImage :  コントロールのサイズいっぱいに拡大縮小
    • AutoSize :  画像サイズに合わせてコントロールのサイズを変更
    • CenterImage :  中央に拡大縮小無しで配置
    • Zoom :  縦横比を維持して拡大縮小

リソースの管理

  • ローカルリソース : プロジェクト内で共用せずに単独 ※フォーム名.resx で管理
  • プロジェクトリソース : プロジェクト内で共用 ※PropertiesフォルダーのResources.resx で管理
Image myImage = Properties.Resources.myPictureImage;  // リソースの読み込み
myPictureBox.Image = myImage;                         // PictureBoxのImageプロパティの設定


<プログレスバー (ProgressBar)>

プロパティ

  • Maximum :  最大値指定
  • Step :  ステップ量を指定し、PerformStepメソッドで更新(現在位置をステップ量だけ進める)
  • Value :  現在の値


<コンテナー>

パネル (Panel)>

プロパティ

  • BorderStyle :  境界線を加えるかどうか


<メニューとツールバー>

<メニューストリップ(MenuStrip)>

  • メニューバーを作成するために使用。
  • 使用すると、デザイナー下部(コンポーネントトレイ)にも表示される。

メニュー項目や、サブメニュー項目の追加

  • メニューバーをクリックし、"ここへ入力" と表示されたコンボボックスに、項目名を入力する。
    → ツールストリップメニューアイテムが追加される。
    ※コンボボックスからMenuItemを選択することでも可能。

ツールストリップメニューアイテム (ToolStripMenuItem)

  • メニュー項目を作成するために使用。
  • アクセスキー(Altキーと併用)は、&を使って指定。 例) 終了(&Q)
  • ショートカットキーは、ShortcutKeysプロパティで設定できる。


<コンポーネント>

<Timer>

  • Timerコンポーネントを使用すると、フォーム上ではなく、下のコンポーネントトレイに表示される

プロパティ

  • Interval 処理の時間間隔 ミリ秒
  • Enabled イベントハンドラの有効 / 無効 ※Start()メソッド / Stop()メソッドでも可能

イベント

  • Tickイベント 指定された間隔の時間が経過したときに発生。
    ※コンポーネントトレイで、ダブルクリックで簡単に設定可能。

時間を扱う場合、TimeSpan構造体が便利

// TimeSpan構造体
TimeSpan startTime = new TimeSpan(0, 0, 0);    // 時間, 分, 秒


<情報ボックス (AboutBox)>

アプリの情報を表示。

  • 作成 :  [プロジェクト]メニュー → [新しい項目の追加] → [情報ボックス]
  • 編集 :  [プロジェクト]メニュー → [(現在のプロジェクトの)プロパティ] → [アプリケーション] → [アセンブリ情報]ボタン
    ※AssemblyInfo.csと同期

インスタンスを作成して、メニューやボタンなどのクリックイベントハンドラで表示させる。

// メニュークリックのイベントハンドラ
private void MyToolStripMenuItem_Click(object sender, EventArgs e) {
    // 終了時に、Dispose()を呼び出してメモリ解放
    using (AboutBox aboutBox = new AboutBox()) {
        aboutBox.ShowDialog();                     // Form#ShowDialog() :使用後に要メモリ解放
    }
}


<アプリケーションのアイコン>

アイコンファイル(.ico)

  • プロジェクトのプロパティ → [アプリケーション] → [リソース]項目の、[アイコンとマニフェスト] で変更可能。


<リリースビルド>

ビルド構成を、Release に変更し、最適化する。

  1. [ソリューション構成] のドロップダウンで、DebugからReleaseに変更する。
  2. [ビルド]メニュー → ソリューションのビルド
  3. [表示]メニュー → 出力 ※正常終了を確認

以上の操作で、以下のものが作成される。
※プロジェクトのフォルダ → binフォルダ → Releaseフォルダ内

  • プロジェクト名(アセンブリ名).exe   ※アプリケーション実行ファイル
  • プロジェクト名(アセンブリ名).exe.config   ※アプリケーション構成ファイル
  • プロジェクト名(アセンブリ名).pdb   ※プログラムデータベースファイル

アプリの名称は、プロジェクトのプロパティの、アセンブリ名で変更可能(デフォルトはプロジェクト名)



<ClickOnce (クリックワンス)>

  1. プロジェクトのプロパティ → 発行 → 発行場所で発行フォルダーの場所を指定。
    ※デフォルトでは、プロジェクトフォルダー内のpublishフォルダー
  2. インストール モードと設定 → [必須コンポーネント]ボタンをクリック
  3. [必須コンポーネントをインストールするセットアッププログラムを作成する] にチェック
  4. インストールする必須コンポーネントを選択
  5. [必須コンポーネントをコンポーネントの開発元のWebサイトからダウンロードする] にチェック

以上の操作で、以下のものが作成される。

  • Application Filesフォルダー
  • プロジェクト名(アセンブリ名).application   ※アプリケーションのインストールと起動
  • setup.exe





Python

Python

<免責事項>
この記事は、管理人の個人的な覚書きのためのものです。
内容に間違いがあっても責任は負いません。

<環境>

Python 3.6.2
Visual Studio Code Version 1.16.0

Windows10 環境変数確認方法:
Windowsアイコンを右クリック → システム
→ 関連設定:システム情報(右にある) → システムの詳細設定(左にある) → 詳細設定タブ内の環境変数ボタン



<参考>



<Visual Studio Code エンコーディング>

  • ファイル → 基本設定 → 設定 → エンコーディングがutf8か確認(違うなら変更) → ユーザー設定を保存
"files.encoding": "utf8"


<Visual Studio Code 統合ターミナル>

<統合ターミナルの表示>

  • 表示(上部メニュー) → 統合ターミナル

<統合ターミナルでのコマンド実行>

PS C:\Users\ユーザー名\Desktop\SampleFolder> Python sample.py

※この例では、sample.pyファイルが、デスクトップの、SampleFolderフォルダーに入っている。
※実行したコマンドは、キーボードの↑(上矢印)キーで、再度呼び出し可能。



<ソースファイルの拡張子>

  • sample.py のように、「 .py 」を使う。


<基本>

  • インタプリタ言語。コンパイルやリンクが必要ない。
  • ソースコードは、デフォルトでは、UTF-8でエンコードされているものとして扱われる。
  • 大文字と小文字は別のものとして扱われる。
  • 改行が、文の区切り
  • 文字列リテラルは、ダブルクォーテーション( " ) または、シングルクォーテーション( ' ) で囲む。
    途中で改行する場合は、バックスラッシュ(\)を使用する。
    ※バックスラッシュ(\)の記述無しの、複数行にわたる文字列リテラルは、三重クォート(""" または''')で囲む。
  • Pythonにおいて、インデントは、実行文をグループにまとめる方法。※ブロック
  • Javaなどに存在する、インクリメント演算子(++)、デクリメント演算子(--)が無い。
  • 関数内で、グローバル変数への代入をする場合、global文が必要。
    ※global文が無いと、ローカル変数の定義になってしまう。
    ※自由変数がグローバル変数を参照するだけの場合、global文は必要ない。
    ※リスト, 辞書の要素への代入は、変数の定義に非ず、global文なしで可能。※タプルはそもそも代入不可。


<改行>

  • 改行が文の区切り。
  • ,(コンマ)の後に改行した場合は、一文として扱われる。
  • 文の途中で折り返す場合は、\ (バックスラッシュ) を使用する。
  • 文字列リテラルにおける、改行のエスケープシーケンスは、\n


<コメント>

  • 一行コメント(改行まで)は、#(ハッシュ文字)を使用する。
    ※#による一行コメントは、インデント無しでも使用できる。
  • コメントは基本的に、#によるコメント(一行コメント)を使用する。
  • コメントは、文字列リテラルの内部に置くことはできない。
    文字列リテラル中のハッシュ文字は、ただのハッシュ文字となる。
  • 複数行のコメントは、#による一行コメントを複数使うか、或いは、文字列リテラルで代用する。
  • 複数行のコメントを、文字列リテラルで代用する場合、
    """(ダブルクォーテーション3つ)、または '''(シングルクォーテーション3つ)で囲む。

    三重クォートの文字列リテラルは、バックスラッシュ(\)なしで、途中で改行ができる。
    → 改行やホワイトスペースなどが書いた通りに適用されるヒアドキュメントとなる。
    ※通常の文字列リテラルの場合、途中の改行には、一文とみなす為のバックスラッシュ(\)が必要。
    ※文字列リテラルによる代用なので、構文に沿ったインデントが必要。
# 一行コメント(改行まで)

""" 
複数行のコメント ※ヒアドキュメント
(文字列リテラルによる代用なので、構文に沿ったインデントが必要)
"""


<演算子>

※一部

<代入演算子>

  • = : 代入演算子 ※変数に値を代入

<算術演算子>

  • + : 加算、または、文字列の連結
  • - : 減算
  • * : 乗算、または、文字列の反復
  • / : 除算 ※常に浮動小数点数を返す。例)15/3なら5.0を返す
  • // : 一番近い小さい整数に丸める数学除算
    ※floor division 演算子。floor division を行い、(小数部を切り捨てて) 整数を返す。
    ※浮動小数点数について、小数点以下を切り捨てて0 にするには、int()関数が利用できる。
    丸めなし(特に負の値)で完全に切り捨てるところが、floor divisionと異なる。
  • ** : 冪演算(べきえんざん)。冪乗を計算。

<論理演算子>

  • and : 論理積 ※A and B は、AとBが共に真の場合に真となる。
  • or   : 論理和 ※A or B は、AかBのいずれかが真の場合に真となる。
  • not : 論理否定 ※not A は、aが真なら偽、偽なら真となる。


<数値と文字列の連結>

  • 数値と文字列は、単純に、+演算子で連結することができない。※Java等と違うので注意。
  • 最終的に文字列にする場合、数値を文字列に変換してから、文字列と結合する必要がある。
    ※数値を文字列に型変換するには、str()関数が使用できる。
  • 最終的に数値にする場合、文字列を数値に変換してから、数値と結合する必要がある。
    ※文字列を数値に型変換するには、int()関数やfloat()関数などが使用できる。
print("15" + str(32))  # str()を利用 ※結果(文字列):1532
print(int("15") + 32)  # int()を利用 ※結果(数値):47


<変数>

  • 半角アルファベットや数字、アンダースコア( _ )が使用可能。
  • 先頭が数字は不可。
  • 予約語は使用不可。
  • 変数は型を持たないので、型定義はしない。※データ自体が型を持つ。
  • 変数の定義と、初期値の代入を、同時に行う必要がある。
    ※初期値の代入は、組み込み定数 None の代入でも可能。
speed = 15                                     # 変数の定義
print("速さは、" + str(speed) + " m/sです。")  # 結果: 速さは、15 m/sです。


<入力と出力>

  • 画面に文字を出力するには、print()関数(組み込み関数の1つ)が使用できる。
  • print()関数は、キーワード引数 end を使うと、出力の末尾に改行文字を出力しないようにしたり、
    別の文字列を末尾に出力したりできる。
  • キーボードから入力を受け取るには、input()関数(組み込み関数の1つ)が使用できる。
    ※戻り値は、str型なので注意。
# print()で出力
speed = 15
print("速さは、" + str(speed) + " m/sです。")  # 結果: 速さは、15 m/sです。
# print()で出力  ※キーワード引数endを使用
for i in range(10):   # range()は、引数が1つの場合、0 ~ 引数-1 までの値を返す
    # キーワード引数end : 文字列の最後に、自動的に挿入される改行を、任意の文字に変更
    print(i, end = " ") # 結果: 0 1 2 3 4 5 6 7 8 9
# input()で入力  ※戻り値は、str型なので注意。
speed = input("速さを入力してください。")  # 引数で、表示文字列を指定できる。
print("速さは、" + speed + " m/sです。")  # 結果: 速さは、15 m/sです。  ※15を入力した。


<組み込み定数>

組み込み定数の例   ※他にもある

  • True : bool型の真値。
    Trueへの代入は不正で、SyntaxErrorを送出する。
  • False : bool型の偽値。
    Falseへの代入は不正で、SyntaxErrorを送出する。
  • None : 型 NoneType の唯一の値。
    Noneは、関数にデフォルト引数が渡されなかったときなどに、値の非存在を表すのに頻繁に用いられる。
    Noneへの代入は不正で、SyntaxErrorを送出する。


<条件分岐>

<if文>

num = int(input("整数を入力してください。"))

if num < 5:                # 条件式
    print('5未満です。')
elif num == 5:             # "elif" は、"else if" を短くしたもの
    print('5です。')
elif num < 10:
    print('5より大きく、10未満です。')
else:
    print('10以上です。')


<反復処理(ループ)>

<range()関数>

  • 組み込み関数 range() は、算術型の数列を生成する。
  • 指定した終端値は生成されるシーケンスには入らない。
  • range() が返すオブジェクトは、リストであるかのように振る舞うが、リストでは無い。
    これは、イテレートした時に望んだ数列の連続した要素を返すオブジェクトである。
    しかし実際にリストを作るわけではないので、スペースの節約になる。
    このようなオブジェクトは イテラブル (iterable) と呼ばれる。
  • list()関数は、イテラブルからリストを生成する。
print(list(range(7)))   # 結果: [0, 1, 2, 3, 4, 5, 6]

<for文>

<リストの利用>

dogs = ["ポチ", "ハチ", "ゴン太"]  # リストを作成
for dog in dogs:                  # for文で、リストを利用
    print(dog, end = " ")         # 結果: ポチ ハチ ゴン太

<組み込み関数range()の利用>

  • range()は、引数が1つの場合、0(start)≦値<引数(stop) (0 ~ 引数-1)  の整数のイテレータを返す。
    値はループごとに1ずつ増加。
    ※引数が1つの場合、startの値は0となり(デフォルト)、step(増減量)の値は1となる(デフォルト)。
    → 結果的に、引数の値は、生成される値の個数と等しくなる。引数が0以下の場合、中の処理は実行されない
for i in range(10):   # range()は、引数が1つの場合、0 ~ 引数-1 までの値を返す
    # キーワード引数end : 文字列の最後に、自動的に挿入される改行を、任意の文字に変更
    print(i, end = " ") # 結果: 0 1 2 3 4 5 6 7 8 9
  • range()は、引数が2つの場合、第一引数(start)≦値<第二引数(stop)   (第一引数 ~ 第二引数-1) の整数のイテレータを返す。
    値はループごとに1ずつ増加。
    ※第二引数から1を引いた数までなので注意。
for i in range(3, 10):   # range()は、引数が2つの場合、第一引数(ループ開始値) ~ 第二引数-1(ループ終了値) までの値を返す
    print(i, end = " ")    # 結果: 3 4 5 6 7 8 9  ※10は入らないので注意
  • range()は、引数が3つの場合、第三引数は、正だけでなく、負の整数も指定できる。
    • <第三引数が正の場合>
      第三引数(step)の増減量で、第一引数(start)≦値<第二引数(stop) (第一引数 ~ 第二引数-1) の整数のイテレータを返す。
      第二引数-1までとなる。
    • <第三引数が負の場合>
      第三引数(step)
      の増減量で、第一引数(start)≧値>第二引数(stop) (第一引数 ~ 第二引数+1) の整数のイテレータを返す。
      第二引数+1までとなる。
for i in range(3, 10, 2):   # range()は、引数が3つの場合、第三引数(増減量)の増減量で、
                            # 第一引数(ループ開始値) ~ 第二引数-1(ループ終了値) までの値を返す。
    print(i, end = " ")       # 結果: 3 5 7 9

<while文>

  • 条件式が真なら、処理を繰り返す。
num = 0
while num < 10:            # 条件式
    print(num, end = " ")    # 結果: 0 1 2 3 4 5 6 7 8 9
    num += 1

<break文>

  • 最も内側のfor、または、whileループを中断する。
for i in range(3, 10):
    if i > 7:
        break           # 最も内側のfor文を抜ける
    print(i, end = " ")   # 結果: 3 4 5 6 7

<continue文>

  • ループにおける、次のイテレーション(反復)を実行する。
    → 現在のループを中断し、次のループへ移る。
for i in range(3, 10):
    if i == 7:
        continue        # 現在のループを中断し、次のループへ移る
    print(i, end = " ")   # 結果: 3 4 5 6 8 9  ※7は出力されない

<ループの、else節>

  • ループ文は、else節を持つことができる。
  • for文では、反復処理対象のリストを使い切ってループが終了したとき実行される。
    但し、break文でループが終了したときは実行されない。
  • while文では、条件が偽になったときに実行される。
    但し、break文でループが終了したときは実行されない。
for i in range(3, 10):
    if i == 10:
        break
    print(i, end = " ")
else:
    print("\n", end = "")
    print(i)
    print("ループが中断されずに、最後まで実行されました。")

# 結果:
# 3 4 5 6 7 8 9
# 9
# ループが中断されずに、最後まで実行されました。


<イミュータブル と ミュータブル>

イミュータブル(immutable)型 (:不変型)

  • イミュータブルなオブジェクトとは、作成後にその状態を変えることのできないオブジェクトのこと。
  • 固定の値を持ったオブジェクト。
  • イミュータブルなオブジェクトには、数値、文字列、およびタプルなどがある。
    これらのオブジェクトは値を変えられない。
  • 別の値を記憶させる際には、新たなオブジェクトを作成しなければならない。
  • 固定のハッシュ値が必要となる状況で重要な役割を果たす。※辞書のキーなど
  • int, float, str, tuple など

ミュータブル(mutable)型 (:可変型)

  • ミュータブルなオブジェクトとは、作成後も状態を変えることができるオブジェクトのこと。
  • ミュータブルなオブジェクトは、 識別値を変えることなく、値を変更できる。
    ※識別値を調べるには、id()関数が使える。id(object) : オブジェクトの“識別値”を返す。
  • list, dictionary, set など


<文字列型 (string)>

  • 文字列は単引用符(')、または、二重引用符(")で囲み、結果はどちらも同じ文字列になる。
    引用符をエスケープするには、\ を使う。
  • 文字列リテラルは複数行にまたがって書ける。
    1つの方法は三連引用符("""や''')を使うこと(三重クォート文字列)。
    行末は自動的に文字列に含まれるが、行末に \ を付けることで含めないようにすることもできる。
  • 文字列は、+演算子で連結させることができ、*演算子で反復させることができる。
  • 連続して並んでいる複数の文字列リテラルは自動的に連結される。
    リテラルどうしに対してのみ働き、変数や式には働かない。
    変数どうしや変数とリテラルを連結したい場合は、+演算子を使う。
  • 文字列は インデクス表記(添字表記)することができ、最初の文字のインデクスは 0 になる。
    文字列型と区別された文字型は無い。文字というのは単なる長さが 1 の文字列。
  • Python の文字列は変更できない。つまり不変(immutable)。
    従って、文字列のインデクスで指定したある場所に代入を行うとエラーが発生する。
    元の文字列と別の文字列が必要な場合は、新しく文字列を作成する。
  • 組込み関数len()は文字列の長さを返す。
# 文字列は単引用符(')、もしくは二重引用符(")で囲む
word = "Hello"
print(word)      # 結果: Hello

# 文字列は インデクス表記(添字表記)が可能  ※0が最初の文字
print(word[0])      # 結果: H

# インデクスに負の数を指定した場合は右から数える  ※-1が最後の文字
# -0 は 0 と等しいので、負のインデクスは -1 から始まる
print(word[-1])     # 結果: o

# 文字列は変更できない(不変:immutable)
# word[3] = "a"     # インデクスで指定した場所に代入は、エラー

# スライスで、部分文字列を取得することができる
# スライスのインデクスにはデフォルト値がある;
#   最初のインデクスを省略すると、0とみなされる。
#   第2のインデクスを省略すると、文字列のサイズとみなされる。
word = word[0:2]    # 位置 0(included) から 2(excluded)までの文字列
print(word)         # 結果: He

# 文字列は + 演算子で連結、* 演算子で反復できる
word += "l" * 2 + "o, World!"
print(word)         # 結果: Hello, World!

# 組込み関数 len() は文字列の長さを返す
val = len(word)
print(val)          # 結果: 13

<文字列メソッド>

文字列は 共通のシーケンス演算全てに加え、以下のメソッドを実装する。※一部

  • str.find(sub[, start[, end]])
    文字列のスライス s[start:end] に部分文字列subが含まれる場合、その最小のインデックスを返す。
    オプション引数 start および end はスライス表記と同様に解釈される。
    subが見つからなかった場合 -1 を返す。
    ※find()メソッドは、subの位置を知りたいときにのみ使う。
    subが部分文字列であるかどうかのみを調べるには、in演算子を使う:
print("World" in "Hello, World!") # 結果:  True
  • str.index(sub[, start[, end]])
    find()と同様だが、部分文字列が見つからなかったとき、ValueErrorを送出する。
  • str.replace(old, new[, count])
    文字列をコピーし、現れる部分文字列old全てをnewに置換して返す。
    オプション引数countが与えられている場合、先頭からcount個のoldだけを置換する。
  • str.split(sep=None, maxsplit=-1)
    文字列を、sepをデリミタ文字列として区切った単語のリストを返す。
    maxsplitが与えられていれば、最大でmaxsplit回分割される(つまり、リストは最大 maxsplit+1 要素になる)。
    maxsplitが与えられないか-1なら、分割の回数に制限はない(可能なだけ分割される)。
    sepが与えられた場合、連続した区切り文字はまとめられず、空の文字列を区切っていると判断される(例えば '1,,2'.split(',') は ['1', '', '2'] を返す)。
    引数sepは複数の文字にもできる(例えば '1<>2<>3'.split('<>') は ['1', '2', '3'] を返す)。
    区切り文字を指定して空の文字列を分割すると、['']を返す。
    sepが指定されていないかNoneの場合、異なる分割アルゴリズムが適用される。
    連続する空白文字はひとつのデリミタとみなされる。
    また、文字列の先頭や末尾に空白があっても、結果の最初や最後に空文字列は含まれない。
    よって、空文字列や空白だけの文字列をNoneデリミタで分割すると、[]が返される。
val = "Hello, World!\n".split("\n")
print(val)      # 結果: ['Hello, World!', '']
  • str.splitlines([keepends])
    文字列を改行部分で分解し、各行からなるリストを返す。
    keependsに真が与えらない限り、返されるリストに改行は含まれない。
    split()とは違って、デリミタ文字列sepが与えられたとき、このメソッドは空文字列に空リストを返し、終末の改行は結果に行を追加しない。
val = "Hello, World!\n".splitlines()
print(val)      # 結果: ['Hello, World!']
  • str.startswith(prefix[, start[, end]])
    文字列が指定されたprefixで始まるならTrueを、そうでなければFalseを返す。
    prefixは見つけたい複数の接頭語のタプルでも構わない。
    オプションのstartがあれば、その位置から判定を始める。
    オプションのendがあれば、その位置で比較を止める。
  • str.strip([chars])
    文字列の先頭および末尾部分を除去したコピーを返す。
    引数charsは除去される文字集合を指定する文字列。
    charsが省略されるかNoneの場合、空白文字が除去される。
    chars文字列は接頭語でも接尾語でもなく、そこに含まれる文字の組み合わせ全てがはぎ取られる。
    文字列の最も外側の先頭および末尾から、引数 chars 値がはぎ取られる。
    文字列の先頭からcharsの文字集合に含まれない文字に達するまで、文字が削除される。
    文字列の末尾に対しても同様の操作が行われる。
val = "www.example.com".strip("cmowz.")
print(val)      # 結果: "example"
  • str.zfill(width)
    長さが width になるよう ASCII '0' で左詰めした文字列のコピーを返す。
    先頭が符号接頭辞 ('+'/'-') だった場合、'0' は符号の前ではなく、後に挿入される。
    widthが、len(s)以下の場合元の文字列を返す。


<リスト型 (list)>

  • リストは変更可能 (mutable) で、要素はたいてい同じ型のオブジェクトであり、たいていイテレートによってアクセスする
  • リストはミュータブルなシーケンスで、一般的に同種の項目の集まりを格納するために使われる。
  • 異なる型の要素を含むこともあるが、通常は全ての要素は同じ型を持つ。
  • 他の言語で言う配列(array)と似たようなもの。
    ※Javaにおける配列とListを一緒にしたような感じ・・・。
  • 角括弧の対を使い、空のリストを表す: []
  • 角括弧を使い、項目をカンマで区切る: [a]、[a, b, c]
  • リスト内包表記を使う: [x for x in iterable]
  • 型コンストラクタを使う: list() または list(iterable)
  • リストを作る方法は、他にも組み込み関数 sorted() などいろいろある。
numbers = [1, 4, 9, 16, 25]         # リスト(オブジェクト)を作成
for i in range(len(numbers)):       # len()は、リストの長さ(要素数)を返す
    print(numbers[i], end = " ")    # 結果: 1 4 9 16 25
numbers = [1, 4, 9, 16, 25]     # リストを作成
for i in numbers:               # カウンタ変数iには、リストの要素が入る
    print(i, end = " ")         # 結果: 1 4 9 16 25

<リストオブジェクトのメソッド>

  • list.append(x) : リストの末尾に要素を一つ追加する。a[len(a):] = [x] と等価。
  • list.extend(iterable) : iterableの全ての要素を対象のリストに追加し、リストを拡張する。a[len(a):] = iterable と等価。
  • list.insert(i, x) : 指定した位置に要素を挿入する。
    第一引数は、リストのindexで、そのindexを持つ要素の直前に挿入される。
    a.insert(0, x) はリストの先頭に挿入を行う。
    a.insert(len(a), x) は a.append(x) と等価。
  • list.remove(x) : リスト中で、値xを持つ最初の要素を削除する。該当する項目がなければエラーとなる。
  • list.pop([i]) : リスト中の指定された位置にある要素をリストから削除して、その要素を返す。
    indexが指定されなければ、 a.pop() はリストの末尾の要素を削除して返す。
    この場合も要素は削除される。
  • list.clear() : リスト中の全ての要素を削除する。del a[:] と等価。
  • list.index(x[, start[, end]]) : リスト中で、値xを持つ最初の要素の位置をゼロから始まる添字で返す。
    該当する要素がなければ、ValueError を送出する。
    任意の引数である startとendはスライス記法として解釈され、リストの探索範囲を指定できる。
    返される添字は、start引数からの相対位置ではなく、リスト全体の先頭からの位置になる。
  • list.count(x) : リストでの、xの出現回数を返す。
  • list.sort(key=None, reverse=False) : リストの項目を、インプレース演算 (in place、元のデータを演算結果で置き換えるやりかた) でソートする。
    引数はソート方法のカスタマイズに使える。
  • list.reverse() : リストの要素を、インプレース演算で逆順にする。
  • list.copy() : リストの浅い(shallow)コピーを返す。a[:] と等価。

<多次元リスト>

# 多次元リスト ※例) 二次元リスト
list2D = [[ 1, 2, 3, 4, 5],
          [ 6, 7, 8, 9,10],
          [11,12,13,14,15]]

x = 3
y = 2

# 変数の複数同時の代入:
# タプルのパック(右辺が1つのタプルになる)と、
# シーケンスのアンパック(左辺にアンパックされる)を組み合わせたもの
# x, y = 3, 2         # 右辺:リストやタプルなど、全てのシーケンス型を使うことができる

val = list2D[y][x]  # 要素の値を取り出す。※添え字の指定順に気を付ける。
print(val)          # 結果: 14


<タプル型 (tuple)>

  • タプルは不変型 (immutable) で、複数の型の要素からなることもあり、
    要素はアンパック操作やインデックス (あるいは namedtuples の場合は属性)でアクセスすることが多い。
  • タプルはイミュータブルなシーケンスで、一般的に異種のデータの集まりを格納するために使われる。
  • タプルはまた、同種のデータのイミュータブルなシーケンスが必要な場合
    (set インスタンスや dict インスタンスに保存できるようにするためなど) にも使われる。
  • タプルを作るのはカンマであり、丸括弧ではない。
    丸括弧は省略可能だが、空のタプルの場合や構文上の曖昧さを避けるのに必要な時は例外。
  • 丸括弧の対を使い、空のタプルを表す: ()
  • カンマを使い、単要素のタプルを表す: a, または (a,)
  • 項目をカンマで区切る: a, b, c または (a, b, c)
  • 組み込みの tuple() を使う: tuple() または tuple(iterable)
numbers = (1, 4, 9, 16, 25)         # タプル(オブジェクト)を作成
for i in range(len(numbers)):       # len()は、タプルの長さ(要素数)を返す
    # numbers[i] = 30               # リストと異なり、タプルでは、要素の値の変更は不可
    print(numbers[i], end = " ")    # 結果: 1 4 9 16 25
numbers = (1, 4, 9, 16, 25)     # タプルを作成
for i in numbers:               # カウンタ変数iには、タプルの要素が入る
    print(i, end = " ")         # 結果: 1 4 9 16 25


<辞書型 (dictionary)>

  • 任意のキーを、値に対応付ける連想配列。
  • ある範囲の数でインデクス化されているシーケンスと異なり、辞書は キー (key) でインデクス化されている。
    ※キーは何らかの変更不能な型。
  • 文字列、数値は常にキーにすることができる。
  • タプルは、文字列、数値、その他のタプルのみを含む場合はキーにすることができる。
    直接、あるいは間接的に変更可能なオブジェクトを含むタプルはキーにできない。
  • 辞書は、順序付けのされていない キー(key): 値(value) のペアの集合であり、キーが (辞書の中で)一意でければならない
  • 辞書での主な操作は、ある値を何らかのキーを付けて記憶することと、キーを指定して値を取り出すこと。
  • 波括弧 (brace) のペア: {} は空の辞書を生成。
  • カンマで区切られた key: value のペアを波括弧ペアの間に入れると、辞書の初期値となる key: value が追加される。
  • del で key: value のペアを削除できる。
  • すでに使われているキーを使って値を記憶すると、以前そのキーに関連づけられていた値は失われる。
  • 存在しないキーを使って値を取り出そうとするとエラーになる。
  • 辞書オブジェクトに list(d.keys()) を実行すると、辞書で使われている全てのキーからなるリストを適当な順番で返す。
    ソートされたリストが欲しい場合は、代わりに sorted(d.keys()) を使う。
  • ある単一のキーが辞書にあるかどうか調べるには、 in キーワードを使う。
petName = {"dog": "ポチ", "cat": "タマ"}    # 辞書(オブジェクト)の作成

# キーを指定して、値を取り出す
val = petName["dog"]
print(val)                  # 結果: ポチ
val = petName["cat"]
print(val)                  # 結果: タマ

# キーを指定して、値を書き換え
petName["dog"] = "ハチ"
val = petName["dog"]
print(val)                  # 結果: ハチ
  • ループで利用する場合
petName = {'dog': 'ポチ', 'cat': 'タマ'}    # 辞書オブジェクトの作成

# ループ
for k, v in petName.items():    # items()メソッドで、キーと値を、同時に取り出せる
    print(k, v)

# 結果:
# dog ポチ
# cat タマ


<ユーザー定義関数>

  • def キーワードで、関数を定義する。
  • def の後に、関数名と仮引数を丸括弧で囲んだリストを続ける。
    ※仮引数が無い場合は、丸括弧のみを記述。
  • 関数の実体を構成する実行文は、次の行から始め、インデントが必要。
  • 関数の定義は、呼び出し処理の前(※実行順の意)に行う必要がある。
  • 戻り値がある場合は、return文を使用
  • 関数の中で変数を定義すると、ローカル変数となる。
    ※ローカル変数のスコープは、その定義された関数内(定義した場所から)。
  • グローバル変数と同じ名前のローカル変数を定義可能。別の変数として扱われる。
  • 関数内で、グローバル変数への代入をする場合、global文が必要。
    ※global文が無いと、ローカル変数の定義になってしまう。
    ※自由変数がグローバル変数を参照するだけの場合、global文は必要ない。
    ※リスト, 辞書の要素への代入は、変数の定義に非ず、global文なしで可能。※タプルはそもそも代入不可。

<ローカル変数, グローバル変数, 自由変数>

  • ローカル変数 (local variable) :  ある名前(識別子)が、ブロック内で束縛されているなら、
    nonlocal や global として宣言されていない限り、それはそのブロックのローカル変数
  • グローバル変数 (global variable) :  ある名前(識別子)が、モジュールレベルで束縛されているなら、その名前はグローバル変数
  • 自由変数 (free variable) :  ある変数が、あるコードブロック内で使われていて、そのブロックで定義はされていないなら、それは自由変数

<ユーザー定義関数> 戻り値なし

# 関数の定義
def myfunc(name):
    print("Hello, " + name + "!")

# 関数の呼び出し
myfunc("World")   # 結果: Hello, World!

<ユーザー定義関数> 戻り値あり

# 関数の定義
def myfunc():
    name = "World"
    return name     # 戻り値がある場合は、return文を使用
    
# 関数の呼び出し
print("Hello, " + myfunc() + "!")   # 結果: Hello, World!

<global文>

  • global文は、現在のコードブロック全体で維持される宣言文。
  • 列挙した識別子をグローバル変数として解釈するよう指定する。※複数の場合、コンマで区切って列挙する。
  • globalを使わずにグローバル変数に代入を行うことは不可能だが(ローカル変数の定義になってしまうため)、
    自由変数を使えば、その変数をグローバルであると宣言せずにグローバル変数を参照することができる。
  • リスト, 辞書の要素への代入は、変数の定義に非ず、global文なしで可能。※タプルはそもそも代入不可。
# グローバル変数
x = 20
y = 30

# 関数の定義
def myAdd(Z):   # 仮引数zはローカル変数
    global x    # 変数xをグローバル変数として解釈するよう宣言
    x = 75      # グローバル変数xへの代入 ※global文を使用しないと、ローカル変数の定義になってしまう
    return x + Z
    
# 関数の呼び出し
print(myAdd(y))     # 結果: 105

# グローバル変数xを出力
print(x)            # 結果: 75
# グローバル変数
x = 20
y = 30

# 関数の定義
def myAdd(Z):   # 仮引数zはローカル変数
    x = 75      # ローカル変数xの定義 ※グローバル変数xとは、別の変数となる
    return x + Z
    
# 関数の呼び出し
print(myAdd(y))     # 結果: 105

# グローバル変数xを出力
print(x)            # 結果: 20
# グローバル変数
x = 20
y = 30

# 関数の定義
def myAdd(Z):       # 仮引数zはローカル変数
    return x + Z    # x: 自由変数が、グローバル変数を参照するだけなら、global文は必須ではない
    
# 関数の呼び出し
print(myAdd(y))     # 結果: 50

# グローバル変数xを出力
print(x)            # 結果: 20


<関数における、引数のデフォルト値>

  • 関数の定義時に、引数(仮引数)に、デフォルト値を設定できる。※デフォルト引数
  • 仮引数にデフォルト値が指定されている場合、関数呼び出しでの実引数の指定が省略できる。
  • デフォルト引数(default argument)は、非デフォルト引数(non-default argument)の後に指定しなければならない。
def calcTriangleArea(base, height = 10):    # 引数heightにデフォルト値を指定(デフォルト引数)
    area = base * height / 2
    return area

# 引数ひとつだけで関数呼び出し ※仮引数baseに代入される
print(calcTriangleArea(20))         # 結果: 100.0

# 引数ふたつで関数呼び出し ※指定した実引数が、仮引数のデフォルト値よりも優先される
print(calcTriangleArea(20, 50))     # 結果: 500.0


<関数呼び出しにおける、キーワード引数>

  • 関数呼び出し時にキーワード引数を用いると、関数の仮引数から指定したキーワードを探し、値を割り当てることができる。
  • 名前付き引数を使用する。
  • 引数の指定は、順不同で良くなる。
  • 必要な引数にのみ値を渡す。
def calcTriangleArea(base, height):
    area = base * height / 2
    return area

# 通常(キーワード引数なし)の関数呼び出し ※基本的に左から順番に、実引数が仮引数に代入されていく
print(calcTriangleArea(10, 20))                     # 結果: 100.0

# キーワード引数を利用した関数呼び出し   ※実引数の指定が、順不同となる
print(calcTriangleArea(height = 40, base = 70))     # 結果: 1400.0

# キーワード引数を利用した関数呼び出し   ※位置引数(positional argument、固定引数)と、キーワード引数(keyword argument)の混在
print(calcTriangleArea(30, height = 50))            # 結果: 750.0

# ※※※これはエラーとなる※※※
# キーワード引数を利用した関数呼び出し   ※位置引数は、キーワード引数の前に指定する必要がある
#print(calcTriangleArea(height = 80, 60))           # 結果: SyntaxError: positional argument follows keyword argument


<ラムダ式 (lambda)>

  • 無名のインライン関数で、関数が呼び出されたときに評価される1つの式(expression)を含む。
  • ラムダ関数を作る構文は lambda [arguments]: expression である。
    ※expressionには、関数の指定も可能。
  • キーワード lambda を使うと、名前のない小さな関数を生成できる。
  • ラムダ式の関数は、関数オブジェクトが要求されている場所にならどこでも使うことができる。
  • ラムダ式は、構文上単一の式に制限されている。
  • 意味付け的には、ラムダ形式は単に通常の関数定義に構文的な糖衣をかぶせたものに過ぎない。
  • 入れ子構造になった関数定義と同様、ラムダ式もそれを取り囲むスコープから変数を参照することができる。
  • (ラムダ式自体は、関数名みたいな感じで使用できる、と覚えておくと良いかもしれない。)
# ラムダ式の部分(lambda x, y: x + y)が関数(関数名)で、(7, 9)の部分が引数の指定と関数呼び出しの形式。
result = (lambda x, y: x + y)(7, 9) # ラムダ式の引数xに7、ラムダ式の引数yに9が代入される
print(result)              # 結果: 16

# 以下のやり方でも、出力結果は同じ
f = lambda x, y: x + y     # ラムダ式を変数に代入 ※標準の関数でも、変数への代入は可能
result = f(7, 9)           # 関数呼び出し ※ラムダ式が呼び出される。
print(result)              # 結果: 16
def add(a, b):
    return a + b

# (lambda x, y: add(x, y))の部分が関数(ラムダ式)で、(7, 9)の部分が引数の指定と関数呼び出しに相当。
result = (lambda x, y: add(x, y))(7, 9) # ラムダ式に、関数を設定 ※ラムダ式の引数xに7、ラムダ式の引数yに9が代入される
print(result)              # 結果: 16

# 以下のやり方でも、出力結果は同じ
f = lambda x, y: add(x, y) # ラムダ式を変数に代入 ※標準の関数でも、変数への代入は可能
result = f(7, 9)           # 関数呼び出し ※ラムダ式が呼び出され、その中でさらにadd()関数が呼び出される。
print(result)              # 結果: 16


<クラス>

  • クラス(class)は、ユーザー定義オブジェクトを作成するためのテンプレート。
    クラス定義は普通、そのクラスのインスタンス上の操作をするメソッドの定義を含む。
  • クラスが __init__() メソッドを定義している場合、クラスのインスタンスを生成すると、
    新しく生成されたクラスインスタンスに対して自動的に __init__() を呼び出す。※コンストラクタ
  • 属性の名前には二種類(データ属性およびメソッド)ある。
    • データ属性 (data attribute): Smalltalkの“インスタンス変数”や C++の“データメンバ” に相当。
    • メソッド (method): クラス本体の中で定義された関数。
      そのクラスのインスタンスの属性として呼び出された場合、
      メソッドはインスタンスオブジェクトを第一引数 (argument) として受け取る (この第一引数は通常 self と呼ばれる)。
      (Pythonでは、メソッドという用語はクラスインスタンスだけのものではなく、
      オブジェクト型にもメソッドを持つことができる。※リストオブジェクトなど。)
  • メソッドの最初の引数を self と呼ぶが、この名前付けは単なる慣習でしかない。
    self という名前は、Pythonでは何ら特殊な意味を持たないが、
    この慣行に従わないと、コードは他の Pythonプログラマにとってやや読みにくいものとなる。
  • クラス変数は、全てのインスタンスで共有される。
  • インスタンス変数は、それぞれのインスタンス毎にユニーク。
# クラス定義
class MyPet:
    kind = "猫"                       # クラス変数(class variable)は、全てのインスタンスで共有される

    # 初期化   ※クラスのインスタンスを生成すると、新しく生成されたクラスインスタンスに対して自動的に __init__() を呼び出す
    def __init__(self, name):         # インスタンスオブジェクトを第一引数として受け取る
        self.name = name              # インスタンス変数(instance variable)は、それぞれのインスタンス毎にユニーク

    # メソッド
    def favourite_food(self):
        food = ""                     # foodは、このメソッドのローカル変数であり、別のメソッドから利用できない
        if self.name == "タマ":       # インスタンス変数を利用
            food = "生クリーム"
        elif self.name == "トム":
            food = "アイスクリーム"
        mystr = self.name + "の好物は、" + food  # mystrは、このメソッドのローカル変数であり、別のメソッドから利用できない
        return mystr

# クラスのインスタンス化(instantiation) ※関数のような表記法を使う。
# クラスの新しいインスタンス(instance)を生成し、そのオブジェクトを変数へ代入
pet1 = MyPet("タマ")
pet2 = MyPet("トム")

# 属性参照 =======================================================
# クラス変数は、全てのインスタンスで共有される
print(pet1.kind)                # 結果: 猫
print(pet2.kind)                # 結果: 猫

# インスタンス変数は、それぞれのインスタンス毎にユニーク
print(pet1.name)                # 結果: タマ
print(pet2.name)                # 結果: トム

# メソッド呼び出し
print(pet1.favourite_food())    # 結果: タマの好物は、生クリーム
print(pet2.favourite_food())    # 結果: トムの好物は、アイスクリーム


<派生クラス>

  • 基底クラス(base class)を派生(拡張)して、派生クラス(derived class)をつくることができる。
    このとき、既存のクラスの属性を新規に作成したクラスに引き継がせることができる。これを継承とよぶ。
  • 派生クラスは基底クラスのメソッドを上書き(override)することができる。
  • 派生クラス名.メソッド名()の呼び出しでは、基底クラスの同名のメソッド(コンストラクタを含む)は呼び出されない。
    クラスの中でオーバーライドされた継承メソッドにアクセスするには、親クラス(基底クラス)を参照可能なsuper()関数が利用できる。
    ※または次の方法もある。
  • 基底クラスのメソッドを直接呼び出す方法: BaseClassName.methodname(self, arguments)
# 基底クラス (base class) の定義
class Base:
    def __init__(self):
        self.x = 20         # インスタンス変数(データ属性)
        print("Base")
    def baseMethod(self):
        return "基底クラス"

# 派生クラス (derived class) の定義
class Sub(Base):
    def __init__(self):
        super().__init__()   # クラス内で、基底クラスの(派生クラスと名前が重複する)メソッドを呼び出すには、super()を利用
        #Base.__init__(self) # これでも可能
        print("Sub")
        print(self.x)        # super()を使って基底クラスを初期化しておかないと、エラー
    def subMethod1(self):
        return "派生クラス"
    def subMethod2(self):
        baseStr_UseSuper = super().baseMethod() # 基底クラスのメソッド呼び出し ※super()を利用する場合
        baseStr_NonuseSuper = self.baseMethod() # 同クラス内(基底クラスから継承)のメソッド呼び出し ※super()を利用しない場合
        subStr = self.subMethod1()      # 同クラス内(派生クラス)のメソッド呼び出し
        print(baseStr_UseSuper + ", " + baseStr_NonuseSuper + ", " + subStr)
        
# ===============================================================================================
sub = Sub() # 結果:
            # Base
            # Sub
            # 20
val = sub.baseMethod()
print(val)              # 結果: 基底クラス
val = sub.subMethod1()
print(val)              # 結果: 派生クラス

sub.subMethod2()        # 結果: 基底クラス, 基底クラス, 派生クラス


<モジュールのインポート>

  • インポート方法は複数ある。
import tkinter         # tkinterモジュールをインポート
import tkinter as tk   # tkinterモジュールをインポート ※tkとして扱える
  • 以下は、アンダースコア (_) で始まるものを除いてすべての名前をインポートする。
  • 未知の名前がインタープリターに読み込まれ、定義済みの名前を上書きしてしまう可能性があるのであまりよくない。
from tkinter import *  # tkinterモジュールから全ての名前をインポート


<乱数>

  • 擬似乱数を生成するには、randomモジュールをインポートする。
import random

# 整数用の関数 =================================================================
# random.randrange(stop)  ※0 <= 整数値 < stop
rdm1 = random.randrange(10)
print(rdm1)     # 0  整数値 < 10  ※0から9(含む)までのいずれかの整数

# random.randrange(start, stop[, step])  ※start <= (stepによる)整数値 < stop  逆転もあるので注意
rdm2 = random.randrange(2, 10, 2)
print(rdm2)     # 2 ≦ 整数値(ステップ2) < 10   ※2,4,6,8のいずれかの整数

# random.randint(a, b)  ※a <= 整数値 <= b  ※randrange(a, b+1) のエイリアス
rdm3 = random.randint(2, 10)    # a > b だとエラー
print(rdm3)     # 2 ≦ 整数値 ≦ 10  ※2から10(含む)までのいずれかの整数

# 実数分布 ====================================================================
# random.random() ※ランダムな浮動小数点数)を返す。範囲: 0.0(含む) ~ 1.0(含まない)
rdm4 = random.random()
print(rdm4)     # 0.0 <= 実数値 < 1.0  ※0.0から1.0(含まない)までのいずれかの実数

# random.uniform(a, b) ※a <= b なら a <= 実数値 <= b , b < a なら b <= 実数値 <= a
# 端点の値 b が範囲に含まれるかどうかは、等式 a + (b-a) * random() における浮動小数点の丸めに依存
rdm5 = uniform(1.5, 5.0)
print(rdm5)     # 1.5 <= 実数値 <= 5.0  ※1.5から5.0(含む)までのいずれかの実数


<ファイルの入出力>

  • file object(ファイルオブジェクト)は開かれたファイルを表す。※別名は、I/O オブジェクト
  • ファイルオブジェクト: 下位のリソースへのファイル志向 API (read() や write() メソッドを持つもの) を公開しているオブジェクト。
  • ファイルオブジェクトは、作成された手段によって、実際のディスク上のファイルや、
    その他のタイプのストレージや通信デバイス(例えば、標準入出力、インメモリバッファ、ソケット、パイプ、等)へのアクセスを媒介できる。
  • ファイルオブジェクトは file-like objects や streams とも呼ばれる。
  • ファイルオブジェクトは、3種類ある。: 生のバイナリーファイル、バッファされたバイナリーファイル、そしてテキストファイル。
  • インターフェイスは io モジュールで定義されている。
  • ファイルオブジェクトを作る標準的な方法は、open()関数を使うこと。
  • open()関数は、ファイルを開き、対応するファイルオブジェクトを返す。ファイルを開くことができなければ、OSErrorが送出される。
    ※ファイルオブジェクトのclose()メソッドで、ファイルを閉じる。
  • ファイルオブジェクトのreadline()メソッドは、ファイルから1行だけを読み取る。
    改行文字(\n)は、読み出された文字列の終端に残る。
    改行が省略されるのは、ファイルが改行で終わっていない場合の最終行のみ。ファイルの終端(EOF)に達したら、空文字列('')を返す。
    ※テキストファイルに直接 \ と文字で記述されたものは、 \\ (バックスラッシュのエスケープシーケンス)として読み込まれる(表示上はそのまま \ )。
    例えば、直接 \n と文字で記述されたものは、\\n として読み込まれる(表示上はそのまま \n )。
    このため、実際に改行をさせたい場合は、\\n を \n に変換する処理が必要。
    ※文字列メソッド str.replace(old, new [,count])が利用できる。
# ファイル読み込み ========================================================================================
# open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True, opener=None)
# file を開き、対応するファイルオブジェクトを返す。ファイルを開くことができなければ、OSErrorが送出される。
#
# file: 開くファイルのパス名を与えるものか、または、ラップするファイルの整数のファイルディスクリプタ
# mode: オプションの文字列で、ファイルが開かれるモードを指定する。デフォルトは 'r' で、読み込み用にテキストモードで開く。
#       他に、書き込み用の 'w'、排他的な生成用の 'x'、追記用の 'a' などがある。
# buffering: オプションの整数で、バッファリングの方針を設定する。バッファリングを無効にする(バイナリモードでのみ有効)には0、
#            行単位バッファリング(テキストモードでのみ有効)には1、固定値のチャンクバッファの大きさをバイト単位で指定するには1以上の整数
# encoding: ファイルのエンコードやデコードに使われる text encoding の名前。テキストモードでのみ使用。
#           エンコーディングが指定されなければ、デフォルトはプラットフォーム依存

f = open("samplefolder/sample.txt", "r", encoding = "utf-8") # ファイルオブジェクトを返す
while True:
    line = f.readline() # 1行ずつ読み込む
    print(line, end='')
    if not line:        # ファイルの終端(EOF)に達したら、空文字列('')を返す
        f.close()       # ファイルを閉じる
        break
  • ファイルから複数行を読み取るには、ファイルオブジェクトに対してループを書く方法がある。
f = open("samplefolder/sample.txt", "r", encoding = "utf-8") # ファイルオブジェクトを返す

for line in f:          # 1行ずつ読み込むのを繰り返す。ファイル終端の、空の文字列で終了
    print(line, end='')

f.close()               # ファイルを閉じる


<GUIプログラム>

  • Tkinterモジュールをimportすることで、GUIプログラミングが可能。※import時、先頭は小文字のt
  • Tkinterは、Python からGUIを構築・操作するための標準ライブラリ(ウィジェット・ツールキット)。
    Tcl/Tk(ティクル・ティーケー:スクリプト言語"Tcl"と、そのGUIツールキット"Tk"からなる、GUIスクリプティング環境)のTk部分を、
    Pythonで利用できるようにしたもので、簡単にGUI画面をもったアプリケーションを作ることが可能。
  • Tkクラスのmainloop()メソッドで、ディスプレイ表示や、表示の更新が行われる。
  • 各ウィジェットを変更した場合(表示/非表示や有効/無効など)に、mainloop()メソッドの到達前に、強制的に表示更新させるには、
    Tkクラスや各ウィジェットのupdate()メソッド(※Miscクラスから継承)が利用できる。
  • ウィンドウ上のウィジェットを削除するには、各ウィジェットのdestroy()メソッドが利用できる。
  • Canvas上のオブジェクトを削除するには、Canvasクラスのdelete()メソッドが利用できる。
  • ウィジェットの表示・非表示は、配置・非配置で可能。  ※いずれでも可能。
    • place()で表示(配置)、place_forget()で非表示(非配置)。
    • pack()で表示(配置)、pack_forget()で非表示(非配置)。

<ウィンドウ>

  • ウィンドウ作成には、tkinterが利用できる。
# 最低限の、GUIウィンドウ作成

import tkinter          # tkinter をインポート
#from tkinter import *  #このインポートのほうが効率がいいが、構造理解のため、敢えて使わない

# Tkクラスを(引数なしで)インスタンス化することで、Tkのトップレベルウィジェット(アプリケーションのメインウィンドウ)を生成
tk = tkinter.Tk()       # 生成したオブジェクトを、変数に代入
tk.mainloop()           # Tkのメインループをコール
import tkinter

tk = tkinter.Tk()

tk.title("タイトル")    # ウィンドウタイトル
tk.minsize(640, 480)    # 最小ウィンドウサイズ

tk.mainloop()

<フレーム・ウィジェット>

  • フレームは、複数のウィジェットを纏めることができる。
  • 削除するには、オブジェクトの、destroy()メソッドを使用。
  • Canvasとは独立している。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("キーボード操作")
tk.minsize(640, 480)

# フレーム
frame = tkinter.Frame(tk, width = 640, height = 480, bg = "green")
frame.place(x = 0, y = 0)

# ラベル  ※作成したフレームの子にする
lbl = tkinter.Label(frame, text = "フレーム内ラベル", bg = "white", font = ("MS Pゴシック", 22)) # frameをparentに指定
lbl.place(x = 100, y = 50)

# ボタン  ※作成したフレームの子にする
btn = tkinter.Button(frame, text = "フレーム内ボタン", width = 20, bg = "white")    # frameをparentに指定
btn.place(x = 100, y = 100)

# フレームの非表示 ※フレーム内のWidgetを纏めて操作できる
frame.place_forget()

# メインループ
tk.mainloop()

<ラベル・ウィジェット>

  • 削除するには、オブジェクトの、destroy()メソッドを使用。
  • Canvasとは独立している。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル ※bgを指定しない場合、背景は薄いグレー(デフォルト)
# フォントは、リストかタプルで指定
lbl = tkinter.Label(tk, text = "表示するテキストをここに書く", bg = "white", font = ("MS Pゴシック", 22))
lbl.place(x = 100, y = 40)

# メインループ
tk.mainloop()
  • ラベルのテキストを変更する。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル
lbl = tkinter.Label(tk, text = "表示するテキストをここに書く", fg = "blue", bg = "white", font = ("MS Pゴシック", 22))
lbl.place(x = 100, y = 40)

# ラベルのテキスト変更 ※いずれの方法でも可能
lbl["text"] = "変更するテキストをここに書く"      # オブジェクト生成後、オプション名を辞書インデックスのように扱う
#lbl.config(text = "変更するテキストをここに書く") # または、オブジェクト生成後に、config()メソッドを使って属性を更新

# メインループ
tk.mainloop()
  • ラベルを無効にするには、stateオプションに、"disabled"を指定する。
    ※完全に見えなくなるわけではなく、テキストがグレー表示になる。
    ※有効にする場合は、"normal"
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル
lbl = tkinter.Label(tk, text = "表示するテキストをここに書く", fg = "blue", bg = "white", font = ("MS Pゴシック", 22))
lbl.place(x = 100, y = 40)

# ラベルのテキスト変更 ※いずれの方法でも可能
lbl["text"] = "変更するテキストをここに書く"      # オブジェクト生成後、オプション名を辞書インデックスのように扱う
#lbl.config(text = "変更するテキストをここに書く") # または、オブジェクト生成後に、config()メソッドを使って属性を更新

# ラベルを無効にする
lbl["state"] = "disabled"
#lbl.config(state = "disabled")   # これでも可能

# メインループ
tk.mainloop()
  • ラベルを削除する。
    ※ラベルなどのGUIオブジェクトを削除するには、そのオブジェクトの、destroy()メソッドを使用。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル
lbl = tkinter.Label(tk, text = "表示するテキストをここに書く", fg = "blue", bg = "white", font = ("MS Pゴシック", 22))
lbl.place(x = 100, y = 40)

# ラベルのテキスト変更 ※いずれの方法でも可能
lbl["text"] = "変更するテキストをここに書く"      # オブジェクト生成後、オプション名を辞書インデックスのように扱う
#lbl.config(text = "変更するテキストをここに書く") # または、オブジェクト生成後に、config()メソッドを使って属性を更新

# ラベルを削除する
lbl.destroy()

# メインループ
tk.mainloop()
  • 複数行のラベル
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル
lbl = tkinter.Label(tk, width = 22, height = 5, bg = "white",
        anchor = tkinter.NW, wraplength = 85, justify = "left", text = "abcdefghijklmnopqrstuvwxyz")
lbl.place(x = 10, y = 20)

# メインループ
tk.mainloop()

<オプション>

  • オプションを利用することで、共通項目を設定できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# オプション =========================================================================
# 全てのラベルのフォントを設定  ※フォントは、リストかタプルで指定
tk.option_add("*Label.Font", ("MS Pゴシック", 10))  # 全てのウィジェットのフォントを設定する場合は、*font
# 全てのラベルの背景色を設定
tk.option_add("*Label.Background", "white")         # 全てのウィジェットの背景を設定する場合は、*Background

# ラベル
lbl1 = tkinter.Label(tk, text = "ラベル1")
lbl1.place(x = 100, y = 50)

lbl2 = tkinter.Label(tk, text = "ラベル2")
lbl2.place(x = 100, y = 100)

lbl3 = tkinter.Label(tk, text = "ラベル3")
lbl3.place(x = 100, y = 150)

# メインループ
tk.mainloop()

<ボタン・ウィジェット>

  • 削除するには、オブジェクトの、destroy()メソッドを使用。
  • Canvasとは独立している。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ボタン
btn = tkinter.Button(tk, text = "ボタンのテキスト", width = 20, bg = "white")
btn.place(x = 100, y = 50)

# メインループ
tk.mainloop()
  • ボタンにイベントを設定する。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ユーザー定義関数
def btn_click():
    print("ボタンがクリックされました。")

# ボタン
btn = tkinter.Button(tk, text = "ボタンのテキスト", width = 20, bg = "white")
#btn = tkinter.Button(command = btn_click, text = "ボタンのテキスト", width = 20, bg = "white") # イベント設定1
btn.place(x = 100, y = 50)

# イベント設定 ※イベント設定1,2,3いずれの方法でも可能
btn["command"] = btn_click       # イベント設定2
#btn.config(command = btn_click) # イベント設定3

# メインループ
tk.mainloop()
  • ボタンを無効にするには、stateオプションに、"disabled"を指定する。
    ※有効にする場合は、"normal"
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ユーザー定義関数
def btn_click():
    print("ボタンがクリックされました。")

# ボタン
btn = tkinter.Button(tk, text = "ボタンのテキスト", width = 20, bg = "white")
#btn = tkinter.Button(command = btn_click, text = "ボタンのテキスト", width = 20, bg = "white") # イベント設定1
btn.place(x = 100, y = 50)

# イベント設定 ※イベント設定1,2,3いずれの方法でも可能
btn["command"] = btn_click       # イベント設定2
#btn.config(command = btn_click) # イベント設定3

# ボタンを無効にする
btn["state"] = "disabled"
#btn.config(state = "disabled")   # これでも可能

# メインループ
tk.mainloop()

<エントリー・ウィジェット>

  • 削除するには、オブジェクトの、destroy()メソッドを使用。
  • Canvasとは独立している。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# エントリー
entry = tkinter.Entry(tk, width = 50, bd = 5, bg = "white")
entry.place(x = 100, y = 50)

# メインループ
tk.mainloop()
  • エントリーに入力されたテキストを取得する。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# エントリー
entry = tkinter.Entry(tk, width = 50, bd = 5, bg = "white")
entry.place(x = 100, y = 50)

# ユーザー定義関数
def btn_click():
    entryText = entry.get()  # エントリーに入力されたテキストを取得
    print(entryText)

# ボタン
btn = tkinter.Button(tk, command = btn_click, text = "ボタンのテキスト", width = 20, bg = "white")
btn.place(x = 100, y = 100)

# メインループ
tk.mainloop()
  • エントリーを無効にするには、stateオプションに、"disabled"を指定する。
    ※有効にする場合は、"normal"
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# エントリー
entry = tkinter.Entry(tk, width = 50, bd = 5, bg = "white")
entry.place(x = 100, y = 50)

# エントリーを無効にする
entry["state"] = "disabled"
#entry.config(state = "disabled")   # これでも可能

# ユーザー定義関数
def btn_click():
    entryText = entry.get()  # エントリーに入力されたテキストを取得
    print(entryText)

# ボタン
btn = tkinter.Button(tk, command = btn_click, text = "ボタンのテキスト", width = 20, bg = "white")
btn.place(x = 100, y = 100)

# メインループ
tk.mainloop()

<キャンバス・ウィジェット (Canvas widget)>

  • ウィンドウにグラフィックスを描画するには、土台となるCanvasが必要。
  • グラフィックスを作成する場合、Canvasクラスのcreate_が先頭にあるメソッドで作成。※この時、識別番号(object ID)が返る。
  • キャンバス上のオブジェクトを削除する場合、Canvasクラスのdelete()メソッドで削除
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
    ※キャンバス上の"全て"のオブジェクトを削除する場合、delete("all") とする。
  • グラフィックスの属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, bg = "white", width = 640, height = 480)   # bgなど、キーワード引数は任意
canvas.place(x = 0, y = 0)   # canvas.pack()でも配置できる(※ウィンドウサイズが変わると、位置が動く)。

# メインループ
tk.mainloop()

<画像>

  • 画像は、Canvasに描画。
  • Canvasクラスのcreate_image()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
  • Canvasクラスの、create_image()メソッドの引数imageについて:
    • 画像の更新は、基本的に、Tkクラスのmainloop()メソッドやupdate()メソッドで行われる。
      それまでイメージオブジェクトへの参照を保持する必要がある。
    • 引数imageには、戻り値を直接代入するような、(すぐ消滅する)関数の指定はできない。
      → 変数(グローバル変数)を用意しておき、一度参照を代入してから、imageに代入するのが無難。
      ※文法的には可能だが、すぐに参照が消滅するため、mainloop()やupdate()による更新で画像が消える。
    • クラス内でcreate_image()メソッドを使用する場合、
      イメージオブジェクトへの参照を、メソッド内のローカル変数に代入したものを指定すると画像が消える。
      → インスタンス変数(例 self.imgなど)、または、グローバル変数を指定する。
      ※文法的には可能で、メソッド内でupdate()で更新すれば画像は表示できる。
      しかし、メソッドを抜けた時点で参照が消失し、mainloop()やupdate()による更新で画像が消えるため、
      インスタンス変数(例 self.imgなど)、または、グローバル変数を指定しておくのが無難。
    • 関数内でcreate_image()メソッドを使用する場合、イメージオブジェクトへの参照を、ローカル変数に代入したものを指定すると画像が消える。
      → グローバル変数を指定する。※global文を忘れずに。
      ※文法的には可能で、関数内でupdate()で更新すれば画像は表示できる。
      しかし、関数を抜けた時点で参照が消失し、mainloop()やupdate()による更新で画像が消えるため、
      グローバル変数を指定しておくのが無難。
    以上を踏まえると、
    イメージオブジェクトへの参照は、グローバル変数(または、クラスのインスタンス変数)に保持させるのが無難
    ※関数内ではglobal文を忘れずに。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, bg = "white", width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 画像
img = tkinter.PhotoImage(file = "img/myImage.png")  # この例では、.pyファイルと同じ階層のimgフォルダ内の、myImage.png画像を読み込む
canvas.create_image(0, 0, anchor = tkinter.NW, image = img, tag = "myImageTag") # anchor指定無しの場合、中心が基準 ※NW:NorthWest

# メインループ
tk.mainloop()
  • 画像の削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, bg = "white", width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 画像
img = tkinter.PhotoImage(file = "img/myImage.png")
image_ID = canvas.create_image(0, 0, anchor = tkinter.NW, image = img, tag = "image_Tag")

# 画像を削除
canvas.delete("image_Tag")    # 同じタグのものが全て削除される
#canvas.delete(image_ID)      # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • 画像の属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, bg = "white", width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 画像
img1 = tkinter.PhotoImage(file = "img/myImage1.png")
img2 = tkinter.PhotoImage(file = "img/myImage2.png")
image_ID = canvas.create_image(0, 0, anchor = tkinter.NW, image = img1, tag = "image_Tag")

# 画像の属性を変更
canvas.itemconfig(image_ID, image = img2)
#canvas.itemconfigure(image_ID, image = img2)   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<矩形>

  • 矩形は、Canvasに描画。
  • Canvasクラスのcreate_rectangle()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("矩形を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
# 左上x座標, 左上y座標, 右下x座標, 右下y座標, オプション
canvas.create_rectangle(50, 50, 590, 430, fill = "blue") # fillで塗りつぶし ※色は16進数でも指定可能(例: #0000ff)

# メインループ
tk.mainloop()
  • 矩形の削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("矩形を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
# 左上x座標, 左上y座標, 右下x座標, 右下y座標, オプション
# 色は16進数でも指定可能(例: #0000ff)
rect_ID = canvas.create_rectangle(50, 50, 590, 430, outline = "red", fill = "blue", tag = "rect_Tag")

# 矩形を削除
canvas.delete("rect_Tag")    # 同じタグのものが全て削除される
#canvas.delete(rect_ID)      # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • 矩形の属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("矩形を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
# 左上x座標, 左上y座標, 右下x座標, 右下y座標, オプション
# 色は16進数でも指定可能(例: #0000ff)
rect_ID = canvas.create_rectangle(50, 50, 590, 430, outline = "red", fill = "blue", tag = "rect_Tag")

# 矩形の属性を変更
canvas.itemconfig(rect_ID, fill = "yellow")
#canvas.itemconfigure(rect_ID, fill = "yellow")   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<テキスト (文字)>

  • テキスト(文字)は、Canvasに書く(描画する)。
  • Canvasクラスのcreate_text()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("テキストを書く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# テキストを書く  ※デフォルトでは、テキスト領域の中心が基準
# フォントは、リストかタプルで指定
canvas.create_text(100, 50, text = "Hello, World!", font = ("メイリオ", 15), fill = "blue", tag = "text_Tag")

# メインループ
tk.mainloop()
  • テキストの削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("テキストを書く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# テキストを書く  ※デフォルトでは、テキスト領域の中心が基準
# フォントは、リストかタプルで指定
text_ID = canvas.create_text(100, 50, text = "Hello, World!", font = ("メイリオ", 15), fill = "blue", tag = "text_Tag")

# テキストを削除
canvas.delete("text_Tag")    # 同じタグのものが全て削除される
#canvas.delete(text_ID)      # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • テキストの属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("テキストを書く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# テキストを書く  ※デフォルトでは、テキスト領域の中心が基準
# フォントは、リストかタプルで指定
text_ID = canvas.create_text(100, 50, text = "Hello, World!", font = ("メイリオ", 15), fill = "blue", tag = "text_Tag")

# テキストの属性を変更
canvas.itemconfig(text_ID, fill = "yellow")
#canvas.itemconfigure(text_ID, fill = "yellow")   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<線>

  • 線は、Canvasに描画。※波線も描画できる。
  • Canvasクラスのcreate_line()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("線を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 線を描く
# 座標(10, 20)と座標(250, 50)を結ぶ、線を描く
canvas.create_line(10, 20, 250, 50, width = 3, fill = "blue", tag = "line_Tag")

# メインループ
tk.mainloop()
  • 線の削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("線を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 線を描く
# 座標(10, 20)と座標(250, 50)を結ぶ、線を描く
line_ID = canvas.create_line(10, 20, 250, 50, width = 3, fill = "blue", tag = "line_Tag")

# 線を削除
canvas.delete("line_Tag")    # 同じタグのものが全て削除される
#canvas.delete(line_ID)      # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • 線の属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("線を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 線を描く
# 座標(10, 20)と座標(250, 50)を結ぶ、線を描く
line_ID = canvas.create_line(10, 20, 250, 50, width = 3, fill = "blue", tag = "line_Tag")

# 線の属性を変更
canvas.itemconfig(line_ID, fill = "red")
#canvas.itemconfigure(line_ID, fill = "red")   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<弧(円弧)>

  • 弧(円弧)は、Canvasに描画。
  • Canvasクラスのcreate_arc()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("弧を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 弧を描く
# バウンディングボックスの左上座標(10, 20)と右下座標(250, 200)、反時計回り120度の弧
canvas.create_arc(10, 20, 250, 200, extent = 120, style = tkinter.ARC, tag = "arc_Tag")

# メインループ
tk.mainloop()
  • 弧の削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("弧を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 弧を描く
# バウンディングボックスの左上座標(10, 20)と右下座標(250, 200)、反時計回り120度の弧
arc_ID = canvas.create_arc(10, 20, 250, 200, extent = 120, style = tkinter.ARC, tag = "arc_Tag")

# 孤を削除
canvas.delete("arc_Tag")    # 同じタグのものが全て削除される
#canvas.delete(arc_ID)      # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • 弧の属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("弧を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 弧を描く
# バウンディングボックスの左上座標(10, 20)と右下座標(250, 200)、反時計回り120度の弧
arc_ID = canvas.create_arc(10, 20, 250, 200, extent = 120, style = tkinter.ARC, tag = "arc_Tag")

# 弧の属性を変更
canvas.itemconfig(arc_ID, extent = 240)
#canvas.itemconfigure(arc_ID, extent = 240)   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<楕円>

  • 楕円は、Canvasに描画。
  • Canvasクラスのcreate_oval()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("楕円を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 楕円を描く
# バウンディングボックスの左上座標(10, 20)と右下座標(250, 200)の、楕円
canvas.create_oval(10, 20, 250, 200, fill = "blue", tag = "oval_Tag")

# メインループ
tk.mainloop()
  • 楕円の削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("楕円を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 楕円を描く
# バウンディングボックスの左上座標(10, 20)と右下座標(250, 200)の、楕円
oval_ID = canvas.create_oval(10, 20, 250, 200, fill = "blue", tag = "oval_Tag")

# 楕円を削除
canvas.delete("oval_Tag")    # 同じタグのものが全て削除される
#canvas.delete(oval_ID)         # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • 楕円の属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("楕円を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 楕円を描く
# バウンディングボックスの左上座標(10, 20)と右下座標(250, 200)の、楕円
oval_ID = canvas.create_oval(10, 20, 250, 200, fill = "blue", tag = "oval_Tag")

# 楕円の属性を変更
canvas.itemconfig(oval_ID, fill = "red")
#canvas.itemconfigure(oval_ID, fill = "red")   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<多角形>

  • 多角形は、Canvasに描画。
  • Canvasクラスのcreate_polygon()メソッドで作成。※この時、識別番号(object ID)が返る。
  • Canvasクラスのdelete()メソッドで削除。
    ※引数には、識別番号(object ID)、またはタグを指定する。object ID指定の場合、個別に削除できる。
    タグ指定の場合、同じタグを指定したもの全てを削除できる。
  • 属性を変更する場合、Canvasクラスのitemconfig()メソッド(またはitemconfigure()メソッド)で変更できる。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("多角形を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 多角形を描く
# 座標(10, 20)と座標(250, 50)と座標(100, 200)を結ぶ、多角形を描く
canvas.create_polygon(10, 20, 250, 50, 100, 200, fill = "blue", tag = "polygon_Tag")

# メインループ
tk.mainloop()
  • 多角形の削除。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("多角形を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 多角形を描く
# 座標(10, 20)と座標(250, 50)と座標(100, 200)を結ぶ、多角形を描く
polygon_ID = canvas.create_polygon(10, 20, 250, 50, 100, 200, fill = "blue", tag = "polygon_Tag")

# 多角形を削除
canvas.delete("polygon_Tag")    # 同じタグのものが全て削除される
#canvas.delete(polygon_ID)      # 個別に削除するには、識別番号(object ID)を指定する

# メインループ
tk.mainloop()
  • 多角形の属性の変更。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("多角形を描く")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 多角形を描く
# 座標(10, 20)と座標(250, 50)と座標(100, 200)を結ぶ、多角形を描く
polygon_ID = canvas.create_polygon(10, 20, 250, 50, 100, 200, fill = "blue", tag = "polygon_Tag")

# 多角形の属性を変更
canvas.itemconfig(polygon_ID, fill = "red")
#canvas.itemconfigure(polygon_ID, fill = "red")   # itemconfigure()でも可能

# メインループ
tk.mainloop()

<アニメーション>

  • 各ウィジェットの表示内容を変更した場合に、メインループ到達前に、強制的に表示更新させるには、
    Tkクラスや各ウィジェットのupdate()メソッド(※Miscクラスから継承)が利用できる。
  • 時間を停止させるには、timeモジュールのsleep()関数が利用できる。
    ※timeモジュールをインポートする必要がある。
  • Widget(ウィジェット)を移動させるには、Canvasクラスのmove()メソッドか、coords()メソッドが利用できる。
    • move()メソッドは相対座標を指定する。
    • coords()メソッドは絶対座標を指定する。
import tkinter
import time     # sleep関数利用のためインポート

# ウィンドウ
tk = tkinter.Tk()
tk.title("アニメーション")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
rect_ID = canvas.create_rectangle(50, 50, 200, 200, outline = "red", fill = "blue", tag = "rect_Tag")

# 画面を描画
tk.update()     # 強制的に画面を描画

# 時間を停止
time.sleep(5)   # 引数に、停止する時間(秒)を指定

# アニメーション処理
for i in range(0, 10):
    canvas.move(rect_ID, 20, 10)    # x座標:+20, y座標:+10 動く
    tk.update()                     # 画面を描画
    time.sleep(0.5)                 # 時間を停止

# メインループ
tk.mainloop()

<イベント設定 (バインドとイベント)>

  • ウィジェットコマンドからのbind()メソッドによって、
    あるイベントを待つことと、そのイベント型が起きたときにコールバック関数を呼び出すことができる。
    ※解除はunbind()メソッド
  • bind()メソッドの形式 :
    def bind(self, sequence, func, add='')
    sequence:
    対象とするイベントの型を示す文字列。
    func:
    一引数を取り、イベントが起きるときに呼び出されるPython関数。
    イベント・インスタンスが引数として渡される。
    (このように実施される関数は、一般に callbacks として知られている。)
    add:
    オプションで、'' か '+' のどちらか。
    空文字列を渡すことは、このイベントが関係する他のどんなバインドをもこのバインドが置き換えることを意味する。
    '+' を使う仕方は、この関数がこのイベント型にバインドされる関数のリストに追加されることを意味する。
  • キーボードによるイベントを受け取るには、ウィジェットにフォーカスが必要。
    ※フォーカスを合わせるには、キーボードのTabキー、またはスクリプトから合わせる方法がある。
    ※各ウィジェットのforcus_set()メソッド(Miscクラスから継承)でフォーカスを指定できる。
  • ボタンウィジェットのクリックイベントについては、引数commandにユーザー定義関数を指定することで、イベント設定が可能。

ボタンウィジェットのクリックイベント

import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# 引数無しのユーザー定義関数
def btn_click():
    print("ボタンがクリックされました。")

# ボタン
btn = tkinter.Button(tk, text = "ボタンのテキスト", width = 20, bg = "white")
#btn = tkinter.Button(command = btn_click, text = "ボタンのテキスト", width = 20, bg = "white") # イベント設定1
btn.place(x = 100, y = 50)

# イベント設定 ※イベント設定1,2,3いずれの方法でも可能
btn["command"] = btn_click       # イベント設定2
#btn.config(command = btn_click) # イベント設定3

# メインループ
tk.mainloop()

ボタンウィジェットのクリックイベントで、引数を使う場合1
"expressionに、引数ありのユーザー定義関数を指定した、引数無しのラムダ式" が利用できる。

import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# 引数ありのユーザー定義関数
def btn_click(btn_name):
    print(btn_name + "が押されました")
    
# イベント設定
# ユーザー定義関数に引数を渡したいときは、
# "expressionに、引数ありのユーザー定義関数を指定した、引数無しのラムダ式" が利用できる。
# (ラムダ式を使うのであれば、ラムダ式自体には引数を記述可能(キーワード引数を記述可能)だが、
# そのラムダ式の引数に対して、値を渡せないので意味がない)
btn_name = "起動ボタン"
btn = tkinter.Button(tk, text = btn_name, command = lambda : btn_click(btn_name))
btn.place(x = 10, y = 20)

# メインループ
tk.mainloop()

ボタンウィジェットのクリックイベントで、引数を使う場合2
引数ありのユーザー定義関数内で、イベント用の関数を定義し、それを戻り値にして、引数commandに指定することで可能。

import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# 引数ありのユーザー定義関数
def myCallback(btn_name):
    def btn_click():            # ユーザー定義関数内で、イベント用の関数を定義 ※引数は指定しない
        print(btn_name + "が押されました")
    return btn_click            # イベント用の関数名を返す
    
# イベント設定
# ユーザー定義関数に引数を渡したいときは、
# 引数ありのユーザー定義関数内で、イベント用の関数を定義し、それを戻り値にして、引数commandに指定することで可能
btn_name = "起動ボタン"
btn = tkinter.Button(tk, text = btn_name, command = myCallback(btn_name)) # 引数commandには、戻り値の関数名を指定
btn.place(x = 10, y = 20)

# メインループ
tk.mainloop()

イベント設定※ボタンウィジェットのクリックイベント以外の、イベント設定

import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル
lbl = tkinter.Label(tk, width = 50, height = 10, bg = "white",
        anchor = "nw", wraplength = 85, justify = "left", text = "abcdefghijklmnopqrstuvwxyz")
lbl.place(x = 10, y = 20)

# イベントハンドラ
def press_label(event):     # Event object を引数にとる、コールバック関数
    print(event.keysym + "が押された")

# フォーカスの設定
lbl.focus_set()     # キーボード操作のイベントを受け取るには、フォーカスが必要

# イベント設定
lbl.bind("<KeyPress-space>", press_label)
# イベント解除: lbl.unbind("<KeyPress-space>")

# メインループ
tk.mainloop()

イベント設定で、引数を使う場合 ※ボタンウィジェットのクリックイベント以外の、イベント設定
"expressionに、引数ありのユーザー定義関数を指定した、引数あり(Event object用)のラムダ式" が利用できる。

import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("タイトル")
tk.minsize(640, 480)

# ラベル
lbl = tkinter.Label(tk, width = 50, height = 10, bg = "white",
        anchor = "nw", wraplength = 85, justify = "left", text = "abcdefghijklmnopqrstuvwxyz")
lbl.place(x = 10, y = 20)

# 引数ありのユーザー定義関数
def press_label(event, lbl_name):     # Event object を引数にとる、コールバック関数
    print(lbl_name + "で、" + event.keysym + "が押された")

# フォーカスの設定
lbl.focus_set()     # キーボード操作のイベントを受け取るには、フォーカスが必要

# イベント設定
# ユーザー定義関数に引数を渡したいときは、
# "expressionに、引数ありのユーザー定義関数を指定した、引数あり(Event object用)のラムダ式" が利用できる
lbl_name = "ラベル"
lbl.bind("<KeyPress-space>", lambda event: press_label(event, lbl_name))

# メインループ
tk.mainloop()

イベントタイプ ※一部

  • Button: マウスボタンのひとつが押された。
    例) <Button-1> など  ※1:左マウスボタン、2:中マウスボタン、3:右マウスボタン に対応。
  • ButtonRelease: マウスボタンが離された。
    例) <ButtonRelease-1> など  ※1:左マウスボタン、2:中マウスボタン、3:右マウスボタン に対応。
  • Double-Button: マウスボタンのひとつがダブルクリックされた。
    例) <Double-Button-1> など  ※1:左マウスボタン、2:中マウスボタン、3:右マウスボタン に対応。
  • Motion: ウィジェット内で、押した状態で、マウスポインターが動いた。
    例) <B1-Motion> など  ※B1:左マウスボタン、B2:中マウスボタン、B3:右マウスボタン に対応。
  • Enter: ウィジェットの可視領域に、マウスポインターが入った。
    例) <Enter>
  • Leave: ウィジェットの外に、マウスポインターが外れた。
    例) <Leave>
  • KeyPress: キーボードのキーが押された。※押されている間ずっと
    例) <KeyPress-Return> など  ※Returnキー(Enterキー)
  • KeyRelease: キーボードのキーが離された。
    例) <KeyRelease-space> など  ※spaceキー(Sは小文字なので注意)
  • Shift: Shiftキーと併用のキーが押された。※押されている間ずっと
    例) <Shift-Tab> など  ※Shiftキーを押しながらTabキー
  • Key: キーボードのいずれかのキーが押された。※押されている間ずっと
    例) <Key>

イベントモディファイア ※一部

  • Alt, Any, Control, Double, Lock, Shift, Triple などがある。
    例) <any-keypress> , <double-button-1>
  • '<1>' は '<button-1>' と同じ。
  • 'x' は '<keypress-x>' と同じ。

<キーボード操作>

  • キーボード操作をするには、ウィジェットとイベント処理を関連付ける必要がある。※イベントバインディング
  • イベントバインディングを行うには、各ウィジェットのbind()メソッド、またはbind_all()メソッドを使う。※Universal widget methods
  • ボタンウィジェットのクリックイベントは、command属性に、イベント関数を指定することで可能。
    それ以外のボタン、及び、ボタン以外のウィジェットのイベントは、各ウィジェットのbind()メソッドによるイベントバインディングを行う。
    ※解除はunbind()メソッド
  • キーボードによるイベントを受け取るには、ウィジェットにフォーカスが必要。
    ※フォーカスを合わせるには、キーボードのTabキー、またはスクリプトから合わせる方法がある。
    ※各ウィジェットのforcus_set()メソッド(Miscクラスから継承)でフォーカスを指定できる。
  • 関連づけられた関数の引数にはイベントのオブジェクトが渡される。オブジェクトのkeysym(:key symbol)変数には押されたキーの文字列が入る。
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("キーボード操作")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
rect_ID = canvas.create_rectangle(50, 50, 200, 200, outline = "red", fill = "blue", tag = "rect_Tag")

# 矩形を移動する
def moveRect(event):
    canvas.move(rect_ID, 20, 10)    # x座標:+20, y座標:+10 動く
    tk.update()                     # 画面を描画

# フォーカスを合わせる ※Tabキーを押さなくてもフォーカスを合わせておく
canvas.focus_set()

# イベントバインディング
canvas.bind("<KeyPress-Return>", moveRect)

# メインループ
tk.mainloop()
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("キーボード操作")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
rect_ID = canvas.create_rectangle(50, 50, 200, 200, outline = "red", fill = "blue", tag = "rect_Tag")

# 矩形を移動する
def moveRect(event):
    canvas.move(rect_ID, 20, 10)    # x座標:+20, y座標:+10 動く
    tk.update()                     # 画面を描画

# イベントバインディング
canvas.bind_all("<KeyPress-Return>", moveRect)

# メインループ
tk.mainloop()
import tkinter

# ウィンドウ
tk = tkinter.Tk()
tk.title("キーボード操作")
tk.minsize(640, 480)

# キャンバス
canvas = tkinter.Canvas(tk, width = 640, height = 480)
canvas.place(x = 0, y = 0)

# 矩形を描く
rect_ID = canvas.create_rectangle(50, 50, 200, 200, outline = "red", fill = "blue", tag = "rect_Tag")

# 矩形を移動する
def moveRect(event):
    if event.keysym == "Up":
        canvas.move(rect_ID, 0, -10)    # x座標:0, y座標:-10 動く
    elif event.keysym == "Down":
        canvas.move(rect_ID, 0, 10)     # x座標:0, y座標:+10 動く
    elif event.keysym == "Left":
        canvas.move(rect_ID, -10, 0)    # x座標:-10, y座標:0 動く
    elif event.keysym == "Right":
        canvas.move(rect_ID, 10, 0)     # x座標:+10, y座標:0 動く
    #tk.update()                         # 画面を描画

# イベントバインディング
canvas.bind_all("<KeyPress-Up>", moveRect)
canvas.bind_all("<KeyPress-Down>", moveRect)
canvas.bind_all("<KeyPress-Left>", moveRect)
canvas.bind_all("<KeyPress-Right>", moveRect)

# メインループ
tk.mainloop()




12歳からはじめる ゼロからの Pythonゲームプログラミング教室

12歳からはじめる ゼロからの Pythonゲームプログラミング教室

2017/5/11発売予定 大槻有一郎 (著), リブロワークスPython部 (著), 雪印 (イラスト)

( ゚Д゚)すごい表紙だ・・・。
お値段が手ごろで素晴らしい。


SmileBASIC プチコン3号

SmileBASIC プチコン3号

自分用の覚書

※間違いがあるかも。

<参考サイト>


<画面構成>

プチコン画面構成.png

<上画面(3Dスクリーン)>
画面奥から、

  1. 背景色:全ての画面の後ろに表示される単色面
  2. グラフィック画面:グラフィック命令で描いた図形が表示される画面
  3. BG画面:ゲームのマップなどを作るための画面。
  4. 1コマ16×16ドットのキャラを、最大128×127個並べて表示できる。
  5. 4層のレイヤーがあり、多重スクロールなどの表現が可能。
  6. SPRITE:ゲームのキャラなどに使用する要素。上画面・下画面合わせて、512個までのSPRITEを使用可能。サイズは16×16ドットを基本(異なるサイズあり)とし、個別に任意のサイズで使用可能。アニメーションを作る命令あり。
  7. コンソール画面:PRINT命令などで文字を書くことができるテキスト画面
グラフィック画面は、コンソール画面の裏側に重なっている存在。
横400ドット×縦240ドットの解像度
X座標: 0~399
Y座標: 0~239
左上が原点(0, 0)  ※右下が(399, 239)

グラフィック解像度: 400×240ドット
座標原点: 左上(0, 0)
X座標:右に向かって+
Y座標:下に向かって+
Z座標:奥に向かって+

<下画面(タッチスクリーン)>
画面構成は上画面と同様だが、画面サイズが異なる。
グラフィック解像度: 320×240ドット
座標原点: 左上(0, 0)

<グラフィックページ>

画面に表示する元画像を置く場所が、全部で6つある(GRP0~GRP5)。
各ページの解像度は 512×512 ドット。※GPR4、GPR5では、16×16ドットのキャラが、横に32個並んでいる。

<画面とグラフィックページの対応>
上画面(DISPLAY 0)
  • グラフィック画面GRP0
  • BG画面GRP5
  • SPRITEGRP4
下画面(DISPLAY 1)
  • グラフィック画面GRP1
  • BG画面GRP5
  • SPRITEGRP4

初期状態では、描画ページと表示ページは同じGRP0(下画面ではGRP1)だが、GPAGE命令で変更可能。

GPAGE :  グラフィック表示ページと操作ページの指定。※GPAGE 4,4 で、GRP4を表示できる。
GCOPY : 他のグラフィックページから画像をコピー。

<上下結合表示>

上下結合表示: XSCREEN 4 で、上下をつないで1枚のように扱うことができる。※上画面の両外側は使えない。


<画面の表示・非表示>

VISIBLE : 画面表示要素のON/OFF切り替え。

VISIBLE 1,1,1,1  'コンソール,グラフィック,BG,SPRITE


<サンプル>

トップメニュー → 「サンプルを見る」ボタンを押 す → ファイル一覧から選んで実行。
DIRECTモード → LOAD "SYS/ファイル名" → 実行する。※STARTボタンで停止できるものと、できないものがある。

<基本サンプル>
BASICの基本的な命令を利用した学習用のサンプルプログラム。

  • EX1TEXT :  コンソールへの文字表示
  • EX2CALC :  文字入力を使った簡易計算機
  • EX3KEYDRUM :  キーボードを使った簡易鍵盤とドラム
  • EX4NUMGAME :  数当てゲーム
  • EX5BIORHYTHM :  バイオリズムのグラフィック表示
  • EX6SEQUENCER :  タッチ操作を使った簡易シーケンサー
  • EX7ALIEN :  複数の敵を動かして弾を発射するデモ
  • EX8TECDEMO :  命令ごとの説明と技術評価用デモ

<高度なサンプル>
様々なBASIC命令を駆使したサンプルプログラム。

  • GAME1DOTRC :  敵の攻撃をよけながら画面上のドットをすべて消す絵文字で作ったレースゲーム
  • GAME2RPG :  敵を倒しながら3D風ダンジョンを進むロールプレイングゲーム
  • GAME3JUMP :  敵や障害物をよけながらゴールを目指す横スクロールジャンプアクションゲーム
  • GAME4SHOOTER :  ステージが進むと強化される敵を倒してスコアを稼ぐ弾幕シューティングゲーム
  • GAME5VS :  大きなキャラクターが剣で戦うシンプルな対戦型格闘ゲーム
  • GAME6TALK :  適当な質問に答えると適当な答えが返ってくるナンセンスな占い?ゲーム
  • GAME7EXPAD :  拡張スライドパッド専用。スティックを使ったお手玉ゲーム

<基本>

<基本的な事項>

  • 文字列はダブルクォーテーション( " )で囲む。
  • 条件式において、数値変数または数値が、0なら結果はFALSE(0)、0以外なら結果はTRUE(1)となる。
  • カーソルの左側に命令が無い状態で、HELPボタン(?マーク)を押すと、ヘルプの操作方法や、命令の一覧等を表示できる。
  • 行ごとに一気に削除したい場合は、SELを選んで、十字キー上下で選択して、バックスペース(またはYボタン)が便利。
  • DIRECTモード時、十字キー上下で履歴
  • 小数の演算では誤差が生じる場合があるので要注意。FOR~NEXTのSTEPで、小数を扱うときは誤差に注意。


<モード>

  • DIRECTモード: コンピューターに命令を直接与えるモード。命令をひとつひとつ、入力するたびに実行する。DIRECTボタンで切り替える。
    ※実行するには、ENTERキー(またはAボタン)を押す。
  • EDITモード: プログラムを入力するためのテキスト編集モード。複数の命令をEDITボタンで切り替える。
    ※実行するには、DIRECTモードに移りRUN命令を実行するか、EDITモードのままSTARTボタンを押す。


<プログラミング時(EDITモード時)の操作>

  • 十字ボタン :  カーソル移動。
  • Aボタン :  Enterキーと同じ。
  • Yボタン :  BSキーと同じ。
  • Lボタン :  SHIFTキーとほぼ同じ。
                   ※SHIFTキーとの違い:
                    Lボタンを押しながら、十字ボタンの上下でページ単位(画面単位)の移動、左右で行頭・行末へ移動 (スライドパッド
    )
  • Rボタン :  SHIFTキーと同じ。
  • STARTボタン :  プログラムを実行。実行中の時は、プログラムを中断する。
<プログラム読み書き支援機能>
Lボタン(or SHIFTキー)で、ファンクションキー部分に、ファイルの読み書き支援用ボタンが表示される。

<命令入力支援機能>  ※Visual Studioのインテリセンスみたいなもの。
最初の数文字を入力すると、入力候補選択エリアに、該当する命令を一覧表示。さらに続けて文字を入力すると候補が絞り込まれる。

<命令>
RUN :  (EDITモードで入力した)プログラムを実行する。※DIRECTモードで実行する。
  ※EDITモードのまま、STARTボタンで、RUN命令を記述せずに直接実行することが可能。実行中にSTARTボタンで停止
NEW :  (EDITモードで入力した)プログラムを消去する。※DIRECTモードで実行する。
  ※全てのプログラムSLOTが消去される(引数で限定可能)。
SAVE :  プログラムを保存する。※DIRECTモードで実行する。
  ※使用できる文字: 英数字と_(アンダースコア)
  ※引数でファイル名だけ指定した場合、プログラムSLOT0の内容が保存される。
  SLOT1, SLOT2, SLOT3 の場合は、それぞれファイル名の前にPRG1:, PRG2:, PRG3: を付ける。
  ※Lボタン(or SHIFTキー)で、ファンクションキー部分に、ファイルの読み書き支援用ボタンを表示して、保存することも可能(SAVEボタン)。
LOAD :  プログラムを読み込む。プロジェクト内のファイルの場合、"プロジェクト名 / ファイル名" の形式で指定する。
  ※引数でファイル名だけ指定した場合、プログラムSLOT0に読み込まれる。
  SLOT1, SLOT2, SLOT3 の場合は、それぞれファイル名の前にPRG1:, PRG2:, PRG3: を付ける。
  ※Lボタン(or SHIFTキー)で、ファンクションキー部分に、ファイルの読み書き支援用ボタンを表示して、読み込むことも可能(LOADボタン)。
FILES :  SDメモリーカードに保存したファイルの一覧を、コンソール画面に表示
DELETE :  SDメモリーカードに保存したファイルを、ファイル名を指定して削除する。
ACLS :  描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
CLS :  コンソール画面を消去。※グラフィック画面は消えない。
GCLS :  グラフィック画面を消去する(※コンソール画面は消えない)。色コードを指定した塗りつぶしも可能。
COLOR :  コンソール画面の表示色を指定。
RGB() :  8ビットRGB値をもとに色コードを得る。
RGBREAD :  色コードからRGBの各成分を得る。
PRINT :  文字(文字列)を表示する。


<グラフィック命令>

一般にGで始まる命令は、グラフィック画面に対する命令
GCLS :  グラフィック画面を消去する(※コンソール画面は消えない)。色コードを指定した塗りつぶしも可能。
ACLS :  描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
CLS :  コンソール画面を消去。※グラフィック画面は消えない。
GPAGE :  グラフィック表示ページと操作ページの指定。※GPAGE 4,4 で、GRP4を表示できる。
GCOPY : 他のグラフィックページから画像をコピー。
GLINE :  グラフィック画面に直線を引く
GCOLOR :  グラフィック描画色の指定
GPSET :  グラフィック画面に点を打つ
GBOX :  グラフィック画面に四角形を描く
GFILL :  グラフィック画面に四角形を描いて塗りつぶす
GCIRCLE :  グラフィック画面に円を描く
GPAINT :  グラフィック画面を塗りつぶす
GTRI :  グラフィック画面に三角形を描いて塗りつぶす
GPUTCHR :  グラフィック画面に文字を描く
GSPOIT() :  グラフィック画面の指定座標の色を取得


<サウンド命令>

BEEP :  音を出す。周波数、音量、パンポットの調整などが可能。
BGMPLAY :  音楽演奏 ※トラック番号省略時は0番。
MML(Music Macro Language)を使用した音楽演奏も可能。MMLと入力してHELPボタンで詳しい説明が見られる。
BGMSTOP :  音楽演奏停止 ※フェードアウトが可能。

・特にサウンド系の命令というわけではないが、併用すると便利な命令
WAIT :  指定回数分の垂直同期が来るまでプログラム停止。引数にはフレーム数を指定。※デフォルトで60fpsなので、60で1秒待つことになる。

<サウンドエフェクト>

EFCSET :  音楽のエフェクトの種類を選択。※3:リバーブ(宇宙)
EFCON :  エフェクター設定をONにする。エフェクトの種類はEFCSET命令で選択。

EFCSET 1 'エフェクトの種類 1:リバーブ(風呂場)
EFCON    'エフェクター設定ON


<立体視>

上画面のみ対応。
奥行き座標(Z座標)の設定  ※Z=1024(引っ込む), Z=0(奥行きなし), Z=-256(飛び出す)

  • コンソール画面 :  LOCATE命令
  • グラフィック画面 :  GPRIO命令
  • スプライト :  SPOFS命令
  • BG :  BGOFS命令

<カラー指定>

画面全体で65536色のカラーを使用できる。
・グラフィックページでは、ドット単位で32768色が使用可能。RGB関数で指定する。
※内部的にはRGB各色5ビット+透明1ビット(RGBA=5551)となるが、指定の際にはRGB関数を利用し、RGB各8ビットとして指定する。
2^5 * 2^5 * 2^5 = 2^15 = 32768
・コンソール画面(テキスト)では、透明色を含む16色から選択する。文字色と文字の背景色を設定できる。


<BG>

BGは、Back Groundの略。"BG画面"、"BGスクリーン" とも呼ぶ。
BG画面は4枚のレイヤーが重なった構造(レイヤー番号:0~3)になっており、それぞれにBGキャラを配置できる。
4枚のレイヤーは、いずれも上画面に表示されている。
デフォルトでは、レイヤー0~3は、いずれも上画面と同じサイズ(400×240)。※横25個×縦15個=375個 のBGキャラを配置できる。
16×16ドットのBGキャラを並べて背景画面を作る。
16×16ドット単位で配置する。※1ドット単位ではない。
BGキャラは、GRP5(グラフィックページ5)にあらかじめ読み込まれている。※横32個×縦32個=1024個
1つのキャラは16×16ドット。

0~1023までのキャラ番号が付いている。

BGキャラはBG画面に配置して、画面に表示される。※BGPUT命令などでBG画面に配置するだけですぐ使える。
BG画面はキャラ単位の座標を持つ。
1画面には、横に25キャラ、縦に15キャラ並ぶ。
BGSCREEN命令で、画面を超える大きさのBG画面を使用可能。

左上が原点(0, 0)  ※右下(24, 14)
X座標 0~24  ※横
Y座標 0~14  ※縦
1つのキャラは16×16ドット

各レイヤーの表示位置は、BGOFS命令により、ドット単位で変更できる。→ スクロールが可能。
重ね順は、BGOFS命令でZ座標を指定することで変更可能。3D表示の奥行きにも関係する。

<BGスクリーンの移動方法> ※スクロールなど。

  • BGOFS命令を繰り返す。
    ※表示物が、逆方向に動いているように見えるので注意。例えば、X座標を-1オフセットすると、表示物は右に+1動いたように見える。
  • BGANIM命令で動かす。


<BGのアニメーション>

BGANIM :  BGによるアニメ表示。
配列で指定する方法、DATA命令で指定する方法、直接引数として指定する方法がある。
アニメ対象(変化させる要素)は、いろいろと指定できる。
時間(フレーム数)にマイナス値を指定すると、直前の値から線形補間を行う。

※BGキャラを並べるときはキャラ単位。
※BGOFSやBGANIMでの移動は、BG座標に対して、3DS画面を移動させていくような指定になるので注意。また、移動はキャラ単位ではなくドット単位なので注意。


BGPUT :  BGキャラを、BG画面の指定したレイヤーに配置する
BGFILL :  BGスクリーンをBGキャラで塗りつぶし。指定した矩形領域を、1つのBGキャラで埋める
BGOFS :  BGスクリーンの表示オフセットを変更 / BGの座標を得る。
  ※表示物が、逆方向に動いているように見えるので注意。例えば、X座標を-1オフセットすると、表示物は右に+1動いたように見える。
BGCLR :  BGスクリーンを消去。レイヤー指定が可能。
BGSCREEN :  BGスクリーンのサイズをレイヤーごとに設定
BGSCALE :  BGスクリーンの拡大縮小。
BGROT :  BGスクリーンの回転。
BGHOME :  レイヤーの表示原点設定。※BGスクリーンに対する回転や拡大縮小の原点
BGCOPY :  BGスクリーンをキャラ単位でコピー。※BGスクリーンの指定範囲を他の位置にコピーする。
BGANIM :  BGによるアニメ表示。
BGCOORD :  ディスプレイ座標とBGスクリーン座標との変換。※名前はcoodinate(座標)から???
BGGET() :  BGスクリーンのBGキャラ情報を得る。

<SPRITE>

基本16×16ドットのキャラ(異なるサイズあり)を、1つの動く物体として画面に表示する。大きさは任意に設定できる。画面には最大512個まで表示可能。

  • 最大512個を同時に表示できる。
  • サイズ(幅×高さ)を自由に定義できる。
  • 回転、拡大、縮小の機能がある。
  • 衝突判定の機能がある。
  • スプライト間に親子関係を設定できる
  • 半透明化の機能がある。
  • 内部変数の読み書きができる。
SPRITE用キャラは、GRP4(グラフィックページ4)にあらかじめ読み込まれている。
キャラの基本サイズは16×16ドットだが、それ以外のサイズもある。
※SPSET命令で任意の管理番号のSPRITEに割り当てる。管理番号: 0~511

表示するSPRITEは、SPSET命令で512個まで準備できる。それぞれの番号のSPRITEに、どの番号のキャラ定義を割り当てるかを設定する。
SPRITEの表示座標はSPOFS命令を使い、ドット単位で指定する。※BGと違いキャラ単位の座標ではない。

左上が原点(0, 0)  ※右下(399, 239)
X座標 0~399  ※横
Y座標 0~239  ※縦
中心座標 (200, 120)

<SPRITEの重ね順>
SPLITEの重ね順
  • 重ね順は、Z座標を指定することで変更可能。
  • BGのZ座標と同列に扱われるので、BGの手前に出したり、奥に隠したりできる。
  • Z座標は、3D表示の奥行きにも関係する。
  • SPOFS命令で、表示位置と奥行きを指定できる。

<SPRITEの表示>
ACLS ' 描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
SPSET 0, 12  ' テンプレートの定義番号0012の画像を管理番号0のSPRITEに設定 ※この時点で原点(0, 0)に描画される
SPOFS 0, 400/2-16/2, 240/2-16/2 ' 管理番号0のSPRITEを、画面の中心に描画

<SPRITEの移動方法>
SPLITEの移動方法

  • SPOFS命令を繰り返す。
  • SPANIM命令で動かす。


<SPRITEのアニメーション>
SPANIM :  SPRITEによるアニメ表示。
SPCHK() : SPRITEのアニメーション状態を取得。全て0の時、アニメ停止中。

  • 配列で指定する方法、DATA命令で指定する方法、直接引数として指定する方法がある。
  • アニメ対象(変化させる要素)は、いろいろと指定できる。
  • アニメ開始はSPANIMを実行した次フレームから。
  • 時間(フレーム数)にマイナス値を指定すると、直前の値から線形補間を行う。

SPANIMのループ処理。

'==========================
'TEST_SPANIM_01
'==========================

ACLS

CNT=0 'FRAME-COUNT

SPSET 0,0
SPOFS 0,100,100            '初期位置
SPANIM 0,"XY",-5,200,200,3 '3回ループ

PRINT "FRAME-COUNT,X,Y"

@LOOP
SPOFS 0 OUT X,Y
PRINT CNT;",";X;",";Y 'FRAME-COUNT,X,Y
IF CNT==19 THEN END   '適当に、多めにループさせてみる
INC CNT
VSYNC 1
GOTO @LOOP

'===============================================
' 結果:
'  ループ中は、初期位置(100,100)では表示されないことがわかる。
' 
' FRAME-COUNT,X,Y
' 0,100,100
' 1,100,100   '0 開始
' 2,120,120   '1
' 3,140,140   '2
' 4,160,160   '3
' 5,180,180   '4
' 6,200,200   '5     0
' 7,120,120   '      1
' 8,140,140   '      2
' 9,160,160   '      3
' 10,180,180  '      4
' 11,200,200  '      5     0
' 12,120,120  '            1
' 13,140,140  '            2
' 14,160,160  '            3
' 15,180,180  '            4
' 16,200,200  '            5 終了
' 17,200,200
' 18,200,200
' 19,200,200

SPANIMの最後のフレームで、初期位置に戻してループさせる。

'==========================
'TEST_SPANIM_02
'==========================

ACLS

CNT=0 'FRAME-COUNT

SPSET 0,0
SPOFS 0,100,100       '初期位置
SPANIM 0,"XY",-5,200,200,1,100,100,3 '3回ループ

PRINT "FRAME-COUNT,X,Y"

@LOOP
SPOFS 0 OUT X,Y
PRINT CNT;",";X;",";Y 'FRAME-COUNT,X,Y
IF CNT==19 THEN END   '適当に、多めにループさせてみる
INC CNT
VSYNC 1
GOTO @LOOP

'===============================================
' 結果:
' 
' FRAME-COUNT,X,Y
' 0,100,100
' 1,100,100   '0 開始
' 2,120,120   '1
' 3,140,140   '2
' 4,160,160   '3
' 5,180,180   '4
' 6,200,200   '5
' 7,100,100   '6     0
' 8,120,120   '      1
' 9,140,140   '      2
' 10,160,160  '      3
' 11,180,180  '      4
' 12,200,200  '      5
' 13,100,100  '      6     0
' 14,120,120  '            1
' 15,140,140  '            2
' 16,160,160  '            3
' 17,180,180  '            4
' 18,200,200  '            5
' 19,100,100  '            6 終了
' 20,100,100
' 21,100,100
' 22,100,100
' 23,100,100
' 24,100,100

SPANIMの最初のフレームで、初期位置に戻してループさせる。

'==========================
'TEST_SPANIM_03
'==========================

ACLS

CNT=0 'FRAME-COUNT

SPSET 0,0
'SPOFS 0,100,100       '初期位置
SPANIM 0,"XY",1,100,100,-5,200,200,3 '3回ループ

PRINT "FRAME-COUNT,X,Y"

@LOOP
SPOFS 0 OUT X,Y
PRINT CNT;",";X;",";Y 'FRAME-COUNT,X,Y
IF CNT==19 THEN END   '適当に、多めにループさせてみる
INC CNT
VSYNC 1
GOTO @LOOP

'===============================================
' 結果:
' 
' FRAME-COUNT,X,Y
' 0,0,0
' 1,0,0       '0 開始
' 2,100,100   '1
' 3,120,120   '2
' 4,140,140   '3
' 5,160,160   '4
' 6,180,180   '5
' 7,200,200   '6     0
' 8,100,100   '      1
' 9,120,120   '      2
' 10,140,140  '      3
' 11,160,160  '      4
' 12,180,180  '      5
' 13,200,200  '      6     0
' 14,100,100  '            1
' 15,120,120  '            2
' 16,140,140  '            3
' 17,160,160  '            4
' 18,180,180  '            5
' 19,200,200  '            6 終了
' 20,200,200
' 21,200,200
' 22,200,200
' 23,200,200
' 24,200,200

<SPRITEの内部変数>
各SPRITEは、8個の内部変数(内部変数番号0~7)を持つ。内部変数は、数値を扱うことができ、文字は扱えない。
SPVAR :  SPRITE用内部変数への書き込み。
SPVAR() :  SPRITE用内部変数の読み込み。

ACLS  ' 描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
SPSET 0,3  ' 管理番号0のスプライトに、テンプレートの定義番号3の画像を割り当てる
SPOFS 0,400/2-16/2,240/2-16/2  ' 管理番号0のスプライトを画面の中心にオフセット
SPVAR 0,5,777  ' 管理番号0のスプライトの、内部変数番号5の内部変数に、777を代入
FOR I=0 TO 7
 ' 管理番号0のスプライトの、内部変数を全て読み込む。改行無し、コンマ区切りで表示。
 PRINT SPVAR(0,I);",";  ' 結果: 0,0,0,0,0,777,0,0,
NEXT

<SPRITE同士の衝突判定>
SPCOL命令で衝突判定情報を設定し、SPHITSP関数で衝突判定を行う。
SPCOL実行後、SPHITSP実行前に、必ず、SPOFSまたはSPANIMで位置情報を更新する。
且つ、位置は一度、原点以外にする。その後は、直後に原点にしても良い。

1) SPCOL命令で、衝突判定の対象にしたいSPRITEを指定する(範囲指定可能)。
2) SPOFSまたはSPANIMで位置情報を更新する。※SPCOLとSPHITSPの間で実行すること。
3) SPHITSP関数で、引数に指定したSPRITEの衝突判定を行う。

SPOFSを、プログラム中に全く実行しなかった場合
・衝突判定するが、スケールが対応しない。→ ダメ。

SPCOL実行の前に、SPOFSを実行した場合
・位置が(0,0)だと、衝突判定するが、スケールが対応しない。→ ダメ。
・位置が(0,0)以外だと、衝突判定するが、スケールが対応しない。→ ダメ。
SPCOL実行の後に、SPOFSを実行した場合
・位置が(0,0)だと、衝突判定するが、スケールが対応しない。→ ダメ。
・位置が(0,0)以外だと、衝突判定する、スケールも対応する。→ 良さそう

SPCOL実行の後に、SPOFSで位置を(0,0)以外にして、その直後に位置を(0,0)にした場合
・位置を(0,0)にしたにも関わらず、衝突判定する、スケールも対応する。→ 良さそう
SPCOL実行の前に、SPOFSで位置を(0,0)以外にして、その直後に位置を(0,0)にした場合
・衝突判定するが、スケールが対応しない。→ ダメ。

SPCOLの後、SPOFSまたはSPANIMを実行しなかった場合、SPHITSPによる衝突判定が、おかしな挙動になる。
また、SPCOLの後に、SPOFSを実行しても、位置が(0,0)だと、おかしな挙動になる。(1,0)か(0,1)にしてみるとうまくいく。(0.1,0)などでもうまくいく。
SPCOL実行の後に、SPOFSで位置を(0,0)以外にして、その直後に位置を(0,0)にした場合はうまくいくことから、一度(0,0)以外に動かせば大丈夫らしい。

( ゚Д゚)意味不明・・・。バグなのか???

SPCOL実行後は、必ず、SPHITSP実行前に、SPOFSまたはSPANIMで位置情報を更新する。
且つ、位置は
一度、原点以外にする。その後は、直後に原点にしても良い。

'==========================
'TEST_COLLISION
'==========================

ACLS

'いちご======================
SPSET 0,0
SPSCALE 0,2,2
SPCOL 0,TRUE
SPOFS 0,1,0 '直後に、原点に戻す

'みかん======================
SPSET 1,1
SPCOL 1
X=70:Y=20
SPOFS 1,X,Y

@LOOP
GOSUB @MOVE_MIKAN
IF SPHITSP(1,0) THEN SPCOLOR 1, RGB(255,0,0) ELSE SPCOLOR 1,RGB(255,255,255)
VSYNC 1
GOTO @LOOP

@MOVE_MIKAN
B=BUTTON()
IF B AND #UP    THEN DEC Y '1
IF B AND #DOWN  THEN INC Y '2
IF B AND #LEFT  THEN DEC X '4
IF B AND #RIGHT THEN INC X '8
SPOFS 1,X,Y
RETURN

SPCOL :  SPRITE衝突判定情報の設定。範囲指定可能。
SPHITSP :  SPRITEの衝突判定。衝突したSPRITEの管理番号を返す(衝突無し -1)。
※SPCOLで衝突判定領域を設定したSPRITE同士で、衝突判定する。
※複数のSPRITEと衝突していても、返すのは、最も若いSPRITE管理番号ひとつだけなので要注意。
必ず衝突判定させたいもの毎にSPHITSPを実行させるなど、工夫が必要。

※存在していないSPRITEのID範囲であっても、指定は可能。→ いずれ使用するであろう範囲を、指定しておくことができる。

<自前のSPRITEの定義>
1) LOAD "GRP4:ファイル名" で、作ったスプライトファイルを読み込む。
2) SPDEF命令で、読み込んだスプライトから任意の領域を切り取って、定義番号にセット。

SPSET :  SPRITEを準備する。矩形での範囲指定可能。表示するSPRITEをメモリー上に準備して画面に表示する。
SPOFS :  SPRITEの座標の変更(移動)、または、SPRITEの座標を得る
SPCHR :  SPRITEのキャラクタ定義を変更。※キャラ画像だけ変更し、その他の設定はそのまま。
SPDEF :  SPRITEのキャラクタ定義用テンプレートを作成。
SPSCALE :  SPRITEを拡大縮小。
SPROT :  SPRITEの回転角度指定。※回転角度は度数法(0~360度)で指定する。正で時計回り、負で反時計回り。
SPHOME :  SPRITEの基点を変更する。
SPHIDE :  SPRITE表示を隠す。
SPSHOW :  隠れているSPRITEを表示する
SPCOLOR :  SPRITEの表示色を設定。透明度の設定が可能(0~255の256段階)。
SPANIM :  SPRITEによるアニメ表示。
SPCHK() :  SPRITEのアニメーション状態を取得。全て0の時、アニメ停止中。
SPLINK :  SPRITEを別のSPRITEにリンク。リンクは座標のみ(回転角度や倍率情報は対象外)。
リンク先(親)指定は自分よりも小さい管理番号のみ。
SPUNLINK :  SPLINK命令による連結を切り離す。
SPCLR :  指定SPRITEの使用をやめて、メモリーを解放。

<コンソール出力>

PRINT :  コンソール画面への文字表示。
式を省略すると改行のみ行う。
セミコロン( ; ) 表示後に改行せず、次の表示を密着させる。
カンマ( , ) 表示後に改行せず、次の表示を一定間隔開ける。※システム変数のTABSTEP単位に従う。

LOCATE :  コンソール画面への文字表示位置を指定。
X座標は右方向の文字数 (0~49) ※XSCREEN 4 と下画面(0~39)
Y座標は下方向の文字数 (0~29)
表示位置には奥行き(Z座標)も指定可能。画面奥は0~1024、画面手前は0~-256で指定。

CLS :  コンソール画面を消去。※グラフィック画面は消えない。
ACLS :  描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
GCLS :  グラフィック画面を消去する(※コンソール画面は消えない)。色コードを指定した塗りつぶしも可能。

<演算子>

<算術演算子>

  • +   加算
  • -   減算
  • *   乗算
  • /   除算
  • MOD   剰余
  • DIV   整数同士(それぞれの数値の小数点以下は切り捨て)の除算。結果も整数(小数点以下は切り捨て)。

<比較演算子>
式が評価された結果、真なら1、偽なら0を返す。

  • ==   等しい
  • !=   等しくない
  • >   より大きい
  • <   より小さい
  • >=   以上
  • <=   以下

<論理演算子> 複数条件の比較用

  • 条件1 && 条件2     論理積。同時に満たす。
  • 条件1 || 条件2     論理和。いずれかを満たす。 ※ || の文字は、キーボード上で ? の左上にある。
  • 条件1 AND 条件2     ビット論理積。同時に満たす。
  • 条件1 OR 条件2     ビット論理和。いずれかを満たす。

<コメント>

コメント記述用の記号として、アポストロフィー( ' )を使う。REM命令と同じ。※REMARK(コメント)
コメント内容は、プログラム実行に影響しない。

<命令を区切る>

コロン( : )複数の命令を区切って1行に書くことができる。

X=20:Y=30

<論理値>

論理値(真偽値, 真理値)

  • TRUE :  論理値の「真」。※TRUEの値は常に1である。
  • FALSE :  論理値の「偽」。※FALSEの値は常に0である。


※条件式において、数値変数または数値が、0なら結果はFALSE(0)、0以外なら結果はTRUE(1)となる。

<変数>

変数には、数値変数、文字列変数がある。
※変数名は1文字でなくても良い。英字で始まり、英数字とアンダースコア( _ )からなる任意の長さの名前が付けられる。

<数値変数>

  • 宣言時の型指定は、特に無い。
    サフィックスにより、型指定が可能。%で整数型。#で実数型。無指定(デフォルト)は実数型。
  • プログラム動作モードとして、OPTION STRICT指定の時は、全ての変数宣言が必要。※VAR命令やDIM命令で変数宣言できる。
  • 宣言時は、自動的に0で初期化される。
  • 文字列は代入できない。


<文字列変数>

  • 文字列変数は、変数名の末尾に$記号を付けて表す。
  • 文字列変数同士は、足し算によって結合できる。
A$ = "HELLO "
B$ = "WORLD"
C$ = A$ + B$
PRINT C$    ' HELLO WORLD

<変数のインクリメントとデクリメント>

変数のインクリメントとデクリメント
INC :  変数の値を+1。加算する値を指定可能(省略時:1)。
DEC :  変数の値を-1。減算する値を指定可能(省略時:1)。

<数値と文字列の変換>

・数値から文字列
FORMAT$():  表示書式を使って、値を整形し、文字列化する。
STR$() :  数値から文字列を得る。

・文字列から数値
VAL():  文字列から数値を得る。※数値になり得ないような文字列を指定した場合、0が返る。

<命令と関数>

<命令>
ACLS :  描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
INPUT :  キーボードから数値または文字列を入力。入力用のガイドメッセージを表示できる(省略可)。変数は複数指定可能。
IF~THEN ~ELSE~ENDIF :  条件分岐。ELSEとENDIFはオプション。処理が複数行にわたるときはENDIFを使用。
※一行で済む場合はENDIFはいらず、コロンで区切ることで、複数の処理も可能。
FOR~NEXT :  処理を指定回数繰り返す。STEP増分は、省略時は1。※STEPで増分を指定する際に、小数を扱うときは誤差に注意。
WHILE~WEND :  条件が成立している間、WENDまでを繰り返す。
BREAK :  ループから強制的に抜ける。
END :  プログラムを終了。プログラムを途中で終了させることができる。プログラムは最後の行に達すると終了するので、必ずしも必要ではない。
GOSUB @ラベル :  サブルーチンの呼び出し。サブルーチンからは、RETURN命令で、元のルーチンに戻れる。
GOTO @ラベル :  強制分岐。ラベルに強制ジャンプする。
ON~ GOTO @ラベル :  制御変数の値に合わせて、ラベル行に分岐。
ON~ GOSUB @ラベル :  制御変数の値に合わせて、サブルーチン呼び出し。

<関数>
RND() :  整数の乱数を得る(0~最大値-1まで)。
BUTTON() :  ハードウェアボタンの状態取得。各ボタンに対応した数値を返す。何も入力が無い場合は0を返す。
LEN() :  文字列内の文字数を得る / 配列の要素数を得る
RAD() :  度からラジアンを求める。度:0~360
SIN() :  サイン値を返す。角度はラジアンで指定する。
COS() :  コサイン値を返す。角度はラジアンで指定する。
TAN() :  タンジェント値を返す。角度はラジアンで指定する。

<ユーザー定義関数>

' ユーザー関数の定義例
DEF ADD(X, Y)   ' DEFからENDまでが定義範囲
 RETURN X+Y    ' 戻り値
END

<ユーザー定義命令>

' ユーザー命令の定義例
DEF FUNC_ADD  X, Y   ' DEFからENDまでが定義範囲
 PRINT X+Y
END

' 呼び出し
FUNC_ADD  10, 5   ' 結果は、15 と表示される

<配列>

配列の宣言
DIM :  使用する配列を宣言。※複数宣言するときは、カンマで区切る。
※DIMとVARどちらを使っても良い。
※通常の変数と異なり、プロシージャ内での、DIM / VARによる変数宣言は、ローカル変数扱いになる。
例えば、DEF~END内で宣言した場合、スコープはその中だけになるので注意。
試したところ、@ラベル~RETURN内でも同様だった。

ACLS ' 描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
DIM RGB$[3]   ' 配列を宣言 ※要素数3の文字列変数RGB$の配列

' 各要素への、値の代入
RGB$[0] = "RED"
RGB$[1] = "GREEN"
RGB$[2] = "BLUE"

' 全ての要素を表示してみる
FOR I=0 TO LEN(RGB$)-1   ' LEN() : 配列の要素数を得る
 PRINT RGB$[I]   ' セミコロン無しなので、改行しながら表示
NEXT

UNSHIFT :  配列の先頭に要素を追加(要素数が1つ分増える)。

<配列変数に配列変数を代入>

  • 配列変数に、配列変数を代入することができる。
    ※Javaにおける、配列変数への配列変数の代入による、参照のコピーのイメージ。要素が複製されるわけではなく、それぞれの配列変数が、同一の要素を参照することになる。
    ※同一の実体を参照するため、ある配列で要素を変更すると、別の配列でも影響を受けるので注意。
    ※C言語では、配列変数への配列変数の代入は不可。ポインタへの配列変数の代入は可能。
  • ユーザー定義関数の戻り値としても、配列が利用可能。
  • 実体が異なる配列のコピーは、COPY命令で可能。


COPY :  配列を他の配列にコピー

ACLS ' 描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
DIM A[3] '要素数3の配列を宣言
A[0]=123
A[1]=456
A[2]=789

DIM B[0] '適当な要素数の配列を宣言
B=A ' 配列変数に配列変数を代入。※参照のコピー
PRINT B[0] '123(改行)
PRINT B[1] '456(改行)
PRINT B[2] '789(改行)

<サブルーチン>

GOSUB @ラベル :  サブルーチンの呼び出し。サブルーチンからは、RETURN命令で、元のルーチンに戻れる。
ON~ GOSUB @ラベル :  制御変数の値に合わせて、サブルーチン呼び出し。
ON~ GOTO @ラベル :  制御変数の値に合わせて、ラベル行に分岐。

'良くない例
'エラー RETURN without GOSUB

GOSUB @MYSUB

@MYSUB
 PRINT "テスト"
RETURN
'良い例
'エラー無し

GOSUB @MYSUB
END

@MYSUB
 PRINT "テスト"
RETURN

<垂直同期>

VSYNC :  Vertical Sync(垂直同期)の略。垂直同期と、同期を取る。
指定回数分の垂直同期が来るまでプログラム停止。WAITとは異なり、前回のVSYNCからのVSYNC回数。
引数には、前回のVSYNCからの経過フレーム数を指定。
※ループ内に VSYNC 1 で、そのループが1秒間に最大60回までしか繰り返さないように制限できる。
プチコン3号では、1/60秒間隔で垂直同期イベントが発生する。

垂直同期までに処理が完了しなかった場合、VSYNC命令の処理は無視される。
例えば、もしも、ループ内でVSYNC 1を実行している状況において、
ループ内の処理が1/60秒間で完了しなかった場合、VSYNC 1の処理は無視される。

プチコン3号では、ループ内の処理が軽く、ループの最後にVSYNC 1を記述した場合は、60fpsとなる。

' 60fps
@GAMELOOP
VSYNC 1 ' 指定回数分の垂直同期が来るまでプログラム停止
GOTO @GAMELOOP

<フレームカウント>

MAINCNT :  システム変数。SmileBASIC起動時からのフレームカウント数。
※1/60秒ごとに値が自動的に+1される。
→ 任意の変数をループ内でインクリメントした場合の実際のフレーム数に対して、処理が重い場合にフレーム数に差が出る場合がある。これを利用してFPSを算出できる。

<画面モード>

XSCREEN :  画面モードの設定。※XSCREEN 4 で、上下をつないで1枚のように扱うことができる(上画面の両外側は使えない)。
DISPLAY :  操作対象の上下画面を選択(0:上画面, 1:下画面)。

' 下画面を操作する場合
ACLS ' 描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
XSCREEN 3 ' 画面モードを3にする。
DISPLAY 1 ' 操作対象を下画面にする。

<入力>

BUTTON() :  ハードウェアボタンの状態取得。各ボタンに対応した数値を返す。何も入力が無い場合は0を返す。
STICK :  スライドパッドの情報取得
TOUCH :  タッチ情報取得

<漢字>

スマイルブーム公式サイトの文字コード表→LINK

<CHR$()関数で、文字コードを指定する方法>

UTF-16の文字コードを使用できる。
※プログラム実行が必要なので、コメント文には使えない。
※16進数表記: SmileBASIC, BASICでは&Hを前置する。C,C++では0xを前置。

ACLS ' 描画設定をBASIC起動時の状態に戻す。※サウンド設定には影響しない。
COLOR #TCYAN
PRINT "プチコン3";CHR$(&H53F7)  'UTF16文字コードでは、号はコードポイントU+53F7。16進数表記のための&Hを前置。

CHR$() :  指定された文字コードから文字を返す

<DIRECTモードで、プログラムSLOT 0 以外にKANJITBLを読み込み、漢字テーブルから1文字ずつコピー&ペーストする方法>
※コピペするだけなので、コメント文にも漢字が使える。

' DIRECTモードでLOAD "PRG1:SYS/KANJITBL"を実行しておく
PRINT "プチコン3号" ' 漢字をSLOT 1からコピペで持ってくる

※SLOT 1の内容を消したい場合は、NEW 1を実行

<データ>

READ~ DATA:  データを扱う。
※ループで連続的にDATA命令のデータを読み込む場合、最後のデータを、""や、0 にしておき、条件判断でループを抜けると良い。

READ :  DATA命令で列挙した情報を変数に読み込む
RESTORE :  READ命令が読み込む先頭データを指定。※READ命令が読みに行く先のDATA命令をラベルを使って指定できる。
DATA :  READで読み込むデータの定義。数値も文字列も混在可能。

<乱数>

RND() :  整数の乱数を得る。引数には最大値を指定する(0~最大値-1までを返す)。
RANDOMIZE :  乱数系列の初期化。※引数のシードIDとシード値が、毎回同じで実行すれば、RND()関数で、毎回同じ乱数を生成することが可能。

<コールバック>

各々のスプライトやBGから、サブルーチンを呼び出すことができる。
コールバックとして設定したサブルーチンは、CALL SPRITE命令、または、CALL BG命令を実行したタイミングで呼び出される。
SPFUNC :  SPRITEごとに処理を割り当て。CALL SPRITE により全SPRITEの処理を実行
BGFUNC :  BGレイヤーごとに処理を割り当て。CALL BG により全BGレイヤーの処理を実行
CALLIDX :  システム変数。SPFUNCおよびBGFUNCで呼び出された番号。
CALL SPRITE :  SPRITEコールバックの呼び出し。SPFUNCで設定されたSPRITE毎の処理を一斉呼び出し。
CALL BG :  BGコールバックの呼び出し。BGFUNCで設定されたBG毎の処理を一斉呼び出し。






Win32 API

Win32 API

※自分専用の覚え書き

<参考文献>

  • msdn "Win32 アプリケーションの作成 (C++)" → Link
  • msdn "C++ による Windows プログラミングの学習" → Link

Win32 アプリケーション

クリックするとメッセージボックスが出るウィンドウ

// プリプロセッサ ディレクティブ
#include <windows.h>                      // Win32 API を使用するためインクルード
#include <tchar.h>                        // TCHAR型 ※char型かwchar型に置き換わる

// 関数プロトタイプ宣言
LRESULT CALLBACK MyWinProc(HWND, UINT, WPARAM, LPARAM);

// ===================================================================================
// WinMain関数
// ===================================================================================
// Win32アプリケーションの初期エントリポイント。Windowsシステムが呼び出す。
// 戻り値はOSでは使用しないが、別のプログラムにステータスコードを伝達できる
int WINAPI WinMain(                       // WINAPI : 関数の呼び出し規約 __stdcall の再定義
	HINSTANCE hInstance,                  // アプリケーションの現在のインスタンス(current instance)へのハンドル
	HINSTANCE hprevInstance,              // アプリケーションの以前のインスタンス(previous instance)へのハンドル ※現在は、常にNULL
	LPSTR lpCmdLine,                      // コマンドラインが格納されたヌル終端された文字列(プログラム名を除く)へのポインタ
	int nCmdShow)                         // ウィンドウの表示状態
{
	// ===================================================================================
	// ウィンドウクラスの、作成・設定・登録
	// ===================================================================================
	// 作成
	WNDCLASSEX wcex;                                 // ウィンドウクラス構造体

	// 設定 ※ウィンドウに関する情報
	wcex.cbSize = sizeof(WNDCLASSEX);                // WNDCLASSEX構造体のサイズ(バイト)
	wcex.style = CS_HREDRAW | CS_VREDRAW;            // クラススタイル ※ここではサイズ変更時に再描画
	wcex.lpfnWndProc = MyWinProc;                    // ウィンドウプロシージャーへのポインタ
	wcex.cbClsExtra = 0;                             // ウィンドウクラスの追加バイト数
	wcex.cbWndExtra = 0;                             // ウィンドウインスタンスの追加バイト数
	wcex.hInstance = hInstance;                      // アプリケーションの現在のインスタンスへのハンドル
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);    // アイコン素材へのハンドル
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);      // カーソル素材へのハンドル
	wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);   // 背景ブラシへのハンドル
	wcex.lpszMenuName = NULL;   // メニューリソース名。※ヌル終端された文字列へのポインタ。NULL:デフォルトメニューなし
	wcex.lpszClassName = _T("MySampleWindow");       // ウィンドウクラス名。※ヌル終端された文字列へのポインタ、またはATOM
	wcex.hIconSm = NULL;                             // 小アイコンへのハンドル。NULLの場合、hIconで指定されたアイコンを縮小

	// OSに登録
	if (RegisterClassEx(&wcex) == 0) return 0;       // 成功:登録されたクラスを一意に特定するATOMを返す。失敗:0を返す

	// ===================================================================================
	// ウィンドウのインスタンス作成
	// ===================================================================================
	// インスタンス作成  ※オーバーラップウィンドウ、ポップアップウィンドウ、子ウィンドウのいずれかを拡張スタイル付きで作成
	// 新しいウィンドウへのハンドルを返し、関数が失敗した場合はNULLを返す。  ※#define NULL 0
	HWND hWnd = CreateWindowEx(            // ウィンドウを作成し、ウィンドウへのハンドルを返す。失敗した場合、NULLを返す
		0,                                 // 拡張されたウィンドウスタイル ※0:既定の動作
		_T("MySampleWindow"),              // 登録されているウィンドウクラス名
		_T("マイ サンプル ウィンドウ"),      // ウィンドウ名 ※タイトルバーがあれば、そこに表示される
		// オーバーラップウィンドウ(キャプションと境界線), タイトルバーにコントロールメニューボックス, 最小化ボタン
		WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,     // ウィンドウスタイル  ※WS_OVERLAPPEDWINDOWが便利
		100,                               // 横位置 (初期の水平位置)
		200,                               // 縦位置 (初期の垂直位置)
		300,                               // 幅
		400,                               // 高さ
		NULL,                              // 親ウィンドウ、またはオーナーウィンドウへのハンドル  ※NULL:最上位ウィンドウ
		NULL,                              // メニューへのハンドル、または、子ウィンドウ識別子    ※NULL:メニューを使用しない
		hInstance,                         // アプリケーションの現在のインスタンスへのハンドル
		NULL);                             // ウィンドウ作成データ(追加のアプリケーションデータ) ※void* 型の任意のデータへのポインタ

	// インスタンス作成の失敗時の処理
	if (hWnd == NULL) return 0;              // 失敗した場合、NULL  ※#define NULL 0

	// ===================================================================================
	// ウィンドウの表示
	// ===================================================================================
	// ウィンドウ表示  ※CreateWindowExによって返されるウィンドウハンドルを利用
	ShowWindow(hWnd, nCmdShow);         // 指定されたウィンドウの表示状態を設定
	// ウィンドウ更新
	UpdateWindow(hWnd);                 // 指定されたウィンドウの更新リージョンが空ではない場合、
										// ウィンドウへメッセージを送信し、そのウィンドウのクライアント領域を更新

	// ===================================================================================
	// メッセージループ
	// ===================================================================================
	// MSG構造体
	MSG msg;              // メッセージ情報を格納するための構造体

	// メッセージループ
	BOOL bRet;                          // typedef int BOOL;
	while ((bRet = GetMessage(          // キューからメッセージを取得し、指定の構造体に格納する
		&msg,             // MSG構造体へのポインタ ※メッセージ情報が格納される
		NULL,             // メッセージの取得に使う(取得元)ウィンドウへのハンドル
						  // ※NULL:呼び出し側スレッドに関連付けられている全てのウインドウへのメッセージを取得
		0,                // 取得するメッセージの最小値  ※第3、第4引数が共に0の場合、利用可能なすべてのメッセージを返す
		0                 // 取得するメッセージの最大値
		)) != 0) {                      // WM_QUITメッセージのとき、0。違う場合、0以外の値
		if (bRet == -1) {               // エラーの場合、-1
			break;                      // while文を抜ける
		}
		else {                          // 0と-1 以外の値の処理  ※WM_QUITとエラー以外
			TranslateMessage(&msg);     // キーボード入力に関連付けられており、キー操作を文字に変換

			// メッセージのターゲットウィンドウのウィンドウプロシージャを呼び出すようOSに通知する。
			// これでOSがウィンドウハンドルを検索し、ウィンドウに関連付けられた関数ポインターを特定し、関数を呼び出すことになる
			DispatchMessage(&msg);      // Windowsによるウィンドウプロシージャの呼び出しが間接的に実行される。
										// ウィンドウプロシージャは、戻り値をDispatchMessageに返す
		}
	}

	// ===================================================================================
	// 終了処理
	// ===================================================================================
	// ウィンドウクラスのOS登録解除
	UnregisterClass(_T("MySampleWindow"), hInstance);          // ウィンドウクラス名, インスタンスへのハンドル
	// アプリケーションの終了コード
	return msg.wParam;                                         // WM_QUITメッセージ時の、wParamの値を返す
}

// ===================================================================================
// ウィンドウプロシージャ(Window Procedure)
// ===================================================================================
// ウィンドウへ送信されたメッセージを処理する、アプリケーション定義のコールバック関数
LRESULT CALLBACK MyWinProc(       // CALLBACK : 関数の呼び出し規約 __stdcall の再定義 ※WINAPIと同じ
	HWND hWnd,                    // ウィンドウへのハンドル
	UINT uMsg,                    // メッセージ識別子
	WPARAM wParam,                // メッセージに関する、最初の追加情報
	LPARAM lParam)                // メッセージに関する、2番目の追加情報
{
	switch (uMsg)
	{
	case WM_DESTROY:              // ウィンドウが破棄された時のメッセージ
		// スレッドが自らの終了を要求したことをシステムに伝える。(キューへWM_QUITメッセージをポストし、すぐに制御を戻す)
		PostQuitMessage(0);       // 引数には、アプリケーションの終了コードを指定する。
								  // この値は、メッセージのwParamパラメータとして使われる。※終了時にWinMain関数が返す値になる。
		break;
	case WM_LBUTTONDOWN:          // ウィンドウのクライアント領域で、左マウスボタンを押した時のメッセージ
		MessageBox(hWnd, _T("hello, world!"), _T("messege"), MB_OK);
		break;
	default:
		// 既定のメッセージ処理をする、既定のウィンドウプロシージャ
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}


スッキリ版

上と内容は同じ

#include <windows.h>
#include <tchar.h>

LRESULT CALLBACK MyWinProc(HWND, UINT, WPARAM, LPARAM);

// WinMain関数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprevInstance, LPSTR lpCmdLine, int nCmdShow) {
	// ウィンドウクラスの、作成・設定・登録
	WNDCLASSEX wcex;
	wcex.cbSize = sizeof(WNDCLASSEX);
	wcex.style = CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc = MyWinProc;
	wcex.cbClsExtra = 0;
	wcex.cbWndExtra = 0;
	wcex.hInstance = hInstance;
	wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
	wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
	wcex.lpszMenuName = NULL;
	wcex.lpszClassName = _T("MySampleWindow");
	wcex.hIconSm = NULL;
	if (RegisterClassEx(&wcex) == 0) return 0;

	// ウィンドウのインスタンス作成
	HWND hWnd = CreateWindowEx(0, _T("MySampleWindow"), _T("マイ サンプル ウィンドウ"),
		WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX, 100, 200, 300, 400, NULL, NULL, hInstance, NULL);
	if (hWnd == NULL) return 0;

	// ウィンドウの表示
	ShowWindow(hWnd, nCmdShow);
	UpdateWindow(hWnd);

	// メッセージループ
	MSG msg;
	BOOL bRet;
	while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
		if (bRet == -1) {
			break;
		}
		else {
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
	}

	// 終了処理
	UnregisterClass(_T("MySampleWindow"), hInstance);
	return msg.wParam;
}

// ウィンドウプロシージャ
LRESULT CALLBACK MyWinProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
	switch (uMsg)
	{
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	case WM_LBUTTONDOWN:
		MessageBox(hWnd, _T("hello, world!"), _T("messege"), MB_OK);
		break;
	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}





マイブログへようこそ♪
PLEASANT_DRAGON

2DCG&3DCG,プログラミング,
日記などを掲載中☆

(*´▽`*)コメント大歓迎です☆

最新記事
記事一覧

全ての記事を表示する

カテゴリ
SAI (0)
mi (2)
C (1)
C++ (1)
C# (0)
VBA (0)
月別アーカイブ
最新コメント
RSSリンクの表示
リンク
FC2ブログランキング

FC2Blog Ranking

ピックアップ商品1♪










カレンダー
09 | 2017/10 | 11
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -
ブログ内検索フォーム
プロフィール

エクレア

Author:エクレア


  • 2DCG&3DCGの創作活動をしています。

  • SF系のメカが大好物。

アクセスカウンター
Twitter
ピックアップ商品2♪