2020年07月26日

Python 3 で, Ogg Vorbis と Wave を再生する Player を書きました 続き

pysoundsample.png

前回 の続きです. 上の画像は, sample の gui です.

Ogg Vorbis ファイルと, Wave ファイルを複数同時に再生できるプレイヤーです. MIT License です. 使用方法は, zip 内の readme.txt と, sample.py に書いてあります. 下にあるコードも, zip 内に全て入っています.

マルチスレッドによるエラーを対策したり, wave の再生終了まで待機できるようにしたりしました. 他の変更点はコード冒頭 update.txt に書いてあります.


'''
thread2.py  v1.1

参考ページ: Python スレッドの停止と再開の簡易サンプル
https://qiita.com/BlueSilverCat/items/44a0a2a3c45fc3e88b19
'''

from threading import Thread, Event

class Thread2(Thread):

    def __init__(self, daemon = True, callback = 0):
        super().__init__(daemon = daemon)
        self.started = Event()
        self.alive = 1
        self.active = 1
        self.callback = callback
        self.start()

    def __del__(self):
        self.kill()

    def begin(self):
        self.started.set()
        self.active = 1

    def end(self):
        self.active = 0
        self.started.clear()
        if callable(self.callback):
            self.callback()

    def kill(self):
        self.started.set()
        self.active = 0
        self.alive = 0
        self.join()




'''
soundthread.py  v1.2
'''

from threading import Lock

from pyaudio import PyAudio

from .thread2 import Thread2

class SoundThread(Thread2):

    __lock = Lock()

    def __init__(self, callback):
        super().__init__(callback = callback)

    def close(self):
        self.stream.stop_stream()
        self.stream.close()
        self.p.terminate()

    def kill(self):
        self.close()
        self.end()
        super().kill()

    def open(self, format, channels, rate):
        SoundThread.__lock.acquire()
        self.p = PyAudio()  # 使い回すとエラーが出ることがある
        self.stream = self.p.open(format = format,
                                  channels = channels,
                                  rate = rate,
                                  output = True)
        SoundThread.__lock.release()

    def run(self):
        while self.active:
            self.play()  # Sub Class で実装すること
            self.started.wait()




'''
player.py  v1.0
'''

class Player:

    def __init__(self, enabled):
        self.__enabled = enabled  # False で関数呼び出しを無視する

    def is_enabled(self):
        return self.__enabled

    def on(self):
        if self.__enabled:
            return
        self.__enabled = 1

    def off(self):
        if not self.__enabled:
            return
        self.__enabled = 0




'''
vorbisplayer.py  v1.3

Copyright (c) 2020 Takenoko (http://nekokiss.seesaa.net/)
Released under the MIT license.
see https://opensource.org/licenses/MIT

PyAudio, PyOgg, audio-metadata が install されている必要があります.
'''

import time
from threading import Event

import pyogg as po
import pyaudio as pa

from .soundthread import SoundThread
from .player import Player

class Vorbis:

    def __init__(self, ogg, chunk, loop, tagloop):
        self.ogg = ogg
        self.loop = loop
        self.file = po.VorbisFile(ogg)
        '''
        bit rate size
        1, 3, 4 等の場合もあるかもしれないが,
        取得方法がわからないので 2 で固定
        '''
        self.sampwidth = 2
        # block size
        self.block = (self.sampwidth
                      * self.file.channels)
        self.format = pa.get_format_from_width(self.sampwidth)
        self.cache = {}
        '''
        Loop Tag
        '''
        self.loopstart = 0
        self.loopend = (self.file.buffer_length
                        * self.block)
        if loop and tagloop:
            import audio_metadata as am
            md = am.load(ogg)
            if 'tags' in md and 'loopstart' in md.tags:
                self.loopstart = int(md.tags.loopstart[0]) * self.block
                if 'looplength' in md.tags:
                    self.loopend = (int(md.tags.looplength[0])
                                    * self.block + self.loopstart)
        self.chunk = chunk
        if self.loopend - self.loopstart < self.chunk:
            self.chunk = self.loopend - self.loopstart

    def getdata(self, start):
        if start not in self.cache:
            end = start + self.chunk
            if end > self.loopend:
                data = self.file.buffer[start:self.loopend]
                if self.loop:
                    end = self.loopstart + end - self.loopend
                    data += self.file.buffer[self.loopstart:end]
                else:
                    end = -1
                self.cache[start] = data, end
            else:
                self.cache[start] = self.file.buffer[start:end], end
        return self.cache[start]


class VorbisThread(SoundThread):

    def __init__(self, vorbis, callback):
        self.vorbis = vorbis
        self.paused = Event()
        super().__init__(callback)

    def rebegin(self):
        self.paused.set()
        if self.active:
            self.end()
            # sleep しないと曲の先頭に戻らないことがある
            time.sleep(0.1)
        self.begin()

    def play(self):
        self.paused.set()
        self.open(self.vorbis.format, self.vorbis.file.channels,
                  self.vorbis.file.frequency)
        start = 0
        while self.active:
            data, start = self.vorbis.getdata(start) 
            self.stream.write(data)
            self.paused.wait()
            if start < 0:
                self.end()
        self.close()


class VorbisPlayer(Player):

    def __init__(self, chunk = 1024, loop = 1, tagloop = 1,
                 enabled = 1):
        super().__init__(enabled)
        self.__chunk = chunk
        self.__vorbises = {}
        self.__thread = 0
        self.__loop = loop        # True で loop する
        self.__tagloop = tagloop  # True で LOOPSTART & LOOPLENGTH を使う

    def off(self):
        super().off()
        self.stop()

    def play(self, ogg, callback = 0):
        if not self.is_enabled():
            return
        if ogg in self.__vorbises:
            v = self.__vorbises[ogg]
        else:
            v = Vorbis(ogg, self.__chunk, self.__loop, self.__tagloop)
            self.__vorbises[ogg] = v
        if self.__thread:
            self.__thread.vorbis = v
            self.__thread.callback = 0
            self.__thread.rebegin()
            self.__thread.callback = callback
        else:
            self.__thread = VorbisThread(v, callback)

    def stop(self):
        if self.__thread and self.__thread.active:
            self.__thread.end()

    def pause(self):
        if not self.is_enabled():
            return
        if self.__thread:
            self.__thread.paused.clear()

    def resume(self):
        if not self.is_enabled():
            return
        if self.__thread:
            self.__thread.paused.set()




'''
waveplayer.py  v1.4

Copyright (c) 2020 Takenoko (http://nekokiss.seesaa.net/)
Released under the MIT license.
see https://opensource.org/licenses/MIT

PyAudio が install されている必要があります.
'''

from threading import Event

import pyaudio as pa
import wave

from .soundthread import SoundThread
from .player import Player

class Wave:

    def __init__(self, wav, chunk):
        self.file = wav
        with wave.open(wav, 'rb') as wf:
            self.format = pa.get_format_from_width(wf.getsampwidth())
            self.channels = wf.getnchannels()
            self.rate = wf.getframerate()
            self.buffer = []
            while 1:
                data = wf.readframes(chunk)
                if len(data) <= 0:
                    break
                self.buffer.append(data)


class WavThread(SoundThread):

    def __init__(self, wp, wav, callback):
        self.wp = wp
        self.wav = wav
        super().__init__(callback)

    def close(self):
        super().close()
        self.wp._WavePlayer__blocked.set()

    def play(self):
        self.open(self.wav.format, self.wav.channels,
                  self.wav.rate)
        for data in self.wav.buffer:
            if self.active:
                self.stream.write(data)
        if self.active:
            self.end()
        self.close()


class WavePlayer(Player):

    def __init__(self, chunk = 1024, maxthreads = 8, enabled = 1):
        super().__init__(enabled)
        self.__chunk = chunk
        self.__waves = {}
        self.__threads = []
        self.__blocked = Event()
        if maxthreads < 1:
            maxthreads = 1
        self.__maxthreads = maxthreads  # 最大同時再生 Thread 数

    def __getwav(self, wav):
        if wav not in self.__waves:
            self.__waves[wav] = Wave(wav, self.__chunk)
        return self.__waves[wav]

    def off(self):
        super().off()
        self.stopall()

    def getmaxthreads(self):
        return self.__maxthreads

    def setmaxthreads(self, v):
        if v < 1:
            return
        over = min(self.__maxthreads, len(self.__threads)) - v
        if over > 0:
            for i in range(over):
                t = self.__threads.pop(0)
                if t.active:
                    t.end()
                self.__threads.append(t)
        self.__maxthreads = v

    def play(self, wav, block = 0, callback = 0):
        if not self.is_enabled():
            return
        if block:
            self.__blocked.clear()
        for i, t in enumerate(self.__threads):
            if i < self.__maxthreads:
                if not t.active:
                    t.wav = self.__getwav(wav)
                    t.callback = callback
                    t.begin()
                    break
        else:
            if len(self.__threads) >= self.__maxthreads:
                t = self.__threads.pop(0)
                t.end()
                t.wav = self.__getwav(wav)
                t.callback = callback
                t.begin()
            else:
                t = WavThread(self, self.__getwav(wav), callback)
            self.__threads.append(t)
        if block:
            self.__blocked.wait()

    def stop(wav):
        for t in self.__threads:
            if t.wav.file == wav and t.active:
                t.end()
                return 1
        return 0

    def stopall(self):
        for t in self.__threads:
            if t.active:
                t.end()



vwp200727.zip

スレッドについて, 少しだけわかった気がします.

20/07/27 追記

ファイルを差し替えました. 更新履歴を, ソースコードではなく update.txt にまとめただけですが. あと, この記事にコードを貼り付けました. コードに問題があった場合, 指摘して頂けるとありがたいです.

20/07/28 追記

説明文を追加.

ラベル:Python download
posted by Takenoko at 09:42| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2020年07月09日

Python 3 で, Ogg Vorbis と Wave を再生する Player を書きました

タイトルの通りです. ゲーム制作で必要だったので書きました. ゲームでよく使われるのは .ogg (Ogg Vorbis) と .wav だと思うので, それらを再生できます. ogg は, LOOPSTART, LOOPLENGTH に対応しています.

PyAudio, PyOgg, audio-metadata を使用しているので, それらの install が必要です.

vorbisplayer.py で import している audio-metadata が, Python 3.6 以降を要求するので, それ以降の Python で動きます. waveplayer.py だけを使うのであれば, それ以下でも動くはずです.

ソースファイル (vwp1.1.zip) のダウンロード

zip 内の readme.txt, sample.py を読むと, 使い方がわかると思います.

Linux Mint 18.3 & Python 3.6.11, Windows 8.1 & Python 3.6.8 で動作しました. Mac は持っていないのでわかりません.

何か間違い等があった場合, 指摘していただけるとありがたいです.

20/07/12 追記

ファイルを Version 1.1 に差し替えました.
vorbisplayer に, pause と resume を実装する等の変更を行いました.

20/07/26 追記

続き を書きました. ファイルも次の記事にあります.

ラベル:Python download
posted by Takenoko at 20:52| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年12月17日

Kivy アプリの Windows 用実行ファイルを作成するまで (ライセンス編)

nuitka で kivy 製アプリの実行ファイルを作製した際, *.dist ディレクトリに自動的に生成される dll, 及び, Python*\share\glew\bin\, Python*\share\sdl2\bin\ 両ディレクトリに存在する dll のライセンスについてのメモです. 正確でない可能性は大いにあります. 正直, わからないことが多いので, 間違い等を指摘していただけるとありがたいです.

  • comctl32.dll
    役割: Windows のコモンコントロールを呼び出すための dll ?
    ライセンス: 不明. Visual C++ 6.0 再頒布可能パッケージに含まれているので, 同梱しても問題ない?
    参考:
    https://www.ipentec.com/document/visual-studio-c-plus-plus-redistribution-files
    http://chokuto.ifdef.jp/urawaza/comctl.html

  • libcrypto-1_1.dll, libssl-1_1.dll
    役割: OpenSSL "インターネットでの暗号化通信に使われるオープンソースのプログラムやソフトウェアのこと。"
    ライセンス: OpenSSL License
    引用: https://www.kddi.com/yogo/セキュリティ/OpenSSL.html
    参考: https://ja.wikipedia.org/wiki/OpenSSL
    https://www.atmarkit.co.jp/ait/articles/0906/26/news129_2.html

  • python37.dll
    役割: Python 3.7 を利用するための dll ?
    ライセンス: Python Software Foundation License
    参考:
    https://ja.wikipedia.org/wiki/Python_Software_Foundation_License
    https://docs.python.org/ja/3/faq/general.html

  • pywintypes37.dll
    ライセンス: python37.dll と同じ?

  • sqlite3.dll
    役割: "SQLite(エスキューライト、エスキューエライト)は、パブリックドメインの軽量な関係データベース管理システム (RDBMS) である。"
    ライセンス: public domain
    引用: https://ja.wikipedia.org/wiki/SQLite

  • tcl86t.dll, tk86t.dll
    役割: おそらく, tcl/tk を使用するための dll
    ライセンス: BSDライセンス ?

  • vcruntime140.dll
    役割: C で作製された exe を起動するのに必要な dll ?
    ライセンス: 不明. Visual Studio 2015 の Visual C++ 再頒布可能パッケージに含まれているので, 同梱しても問題ない?
    参考: https://www.ipentec.com/document/visual-studio-c-plus-plus-redistribution-files

  • glew32.dll
    役割: OpenGL Extension Wrangler Library
    ライセンス: Modified BSD License, MIT License

  • SDL2.dll, SDL2_image.dll, SDL2_mixer.dll, SDL2_ttf.dll
    ライセンス: zlib License

  • libFLAC-8.dll
    役割: "FLAC(フラック、Free Lossless Audio Codec)は、オープンフォーマットの可逆圧縮音声ファイルフォーマットである。"
    ライセンス: 修正BSDライセンス・三条項BSDライセンス
    引用: https://ja.wikipedia.org/wiki/FLAC

  • libfreetype-6.dll
    役割: "FreeType(フリータイプ)は、フォントエンジンを実装したライブラリである。"
    ライセンス: The FreeType Project LICENSE
    引用: https://ja.wikipedia.org/wiki/FreeType
    参考: http://giraffydev.hatenablog.com/entry/2016/09/27/101841

  • libjpeg-9.dll
    役割: "libjpegは、JPEGのエンコード、デコードを行うためのライブラリである。JPEGファイルを操作するためのユーティリティも含んでいる。"
    ライセンス: フリー、ロイヤリティ無しで商用利用可、表示が必要。"this software is based in part on the work of the Independent JPEG Group" と表記すればよい?
    引用: https://ja.wikipedia.org/wiki/Libjpeg
    参考: https://qa.itmedia.co.jp/qa5192199.html

  • libmodplug-1.dll
    役割: "ModPlug Tracker(モッドプラグトラッカー)は、Windows上で Olivier Lapicque によって開発されたオーディオモジュールトラッカーである。"
    ライセンス: public domain

  • libmpg123-0.dll
    役割: mpg123 "mpg123 is a free and open-source audio player. It supports MPEG audio formats, including MP3."
    ライセンス: LGPL 2.1
    引用: https://en.wikipedia.org/wiki/Mpg123

  • libogg-0.dll
    ライセンス: 修正BSDライセンス・三条項BSDライセンス

  • libopus-0.dll
    ライセンス: 修正BSDライセンス・三条項BSDライセンス

  • libopusfile-0.dll
    ライセンス: 修正BSDライセンス・三条項BSDライセンス

  • libtiff-5.dll
    ライセンス: libtiff Software License

  • libwebp-7.dll
    ライセンス: 修正BSDライセンス・三条項BSDライセンス

  • libvorbis-0.dll
    ライセンス: 修正BSDライセンス・三条項BSDライセンス

  • libvorbisfile-3.dll
    ライセンス: 不明. libvorbis-0.dll と同じだろうか

  • zlib1.dll
    ライセンス: zlib License

気をつける必要がある dll は, LGPL 2.1 ライセンスの libmpg123-0.dll 位でしょうか. このファイルは (おそらく, 動画を扱わなければ) 無くても動くので, nuitka で生成したファイル群を, ソースファイルを公開せずに頒布しても問題なさそうに思えます.

ラベル:Windows nuitka kivy Python
posted by Takenoko at 11:16| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年11月19日

Kivy アプリの Windows 用実行ファイルを作成するまで (作製編)

1. PyInstaller を使用する場合

main.py

main.kv

上記の main.py, main.kv を例に説明します. 適当なディレクトリにこれらのファイルを作製します.

コマンドプロンプトを管理者として開き, main.py ファイルのあるディレクトリに移動し,

python -m PyInstaller --noconsole main.py

を入力します.

main.py のあるディレクトリに生成された main.spec を開き,

# -*- mode: python ; coding: utf-8 -*-

の次の行に,

from kivy_deps import sdl2, glew

を追加し, ('.' ではなく, '_' なので注意*1)

a.datas,

の次の行に,

*[Tree(p) for p in (sdl2.dep_bins + glew.dep_bins)],

を追加します. インデントは揃えます.

datas=[],

datas=[('main.kv', '.')],

にします. kv ファイルを使わない場合は, 必要ないはずです.

python -m PyInstaller main.spec

と入力し,

WARNING: The output directory "(main.py のあるディレクトリ)\dist\main" and ALL ITS CONTENTS wil l be REMOVED! Continue? (y/N)

と出たら y を入力します.

dist/main

に main.exe が作製されているので, 実行して画面が表示されたら成功です.

2. Nuitka を使用する場合

main.py

上記の main.py (main.kv は PyInstaller の項と同じもの) を例に説明します. 適当なディレクトリにこれらのファイルを作製します.

コマンドプロンプトを管理者として開き, main.py ファイルのあるディレクトリに移動し,

python -m nuitka --standalone --windows-disable-console --mingw64 --jobs=1 main.py

と入力します. jobs は, CPU コア数 * 2 にするといいのかもしれません. この作業は時間がかかります. 終了後, main.dist/ に main.exe が作製されます.

Python37-32\Lib\site-packages\kivy\

から data フォルダを main.dist/kivy にコピーし,

Python37-32\share\glew\bin\

から glew32.dll を,

Python37-32\share\sdl2\bin\

から全てのファイルを main.dist にコピーします. *2 最後に, main.kv を main.dist にコピーします.

main.exe を実行して画面が表示されたら成功です.

3. サンプル

以前, Python で迷路生成 で書いた kivy のコードを PyInstaller, Nuitka の両方で exe 化してみました.

PyInstaller

Nuitka

自分の環境では動作する, しないといった報告をしていただけると喜びます. 少なくとも, Linux Mint 18.3 の Wine では動きませんでした.

*1

Create a package for Windows(翻訳済み) − Kivy 1.10.0 ドキュメント:

では kivy.deps になっている. 以前はそうだったのかもしれない.

*2

作製環境でこのサンプルを動かした場合,

  • libmpg123-0.dll
  • libcrypto-1_1.dll
  • libssl-1_1.dll
  • libvorbis-0.dll
  • libvorbisfile-3.dll
  • libwebp-7.dll
  • libtiff-5.dll
  • libopus-0.dll
  • libopusfile-0.dll
  • libmodplug-1.dll
  • libFLAC-8.dll
  • libogg-0.dll
  • tcl86t.dll
  • tk86t.dll
  • sqlite3.dll
は無くても動きました.

参考ページ

Create a package for Windows(翻訳済み) − Kivy 1.10.0 ドキュメント:
KivyのGUIアプリをNuitkaで簡単に小サイズ・高速に動く実行ファイル(exe)にする(Windows10)
Packaging Kivy apps written in Python 3, targeting Windows using Nuitka

19/12/17 追記: 無くても動く dll を列挙した.

posted by Takenoko at 13:40| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

Kivy アプリの Windows 用実行ファイルを作成するまで (準備編)

windows 8.1 Home 64bit で, Python がインストールされていない windows でも 実行できる Kivy アプリの exe を作製するまでの過程です.

長くなったので, Python, gcc 等をインストールする準備編, PyInstaller or Nuitka を使用する作製編に分割しました. 後日, ライセンス編も書く予定です.

私の場合, 作成したファイルをネットで公開するつもりなので, Python や gcc 等は 32bit を選択しています. ファイルのバージョンは, メモを書いていた時点での最新を選んでいます.

1. mingw-w64 32bit インストール

http://mingw-w64.org/doku.php/download/mingw-builds

で, Installation: Sourceforge をクリックするとページ遷移し, インストーラが自動的にダウンロードされます.

mingw-w64-install.exe

を実行し,

Ver 8.10
i686
posix
sjlj
0

を選択します.

デフォルトのインストールパスが長いので,

C:\mingw-w64\i686-8.1.0-posix-sjlj-rt_v6-rev0

に変更します.

環境変数の Path に

C:\mingw-w64\i686-8.1.0-posix-sjlj-rt_v6-rev0\mingw32\bin\

を追加します.

コマンドプロンプトを開き,

gcc -v

と入力し, いろいろと情報が出てきたら成功です.

2. Python3 32bit をインストール

https://www.python.org/downloads/windows/

から, Stable Releases の, Nuitka が対応している最新バージョン (現時点では 3.7.5) の Download Windows x86 executable installer をクリックしてインストーラをダウンロードします.

python-3.7.5.exe

を実行します.

Add Python 3.7 to PATH にチェックを入れ, Install Now をクリックします. Path は自動的に追加されるようです.

3. Kivy をインストール

コマンドプロンプトを管理者として開き, 以下の, '#' でコメントアウトしていない行を順に入力します.

python -m pip install --upgrade pip wheel setuptools
python -m pip install docutils pygments pypiwin32 kivy.deps.sdl2 kivy.deps.glew
#python -m pip install kivy.deps.gstreamer
#python -m pip install kivy.deps.angle
python -m pip install kivy

インストールが終わったら,

pip list

と入力し, Kivy がインストールされていることを確認します.

*コメントアウトした行について

#python -m pip install kivy.deps.gstreamer

Kivyを使い始める

には, "Kivyには既にオーディオとビデオのプロバイダがありますが、より高度なものにはGStreamerが必要です。" と書いてあります. また, 動画プレイヤーも入っているらしいです. 私には必要なさそうなので入れませんでした.

#python -m pip install kivy.deps.angle

Kivy Windows Hello Worldへの道 真っ黒画面

には, "OpenGl ESのDirectX実装" と書いてあります. 必要かどうかわからないので, 必要になった時点で入れれば良いのだろうと思います.

4. Kivy のエラー対策

Windows で kv ファイルを読み込む際にエラーが出るようなので,

C:\Users\ユーザー名\AppData\Local\Programs\Python\Python37-32\Lib\site-packages\kivy\lang\

の (環境やバージョンによって場所は違うはず) builder.py を変更します.

if __debug__:
trace('Lang: load file %s' % filename)
with open(filename, 'r') as fd:
kwargs['filename'] = filename
data = fd.read()

with open(filename, 'r') as fd:

with open(filename, 'r', encoding='utf8') as fd:

に書き換えます.

5. PyInstaller をインストール (使用する場合)

python -m pip install pyinstaller

と入力し, 終了後,

pip list

と入力し, インストールされていることを確認します.

6. Nuitka をインストール (使用する場合)

python -m pip install nuitka

と入力し, 終了後,

pip list

と入力し, インストールされていることを確認します.

作製編 へ続きます.

posted by Takenoko at 12:48| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年04月15日

kivy 一行TextInput の高さを font_size から計算して設定する

タイトルの通りです.



これで, 文字列が Left, Middle に表示されるはずです.
ラベル:Python kivy
posted by Takenoko at 15:27| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年04月12日

kivy ListView のアイテムが選択された時の処理を追加 続き


listadapter2.py


main.py


main.kv


ListAdapter を継承したクラス, ListAdapter2 を別ファイルに記述し, 引数を関数にして, 使い回せるようにしました. いいクラス名が浮かばなかった. SelectableListAdapter にしようかと思ったけど, 元々選択はできるわけだし. callback という単語はよく見るけど, 意味はよくわかっていません. こういう使い方でいいんだろうか.
ラベル:Python kivy
posted by Takenoko at 14:17| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年04月09日

kivy ListView のアイテムが選択された時の処理を追加

タイトルの通りです. アイテムの選択状態を Label に反映するサンプルです.

main.py


main.kv


19/04/12 追記: 続きを書きました.
ラベル:Python kivy
posted by Takenoko at 14:59| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年03月27日

kivy クラスルールと継承

クラスルールは, それを継承するクラスにも適用される.



この場合, Label を継承している Button の font_size も 24 になってしまう. ルールは上から順に適用され, 競合する場合は下のルールで上書きされるため, Label と Button の順序を逆にすれば問題ない. 当たり前の事かもしれないが, このことに気づかず, しばらく悩んだので.

19/04/02 追記: タイトル変更, 文章を少し修正.
ラベル:kivy
posted by Takenoko at 14:57| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

2019年03月26日

python で迷路生成

maze256_2.png
毎回, 始点をランダムに選択した場合

0_2.png
可能な限り, 伸ばした先の点を次の始点にする

maze128_2.png
ランダム

以前に java で書いた迷路生成するコード を, 伸ばす度に始点を変更するかどうかの判定を追加し,  python に移植してみました. gui は kivy です. ソースファイル . linux と android(kivy launcher) で動作を確認しています. main.py が gui, test.py が cui です. test.py は kivy を使っておらず, python のみです.

kivy での画像生成やアニメーションの方法を覚えるために作ったので, 迷路の生成は重要ではないんですが, python2 と 3 で, 生成にかかる時間が数倍から十倍程度違うのが気になります. python2 の方が非常に遅い. 3 より 2 のが速いらしいんですが.

19/03/27 追記 : ソースファイルを差し替え. ループのネストを一つ減らしてみたり, 配列シャッフル用の配列を使いまわしたりしてみたが, 変わらず. python2 のサポート期限は 2020 年らしいので, まあいいか...
19/04/12 追記: ファイル名追加. 画像差し替え.

mazegenerator.py

xorshift128.py
ラベル:Python kivy 迷路
posted by Takenoko at 14:17| Comment(0) | programming | このブログの読者になる | 更新情報をチェックする

広告


この広告は60日以上更新がないブログに表示がされております。

以下のいずれかの方法で非表示にすることが可能です。

・記事の投稿、編集をおこなう
・マイブログの【設定】 > 【広告設定】 より、「60日間更新が無い場合」 の 「広告を表示しない」にチェックを入れて保存する。


×

この広告は180日以上新しい記事の投稿がないブログに表示されております。