フラクタル図形を描画してみる 【Python & tkinter】

Python

Python を使って、フラクタル図形(マンデルブロー図形)を描画してみます。
Python に入っている tkinter を使います。

以下の環境で動作確認をしています。
環境: Windows パソコン、Python 3.x、tkinter 8.6 以上

背景

このサイトではこれまで、tkinter を使った GUI アプリなどを扱ってきています。

そこで今回は、Python でフラクタル図形を生成し、tkinter の GUI 上に表示するスクリプトについてまとめ、公開しておくことにします。
描画する図形は何でもよく、フラクタル図形のシンプルなものとしてもよいですが、せっかくですのでよく知られているマンデルブロー図形とします。
任意の箇所をダブルクリックしていくと、画像を拡大して表示できます。

ネット検索をすると、Python でインターフェースを作っておき、アプリ上の操作で画像を自由自在に表示する、といったサンプルコードは少ないようです。
そこで、自力で何らかの画像データを作成したとき、tkinter 上で表示する事例にもなるよう、サンプルコードをまとめ、公開しておくことにします。
アプリ上で、画像の画素数やカラーなども変更・設定できます。フラクタルのパターンを使ったデザインや、パソコンの壁紙の作成なども可能になります。

設定と起動方法

① パソコン内にフラクタル画像作成用のフォルダ(例: mandelbrot1)を作成してください。
例: C:\user\mandelbrot1
② ①のフォルダ内に “mandelbrot1.py” という名前でテキストファイルを作成し、以下のサンプルスクリプトを貼りつけて保存してください。
③ コマンドプロンプトを起動し、②のサンプルスクリプトを実行してください。
例: python C:\user\mandelbrot1\mandelbrot1.py

使い方

基本操作

・ [draw] ボタンをクリックすると、マンデルブロー図形を描画します。
・ マンデルブロー図形を描画した状態で、画面上で右クリック(シングルクリック)をすると、表示倍率を変えずに、クリックをした地点を中心とした図形を再描画します。
・ マンデルブロー図形を描画した状態で、画面上でダブルクリックをすると、ダブルクリックをした位置に移動し、かつ、表示倍率を上げて図形を描画します。
・ [up] 、[down] ボタンをクリックすると、表示領域をそれぞれ、上側、下側に移動します。
・ [left]、[right] ボタンをクリックすると、表示領域をそれぞれ、左側、右側に移動します。
・ [zoom_in]、[zoom_out] ボタンをクリックすると、表示をそれぞれ、拡大、縮小します。
・ [hue +30 deg]、[hue -30 deg] ボタンをクリックすると、各点でのカラーを変更します。具体的には、各点での輝度値を色相環上の所定角分、変更します。
・ [save] ボタンをクリックすると、表示されている画像を、filename 欄に示されたファイル名で、①のフォルダ内に保存します。
・ [set default] ボタンをクリックすると、設定を初期値に戻します。

その他、詳細

・ 操作画面上で、点(x1_center, y1_center) は、表示する画像の中心となる座標です。
・ width w1 は、X 軸方向の描画範囲です。Y 方向の描画範囲は、以下の画素数の設定で自動で設定されます。表示倍率を微調整する場合はこの値を変更し、[draw] ボタンをクリックしてください。
・ nx1、ny1 は、それぞれ、X 軸方向、Y 軸方向の画素数です。画像の画素数を変更する場合は、この欄で設定してください。
パソコンの壁紙を作りたい場合は、モニターの画素数をこの欄に入力します。また、計算スピードを上げたい場合は、最初は小さな値を設定して、気に入った色設定やレイアウトが見つかったら大きな値に戻して画像を出力する、などしてください。
・ hue1_offset は、基準となる色相です。おおまかにいえば、上の図の背景色の設定(色相)です。色相は、0 ~ 360 度の範囲で、0 度が赤色、120 度が緑色、240 度が青色に対応するように定義されています。
この基準となる色相 hue1_offset に、マンデルブロー図形の計算から得られた、発散するまでの繰り返し量を上乗せすることで、各色を設定しています。
・ hue1_coef は、マンデルブロー図形を描画する際の色変化の係数です。hue1_coef = 1.0 とすると、発散するまでの繰り返し量の範囲を、色相の 0 ~ 360 度の範囲に対応させるよう、輝度値を設定します。
色の変化を小さくする場合は、hue1_coef = 1.0 → 0.0 のように、小さな値を設定してください。hue1_coef = 0 とすると、色の変化はゼロ(発散する/しないの2色のみ)となります。
色の変化を大きくする場合は、hue1_coef = 1.0 → 10.0 のように、大きな値を設定してみてください。カラフルに色が変化する表示になります。
・ saturation, brightness は、それぞれ、彩度、明度の設定値です。彩度や明度を下げる場合は、値を小さくしてください。
・ filename は、保存する際のファイル名です。ファイル名を変更する場合は、この欄を修正してください。

うまく動いたら

・ うまく動いたら、マンデルブロー図形の各場所をダブルクリック/右クリックして、各場所のデザインを探索してみてください。[hue …] ボタンで、色の調整も可能です。
・ 気に入ったデザインができたら、画素数を上げて画像を保存することで、壁紙などの作成が可能です。
たとえば、2K のモニターであれば、nx1 = 1920 pixels、ny1 = 1080 pixels と設定することで全画面用の壁紙を作成できます。

マンデルブロー図形についてのまとめ

・ マンデルブロー図形は、カージオイド(円の端部にマーキングをし、同一半径となる他の円の周りにすべらさずに転がしたときにマーキングが描く図形、ハート形の図形)に、バブルがついた形状を基本図形としています。
フラクタル図形となっており、拡大していくと、同じようなパターンが無数に現れます。
・ 計算の手順についてまとめると以下となります。
(1) 座標上の任意の1点 (x1, y1) を設定します。この値から、複素数 c1 = x1 + y1 * i を作ります。
(2) 複素数 z1 の初期値を z1 = 0 とします。
(3) 変換式 z1′ = z1^2 + c1 に、z1 と c1 の値を代入し、z1′ を求めます。
(z1^2、z1**2 は、いずれも、z1 の2乗の意味です。)
(4) z1′ を z1 に置き換えます。
(5) 繰り返し回数を n1 として、上記(3)~(4)の計算を繰り返します。
繰り返し計算の途中で、| z1 | の値が所定のしきい値( thr1、>=2)を超えたら発散するもの(マンデルブロー集合には属さない)と判断し、(繰り返し回数 n1 として)計算を打ち切ります。
計算を繰り返しても発散しない(しきい値を超えない)場合は、マンデルブロー集合に属すると判断します(上図の黒色)。
プログラムを作る場合は、無限回の繰り返し計算はできません。そこで、あらかじめ繰り返し回数の最大値 n1_max を設定しておき、繰り返し回数 n1 が n1_max を超えたら、マンデルブロー集合に属すると判断し、計算を終了します。
(6) 描画範囲となる平面上の各点 (x1, y1) について(1)~(5)を実行し、各点での繰り返し回数 n1 を求めます。繰り返し回数 n1 の値から、点 (x1, y1) での色を決定します。
※ 例として、(x1, y1) = (0, 0) (原点)では、z1′ = z1^2 + c1 の変換をいくら繰り返しても、z1′ = 0 のままです。すると、| z1 | の値は、しきい値 thr1 を超えることはないので、繰り返し回数 n1 は、プログラムで設定されている最大値 n1_max となります(最大回数繰り返しても、発散することがない)。
マンデルブロー図形の描画の際は、n1 ≒ n1_max となった場合、該当する画素の輝度値は RGB = (0, 0, 0) (黒)としています。
また、黒色以外での着色はすべて、発散すると判断された場所となります。
したがって、マンデルブロー図形としてよく知られているカラフルなパターンは、実は、マンデルブロー集合には属さない点の集合であるということになります。

サンプルスクリプトの説明

・ スクリプトの冒頭で、各パッケージをインポートしています。GUI の作成用に tkinter、画像の計算用に matplotlib、PIL を使用します。
・ init1()、set_size1() は、パラメータを初期化するための関数です。
・ hsv2rgb1() は、HSV の色空間座標を RGB の色空間座標に変換する関数です。
・ color1() は、マンデルブロー図形の各点での計算結果(繰り返し回数)を、カラーに変換する関数です。
・ mandelbrot0()、mandelbrot1() は、マンデルブロー図形を生成するための関数です。座標を与えると、複素数(c1 = x1 + y1 * 1j )を設定し、式 z1′ = z1*z1 + c1 への代入を繰り返すことで、発散するまでの繰り返し回数を求めます。この繰り返し回数を色相に割り当てることで、計算結果をカラー表示させています。
なお、Python のプログラミングでは、虚数 i は、1j のように記載することで、そのまま計算できます。関数 abs() を取ることで、絶対値を取得できます。
・ draw1() は描画のためのメインの関数です。GUI の画面上で [draw] ボタンをクリックすると実行します。
前述の mandelbrot1() 関数を実行して、計算結果を tkinter 上に配置された canvas1 に表示します。
・ move1_left()、move1_right()、move1_up()、move1_down() は、GUI の画面上で、左右上下ボタンをクリックしたときに実行される関数です。座標 x1_center, y1_center をシフトさせて、表示領域を動かせるようにしています。
・ 以下の関数も、GUI の画面上の各ボタンをクリックした際に実行される関数です。拡大、縮小などを実行します。
・ form1 = … となっている行以下で、tkinter を使って、GUI の画面を設定しています。
・ canvas1.bind() となっている3行で、マウスの移動、シングルクリック、ダブルクリックを検出し、実行する関数を設定しています。
・ なお、色相の計算は、下記の関連リンク「ブラウザで動くお絵描きアプリ 【JavaScript】」とほぼ同じです。リンク先のプログラムは JavaScript で書きましたが、今回は Python で書いています。Python で書くと、画像の保存などの自由度が広がるといったメリットがあるといえます。

まとめ

Python を使ってフラクタル図形を描画するスクリプトについてまとめました。

マンデルブロー集合は、以前、いくらか学んだのですが、どうやって着色するのかわかっていませんでした。Python で自力でプログラムを作ってみることでよく理解できましたので、スクリプトも含め、公開しておくことにします。
背景用の画像やアイコンなど何かデザインを作りたいとなったとき、マンデルブロー図形を流用することで手作業では作成が難しいパターンについても生成することが可能になりました。

他にも、各種の図形や tkinter を活用した事例を関連リンクなどにまとめています。もし、関心があるようでしたら、参照してみてください。

関連リンク
・ 円、矩形、直線を描画&ドラッグできるようにする【tkinter】
・ 標準的な座標平面とグラフを描画する 【Python】
・ 円周率を求めてみる 【Python】
・ ブラウザで動くお絵描きアプリ 【JavaScript】
・ 指定範囲を繰り返し再生する音楽プレーヤー【Python】

サンプルスクリプト mandelbrot1.py


import os 
import tkinter as tk1 
from matplotlib import pyplot as plt1 
from PIL import Image as im1 
from PIL import ImageTk as imtk1 

path1 = "" 

def init1(): 
    global path1 
    path1 = os.path.dirname(__file__) 

    textbox1.delete(0, tk1.END) 
    textbox1.insert(0, "-2.0") 
    textbox2.delete(0, tk1.END) 
    textbox2.insert(0, "0.0") 
    textbox3.delete(0, tk1.END) 
    textbox3.insert(0, "6.0") 
    textbox4.delete(0, tk1.END) 
#   textbox4.insert(0, "1920") 
#   textbox4.insert(0, "960") 
    textbox4.insert(0, "640") 
#   textbox4.insert(0, "480") 
#   textbox4.insert(0, "240") 
    textbox5.delete(0, tk1.END) 
#   textbox5.insert(0, "1080") 
#   textbox5.insert(0, "540") 
    textbox5.insert(0, "480") 
#   textbox5.insert(0, "270") 
#   textbox5.insert(0, "135") 
    textbox6.delete(0, tk1.END) 
    textbox6.insert(0, "220") 
    textbox7.delete(0, tk1.END) 
    textbox7.insert(0, "1.0") 
    textbox8.delete(0, tk1.END) 
    textbox8.insert(0, "100") 
    textbox9.delete(0, tk1.END) 
    textbox9.insert(0, "100") 
    textbox10.delete(0, tk1.END) 
    textbox10.insert(0, "im01.png") 
    return 

def set_size1(): 
    nx1       = int( textbox4.get() ) 
    ny1       = int( textbox5.get() ) 
    canvas1.place( width=nx1, height=ny1 ) 
    nx2 = nx1+340 
    ny2 = ny1+20 
    if nx2 < 600: 
        nx2 = 600 
    if ny2 < 400: 
        ny2 = 400 
    form1.geometry( str(nx2) + "x" + str(ny2) ) 
    return 

def hsv2rgb1( h0, s0, v0 ): 
    h0 = h0 % 360                              # mod 
    h1 = h0/60.0 
    s1 = s0/100.0 
    v0 = v0/100.0 
    h2 = h1 - int(h1) 
    v1 = v0 * ( 1.0 - s1 ) 
    v2 = v0 * ( 1.0 - s1 * h2 ) 
    v3 = v0 * ( 1.0 - s1 * ( 1.0 - h2 ) ) 
    rgb1 = [0, 0, 0] 
    if s1 == 0.0: 
        rgb1 = [v0, v0, v0] 
    elif h1 < 0.0: 
        rgb1 = [v0, v3, v1] 
    elif h1 < 1.0: 
        rgb1 = [v0, v3, v1] 
    elif h1 < 2.0: 
        rgb1 = [v2, v0, v1] 
    elif h1 < 3.0: 
        rgb1 = [v1, v0, v3] 
    elif h1 < 4.0: 
        rgb1 = [v1, v2, v0] 
    elif h1 < 5.0: 
        rgb1 = [v3, v1, v0] 
    else: 
        rgb1 = [v0, v1, v2] 
    rgb2 = [ int( 255.0 * rgb1[0] ), int( 255.0 * rgb1[1] ), int( 255.0 * rgb1[2] ) ] 
    return rgb2 

def color1( h1_offset, h1_coef, n1, n1_max, sat1, bri1 ): 
    if n1 > n1_max - 2:                        # not infinite 
        rgb1 = [0, 0, 0] 
    else: 
        h0 = n1/n1_max                         # h0 ~ 0: infinite       h1 ~ 1: not infinite 
        hue1 = 360.0*h0*h1_coef + h1_offset
        rgb1 = hsv2rgb1( hue1, sat1, bri1 )    # hue, saturation, brightness 
    return rgb1 

def mandelbrot0( x1_center, y1_center, width1, height1, nx1, ny1, n1_repeat, thr1): 
    x1_max =  x1_center + width1/2.0 
    x1_min =  x1_center - width1/2.0 
    y1_max =  y1_center + height1/2.0 
    y1_min =  y1_center - height1/2.0 
    a1 = [] 
    n1_max = -1 
    for i1 in range(ny1): 
        y1 = y1_min + (y1_max-y1_min)*i1/(ny1-1) 
        a2 = [] 
        for i2 in range(nx1): 
            x1 = x1_min + (x1_max-x1_min)*i2/(nx1-1) 
            c1 = x1 + y1*1j 
            z1 = 0.0 
            for i3 in range(n1_repeat): 
                z1 = z1 * z1 + c1 
                abs1 = abs( z1 ) 
                if abs1 > thr1:                # infinite 
                    if i3 > n1_max: 
                        n1_max = i3 
                    break 
            a2.append( i3+1 ) 
        a1.append( a2 ) 
    return a1, n1_max+1

def mandelbrot1(): 
    x1_center = float( textbox1.get() ) 
    y1_center = float( textbox2.get() ) 
    width1    = float( textbox3.get() ) 
    nx1       = int(   textbox4.get() ) 
    ny1       = int(   textbox5.get() ) 
    h1_offset = float( textbox6.get() ) 
    h1_coef   = float( textbox7.get() ) 
    sat1      = float( textbox8.get() ) 
    bri1      = float( textbox9.get() ) 
    height1   = float( width1 * ny1/nx1 ) 
    n1 = 100                                   # number of repeats 
    thr1 = 100.0                               # threshold, > 2.0 
    img1, n1_max = mandelbrot0( x1_center, y1_center, width1, height1, nx1, ny1, n1, thr1) 
    img2 = [] 
    img3 = im1.new( "RGB", (nx1, ny1), (255, 255, 255) ) 
    for i1 in range( ny1 ): 
        a1 = [] 
        for i2 in range( nx1 ): 
            n2 = img1[i1][i2] 
            rgb1 = color1( h1_offset, h1_coef, n2, n1_max, sat1, bri1 ) 
            img3.putpixel( ( i2, i1 ), tuple( rgb1 ) ) 
            a1.append( rgb1 ) 
        img2.append( a1 ) 
    return img1, img2, img3, [nx1, ny1] 

def rgb2hex1( a1 ): 
    r1 = hex( a1[0] )[2:].zfill(2) 
    g1 = hex( a1[1] )[2:].zfill(2) 
    b1 = hex( a1[2] )[2:].zfill(2) 
    return "#" + r1 + g1 + b1 

img1 = "" 
img2 = "" 
img3 = "" 
def draw1(): 
    set_size1() 
    global img1 
    global img2 
    global img3 
    img1, img2, img3, nxy1 = mandelbrot1() 
    img4 = imtk1.PhotoImage( img3 ) 
    canvas1.photo = img4 
    canvas1.create_image( int(nxy1[0]/2), int(nxy1[1]/2), image=img4 ) 

#   img2.show() 

#   plt1.imshow( img2 ) 
#   plt1.axis("off") 
#   plt1.show() 

    return 

def move1_left(): 
    x1_center = float( textbox1.get() ) 
    diff1     = float( textbox3.get() ) * 0.1 
    str1 = str( x1_center - diff1 ) 
    textbox1.delete(0, tk1.END) 
    textbox1.insert(0, str1) 
    if chkv1.get(): 
        draw1() 
    return 

def move1_right(): 
    x1_center = float( textbox1.get() ) 
    diff1     = float( textbox3.get() ) * 0.1 
    str1 = str( x1_center + diff1 ) 
    textbox1.delete(0, tk1.END) 
    textbox1.insert(0, str1) 
    if chkv1.get(): 
        draw1() 
    return 

def move1_up(): 
    y1_center = float( textbox2.get() ) 
    diff1     = float( textbox3.get() ) * 0.1 
    str1 = str( y1_center - diff1 ) 
    textbox2.delete(0, tk1.END) 
    textbox2.insert(0, str1) 
    if chkv1.get(): 
        draw1() 
    return 

def move1_down(): 
    y1_center = float( textbox2.get() ) 
    diff1     = float( textbox3.get() ) * 0.1 
    str1 = str( y1_center + diff1 ) 
    textbox2.delete(0, tk1.END) 
    textbox2.insert(0, str1) 
    if chkv1.get(): 
        draw1() 
    return 

def move1_zoom_in(): 
    range1 = str( float( textbox3.get() ) * 0.5 ) 
    textbox3.delete(0, tk1.END) 
    textbox3.insert(0, range1) 
    if chkv1.get(): 
        draw1() 
    return 

def move1_zoom_out(): 
    range1 = str( float( textbox3.get() ) / 0.5 ) 
    textbox3.delete(0, tk1.END) 
    textbox3.insert(0, range1) 
    if chkv1.get(): 
        draw1() 
    return 

def hue1_plus(): 
    hue1 = float( textbox6.get() )+30.0 
    if hue1 > 360.0: 
        hue1 = hue1 - 360.0 
    textbox6.delete(0, tk1.END) 
    textbox6.insert(0, str(hue1)) 
    if chkv1.get(): 
        draw1() 
    return 

def hue1_minus(): 
    hue1 = float( textbox6.get() )-30.0 
    if hue1 < 0.0: 
        hue1 = hue1 + 360.0 
    textbox6.delete(0, tk1.END) 
    textbox6.insert(0, str(hue1)) 
    if chkv1.get(): 
        draw1() 
    return 

def set_deafult1(): 
    init1() 
    set_size1() 
    if chkv1.get(): 
        draw1() 
    return 

def mouse_coordinates1( event1 ): 
    x1_center = float( textbox1.get() ) 
    y1_center = float( textbox2.get() ) 
    range1    = float( textbox3.get() ) 
    nx1 = float( textbox4.get() ) 
    ny1 = float( textbox5.get() ) 
    str1 = "" 
    nx2 = event1.x 
    ny2 = event1.y 
    x2_center = x1_center + float(nx2-nx1/2)*range1/nx1 
    y2_center = y1_center + float(ny2-ny1/2)*range1/nx1 
    return x2_center, y2_center 

def mouse_move1( event1 ): 
    global img2 
    str1 = "" 
    if len(img2) > 1: 
        i1 = event1.x 
        i2 = event1.y 
        rgb1 = img2[i2][i1] 
        x1_center, y1_center = mouse_coordinates1( event1 ) 
        str1 = "{:.5f}".format( x1_center ) + " " + "{:.5f}".format( y1_center ) + " " + str( rgb1 ) 
    label11["text"] = str1 
    return 

def mouse_single_click1( event1 ): 
    x1_center, y1_center = mouse_coordinates1( event1 ) 
    str1 = str( x1_center ) + " " + str( y1_center ) 
    textbox1.delete(0, tk1.END) 
    textbox1.insert(0, str( x1_center )) 
    textbox2.delete(0, tk1.END) 
    textbox2.insert(0, str( y1_center )) 
    if chkv1.get(): 
        draw1() 
    return 

def mouse_double_click1( event1 ): 
    x1_center, y1_center = mouse_coordinates1( event1 ) 
    str1 = str( x1_center ) + " " + str( y1_center ) 
    textbox1.delete(0, tk1.END) 
    textbox1.insert(0, str( x1_center )) 
    textbox2.delete(0, tk1.END) 
    textbox2.insert(0, str( y1_center )) 
    move1_zoom_in() 
    return 

def save1(): 
    global img3 
    file1 = textbox10.get().strip() 
    if file1 != "" and img3 != "": 
        file2 = path1 + "\\" + file1 
        img3.save( file2 ) 
    return 

form1 = tk1.Tk() 
form1.title("mandelbrot v0.1") 
form1.geometry( "1300x560+50+50" ) 

label1 = tk1.Label(text="x1_center") 
label1.place(x=10, y=  5) 
label2 = tk1.Label(text="y1_center") 
label2.place(x=10, y= 35) 
label3 = tk1.Label(text="width w1 ") 
label3.place(x=10, y= 65) 
label4 = tk1.Label(text="nx1, pix") 
label4.place(x=10, y= 95) 
label5 = tk1.Label(text="ny1, pix") 
label5.place(x=10, y=125) 
label6 = tk1.Label(text="hue1_offset, deg") 
label6.place(x=10, y=155) 
label7 = tk1.Label(text="hue1_coef") 
label7.place(x=10, y=185) 
label8 = tk1.Label(text="saturation, %") 
label8.place(x=10, y=215) 
label9 = tk1.Label(text="brightness, %") 
label9.place(x=10, y=245) 
label10 = tk1.Label(text="filename") 
label10.place(x=10, y=275) 
label11 = tk1.Label(text="-") 
label11.place(x=10, y=305) 

textbox1 = tk1.Entry(master=form1) 
textbox1.place(x=110, y=  5, width=60) 
textbox2 = tk1.Entry(master=form1) 
textbox2.place(x=110, y= 35, width=60) 
textbox3 = tk1.Entry(master=form1) 
textbox3.place(x=110, y= 65, width=60) 
textbox4 = tk1.Entry(master=form1) 
textbox4.place(x=110, y= 95, width=60) 
textbox5 = tk1.Entry(master=form1) 
textbox5.place(x=110, y=125, width=60) 
textbox6 = tk1.Entry(master=form1) 
textbox6.place(x=110, y=155, width=60) 
textbox7 = tk1.Entry(master=form1) 
textbox7.place(x=110, y=185, width=60) 
textbox8 = tk1.Entry(master=form1) 
textbox8.place(x=110, y=215, width=60) 
textbox9 = tk1.Entry(master=form1) 
textbox9.place(x=110, y=245, width=60) 
textbox10 = tk1.Entry(master=form1) 
textbox10.place(x=110, y=275, width=60) 

btn1 = tk1.Button(form1, text='draw',         command=draw1,  bg='#c0c0ff' )
btn1.place(x=180, y=  5, width=100)
btn2 = tk1.Button(form1, text='left',         command=move1_left     )
btn2.place(x=180, y= 65, width= 50)
btn3 = tk1.Button(form1, text='right',        command=move1_right    )
btn3.place(x=230, y= 65, width= 50)
btn4 = tk1.Button(form1, text='up',           command=move1_up       )
btn4.place(x=180, y= 35, width=100)
btn5 = tk1.Button(form1, text='down',         command=move1_down     )
btn5.place(x=180, y= 95, width=100)
btn6 = tk1.Button(form1, text='zoom_in',      command=move1_zoom_in  )
btn6.place(x=180, y=155, width=100)
btn7 = tk1.Button(form1, text='zoom_out',     command=move1_zoom_out )
btn7.place(x=180, y=185, width=100)

btn8 = tk1.Button(form1, text='hue +30 deg',  command=hue1_plus      )
btn8.place(x=180, y=215, width=100)
btn9 = tk1.Button(form1, text='hue -30 deg',  command=hue1_minus     )
btn9.place(x=180, y=245, width=100)

btn10 = tk1.Button(form1, text='save',        command=save1          )
btn10.place(x=180, y=275, width=100)

btn11 = tk1.Button(form1, text='set default', command=set_deafult1   )
btn11.place(x=180, y=305, width=100)

chkv1 = tk1.BooleanVar() 
chk1 = tk1.Checkbutton( form1, text="redraw", variable=chkv1 ) 
chk1.place( x=180, y=335, width=60 ) 
chk1.select() 

canvas1 = tk1.Canvas(master=form1, bg="white") 
canvas1.place( x=300, y=5, width=960, height=540 ) 

canvas1.bind('<Motion>', mouse_move1 ) 
canvas1.bind('<Button-3>', mouse_single_click1 ) 
canvas1.bind('<Double-1>', mouse_double_click1 ) 

init1() 
set_size1()

form1.mainloop() 


 

タイトルとURLをコピーしました