kivyでメニューバー作ってみた

環境

os x high Sierra
python 3.7.0
kivy 1.10.1

こんな感じ

f:id:b1u3:20180926225605g:plain

ソースコード

#! kivy 1.0.9
# example.kv

<MenuList>:
    canvas.before:
        Color:
            rgba: 1, 0, 0, .5
        Rectangle:
            pos: self.pos
            size: self.size


<MenuImage>:
    source: 'menu.png'
    keep_ratio: True


<MenuBar>:
    end: True
    canvas.before:
        Color:
            rgba: 1, 0, 0, .5
        Rectangle:
            pos: self.pos
            size: self.size

    MenuImage:
        center: 50, root.center_y
        size: 32, 32


<RootWidget>:
    MenuBar:
        pos: root.pos[0], root.height-90
        size: root.width, 90
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.properties import BooleanProperty, ObjectProperty
from kivy.logger import Logger
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.scrollview import ScrollView


class TestLabel(Label):
    """ For Testing MenuList """
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def on_touch_down(self, touch):
        if self.collide_point(touch.x, touch.y):
            Logger.info(f'[{self.__class__.__name__}\t] {self.text} was touched.')
            return True
        return super().on_touch_down(touch)


class MenuList(ScrollView):

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.layout = GridLayout(cols=1, spacing=20, size_hint_y=None)
        self.layout.bind(minimum_height=self.layout.setter('height'))
        self.do_scroll_x = False
        self.add_widget(self.layout)
        MenuList.test_add_widget(self)

    def add_widget(self, widget, index=0, canvas=None):
        if isinstance(widget, GridLayout) or not self.children:
            super().add_widget(widget)
        else:
            if hasattr(widget, 'text_size'):
                widget.bind(size=self.__class__._update_each_text_rect)
            self.layout.add_widget(widget, index=index, canvas=canvas)

    @staticmethod
    def _update_each_text_rect(instance, value):
        instance.text_size = value[0]-10, value[1]

    @staticmethod
    def test_add_widget(menu_list):
        for i in range(5):
            lbl = TestLabel(text=f'Menu {i}', size_hint_y=None, height=40)
            menu_list.add_widget(lbl)


class MenuImage(Image):
    toggled = BooleanProperty(False)

    def on_touch_down(self, touch):
        Logger.debug(f'[{self.__class__.__name__}\t] touched')
        if self.collide_point(touch.x, touch.y):
            self.toggled = not self.toggled
            return True
        return super().on_touch_down(touch)

    def on_toggled(self, instance, value):
        Logger.info(f'[{self.__class__.__name__}\t] toggled to {value}.')
        if not hasattr(self.parent, 'toggled'):
            Logger.warning(f'[{self.__class__.__name__}\t] {self.parent.__class__.__name__}\
                            has no boolean attr toggled.')
        self.parent.toggled = value


class MenuBar(Widget):
    toggled = BooleanProperty(False)
    menu_list = ObjectProperty(None)

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.menu_list = MenuList()
        self.bind(size=self._update_size, pos=self._update_size)

    def on_toggled(self, instance, value):
        Logger.info(f'[{self.__class__.__name__}\t] toggled to {value}.')
        if self.menu_list is not None:
            if value:
                self.add_widget(self.menu_list)
                self._update_size(self, self.size)
            else:
                self.remove_widget(self.menu_list)

    def _update_size(self, instance, size):
        self.menu_list.size = (280, self.parent.height-90)
        self.menu_list.pos = self.parent.pos


class RootWidget(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)


class ExampleApp(App):
    def build(self):
        return RootWidget()


if __name__ == '__main__':
    ExampleApp().run()

途中まで書いた下書きが消えたので、以上です。

django-sslserverを入れた

最近のiOSアプリを開発していると、sslが効いてないサイトにアクセスするには別途、設定を加えなければならない。やってないからわからんけど、その設定を消し忘れてたりして、諸々を垂れ流したら大変なので、代替案を探した。その結果、djangoを使っていたので、django-sslserverを使うことにした。

環境

インストール

そのまま公式を見ればいいと思う

pip install django-sslserver

settings.pyに追記する

INSTALLED_APPS = [
    ...
    'sslserver'
]

migrate等はする必要はない。

manage.py runsslserver

デフォだと127.0.0.1:8000だが、これを初めて開くときは、信頼されていないので、safariを開くと、警告がでる。

証明書周り

runsslserverをすると、証明書の場所が表示されると思う。
openで開いて、証明書をダブルクリックすると、キーチェーンアクセスが開かれるので、左端のシステムをクリックして、証明書リストにfinderからdevelop.crtをドラッグする。ロックがかかっている場合は解除しておく。
そうすると、信頼されていない証明書が追加される。名前はlocalhost。それをダブルクリックして、別ウィンドウを開きつつ、信頼のところをクリックして、拡張する。「この証明書を信頼するとき」のリストを常に信頼するに変えると他の部分も自動的に変わるので、保存する。

またrunsslserverして、httpsでアクセスすると入れる。

delta-timeについて

kivyのClockのところを読んでいたら、コールバックの引数にdt(delta-time)を渡していた。

んで、dtってなんだろうって調べた。

これは前のフレームとの時間差らしい。

だから、はやさ v pix/sで進ませたければ、そのポジションに前の時間から今の時間の間に進む距離を足せばよいので、

(呼び出される瞬間の位置) = (前の位置) + v*dt

となる。

こっからは自分で考えたんだが、
加速度を用いて
x+=の形にできないだろうかと。

ここで、さっきの式の v*dtはdxであるので(微分のあれ)

 dx = x_{n} - x_{n-1}

こういう関係が成り立っていることがわかる。

これらを考慮すると、先ほどの v*dtは

 dx = v * n * dt + x_{0} - (v * (n-1) *dt + x_{0})

から導き出すことができる。

これを同様にして、加速度を含んだ積分から導き出した物理の公式、

 x = \frac{1}{2}at^{2} + vt + x_{0}

を用いて表してみれば、dxが出ると思った。

よって、

 dx = \frac{1}{2}at_{n}^{2} + vt_{n} + x_{0} - (\frac{1}{2}at_{n-1}^2+vt_{n-1}+x_{0})

コイツに

 t_{n} = n×dt

を代入すると、

 dx = \frac{1}{2}a(2n-1)dt^{2}+vdt

nが消えないので、
x+=の形では表せないようだ。

コード書くときは位置の変数に公式から出した値をぶち込むしかなさそうだ。

ただし、こんな書き方はある

In [19]: def test(dt, v, a):
    ...:     if 10%dt != 0:
    ...:         return
    ...:     x = 0
    ...:     for i in range(10//dt):
    ...:         x += (1/2*a*(2*float(i+1)-1)*dt**2+v*dt)
    ...:     print(x)
    ...:

In [20]: test(2,3,4)
230.0

In [21]: test(5,3,4)
230.0



TVTestのソースコードをちまちまと読み進めた

visual studio C++をあまり使ったことがないので、この機に調べてみようと思った。

そもそもエントリーポイントはどこなのだろうという話だが、普通にmainで検索してたら、AppMainクラスと_tWinMainが見つかった。

WinMain関数 - インコのWindowsSDK

WinMainについてはgoogleで最上位にきたやつを読んだ。

気になった点はここ

#define WINAPI __stdcall
#define WINENTRY WINAPI

なるほど。これは単なる呼び出し規約の宣言だったのか。また知見が増えた。
呼び出し規約について知らない人は、アセンブラの関数呼び出しを調べてみるといいと思う。いろいろな種類があるので。

ところで、エントリーポイントはint _tWinMainっていうのがわかった。
そんで、
CMainAppクラスのmainを呼び出してる感じ。
g_appはシングルトンかと思ったんだけど、ちょっと違う臭い。

Cのシングルトンって
ファイル内にstatic化したクラスを置いてnon-staticなその型の変数置けばシングルトンになんないのかなと思った。
C++のシングルトンはクラスあるんだしシングルトンパターンでできそうな気もするけど、試す時間はないかなぁ。


ビルドスクリプトがどこなのかわからないんだけども。

やっとwindowsにgvimを入れた

os xlinux系ではもっぱらvimを使っているのですが、windowsでは入れてませんでした。前にやった時、windowsでは、知識不足等でカラースキームすら入れることができなくてずっとIDEsublimeを使っていました。それにネットに転がってる情報がだいたいlinux系ですし。

追記
あとでサンプルのgvimrc参考にしながら直します。

neobundleとカラースキーマ: molokaiをいれるまで、やりました。

そんなわけで、入れます。

www.kaoriya.net

香り屋さんからコンパイル済み64bitバイナリをダウンロードしてきます。
現バージョンは 8.1? です。

vim81-kaoriya-win64-8.1.0005-20180520

なので。えぇ、僕は新しい物好きです。

zipを解凍したあと、

先に、vim81を

C:\Program Files (x86)\Vim

にvim74にリネームして入れます。ほかのファイルも一緒にいれた方がいいみたいですね。

molokaiを持ってきます。

github.com

cloneしてください。

molokai.vimを入れる場所は~\.vim\colorsではありませんでした。
さきほどリネームしてVimディレクトリにぶち込んだvim74の中のcolorsのようです。
あとはneobundleも指示通り~\.vim入れるような感じでした。

これでwindowsでも楽しいvim lifeが送れるといいなぁと思いました。
READMEにちょっと書いてほしいなと思いました。syntax on でエラーが出たおかげですんなり(?)入りました。

修正が入るまではたぶんこれで行くと思います。あきらかにvim74はおかしいので。vim74と書いてある部分を修正する手もあったんですけど、簡単に試せる方にしちゃいましたね。申し訳🍆です。

エディターのLive Edit機能

Jetbrains製品使ってたらたまたま見つけたLive editプラグイン。これはhtmlをリアルタイムでレンダリングしてくれるプラグイン
他のエディターでもLive editで検索すれば出てくると思う。sublimevimは出てきた。
結構便利だと思った。

f:id:b1u3:20180921072000g:plain

python 3.7 kivy libpng16-16.png Error on windows8

Environment

  • pipenv
  • python 3.7
  • kivy.deps.sdl2 0.1.18

When I installed kivy through official pip instruction in my windows 8, error happened.
https://kivy.org/docs/installation/installation-windows.html

The procedure entry point inflateValidate could not be located in the dynamic link library C:\Program Files\GIMP2\bin\libpng16-16.dll.

It depends on kivy.deps.sdl2 packages. I tried to change that dll. It worked.

Download link:
www.dllme.com

If does'n work, please commented.