lisz-works

技術系だけど関係ないこと多い系ブログ

Kivyでシンボリックリンク生成アプリを作ってみた

【スポンサーリンク】

Python×Kivy

「Kivyで何か作ってみたいなぁ」と思っていた昨今。

とりあえず試しに何か作ってみようと思い立ちました。

ということで、毎回「どうやるんだっけ?」となるシンボリックリンクを作るためのアプリを作ってみました。

シンボリックリンクとは?

超ざっくりいうと、ショートカットだけど、自分のパスになる仕組みです。

こちらの記事をどうぞ。

www.lisz-works.com

ソース

ソースです。

メイン

メインのpythonファイルです。

# -*- coding: utf-8 -*-

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
from kivy.properties import ObjectProperty
import proc

class FormsWidget(Widget):
    dbgText = StringProperty()
    inputLink = ObjectProperty(None)
    inputTarget = ObjectProperty(None)

    def __init__(self, **kwargs):
        super(FormsWidget, self).__init__(**kwargs)
        self.dbgText = 'is debug'
    
    def buttonExecClicked(self):
        link = self.ids.inputLink.text
        target = self.ids.inputTarget.text
        text = "**err**"
        isOK = True

        if len(link) <= 0:
            isOK = False

        if len(target) <= 0:
            isOK = False

        if len(text) <= 0:
            text = "empty"
            isOK = False

        text = "[link,target]" + link + "," + target
        self.dbgText = text

        if isOK:
            text = proc.exec(link, target)

class SLinkerApp(App):
    def __init__(self, **kwargs):
        super(SLinkerApp, self).__init__(**kwargs)
        self.title = 'SLinker'
    
    def build(self):
        return FormsWidget()

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

SLinkerAppというアプリの設定と、それに紐づけたWidgetを作っています。

Appがアプリ本体で、Widgetが動作や表示を受け持つイメージですかね。

簡単な表示だけだったら、以前試したKivyのサンプル同様、Appだけでできると思いますが。

www.lisz-works.com

またStringPropertyとObjectPropertyが大事です。

  1. StringProperty:ラベルと変数の紐づけをするためのプロパティ設定
  2. ObjectProperty:テキストボックスの入力値との紐づけをするプロパティ設定

これらを設定しないと、ウィンドウの表示項目と変数とのやり取りができないようです。

kvファイル

レイアウト等の設定です。

FormsWidget:

<FormsWidget>
    GridLayout:
        size: root.size
        
        Label:
            id: labelLink
            text: "link: "
            top: root.top
            size: 80, 40
        TextInput:
            id: inputLink
            top: root.top - 50
            size: root.width, 40
            text: ""
        Label:
            id: labelTarget
            text: "target: "
            top: root.top - 100
            size: 80, 40
        TextInput:
            id: inputTarget
            top: root.top - 150
            size: root.width, 40
            text: ""
        Button:
            id: buttonExec
            text: "Linkin'!"
            center_x: (root.width / 2)
            top: root.top - 200
            size: 120, 40
            on_press: root.buttonExecClicked()
        Label:
            id: labelDebug
            text: root.dbgText
            top: root.top - 250
            size: root.width, 20

今回、参考にしたページを元にGridLayoutを使ってみました。

いまいちサイズ感や、位置感がわからず、レイアウトに苦戦しました……
結果的に面倒で、root.width(ウィンドウ幅いっぱい)を設定して逃げたりしています……

ちなみにここで出てくる「root」は、設定しているWidget、つまりFormsWidgetとなります。

特に難しかったのが、center_x要素です。

ぼくの認識が正しければ、その要素の中心X座標だと思うんですけど、なんかうまくいかず……
違うのかな……

「on_press」は、ボタンのクリックイベントです。
クリックすると、設定している「root.buttonExecClicked()」がコールされます。

labelDebugのtextに設定している「root.dbgText」は、「rootのdbgTextと紐づけますよ」という意味合いになります。
なので、dbgTextの値が変わると、それに応じてこのラベルの表示も変化します。

処理用ロジック

処理用のロジックです。

# -*- coding: utf-8 -*-

import os

def exec(link, target, sw=0):
    cmd = createCmd(link, target, sw)
    if len(cmd) <= 0:
        return
    os.system(cmd)

# 実行コマンドの生成
def createCmd(link, target, sw=0):
    cmd = ""
    
    if sw == 0:
        conf = "/D"
    elif sw == 1:
        conf = "/H"
    elif sw == 2:
        conf = "/J"
    else:
        #print("switch error.")
        return cmd

    # mklink /D リンク ターゲット
    #   リンク:リンクしてるフォルダ名(ファイルの参照フォルダ)
    #   ターゲット:リンク対象のパス(ファイルのありか)
    cmd = 'mklink ' + conf + ' "' + link + '" "' + target + '"'
    #print(cmd)
    return cmd

exec()をコールすることで、createCmd()でコマンド生成をし、そのコマンドを実行する。
といった流れです。

DOSのコマンドは、「os.system()」に渡した文字列を実行してくれます。

シンボリックリンクの構文はこうです。

MKLINK [[/D] | [/H] | [/J]] リンク ターゲット

    /D          ディレクトリのシンボリック リンクを作成します。既定では、
                ファイルのシンボリック リンクが作成されます。
    /H          シンボリック リンクではなく、ハード リンクを作成します。
    /J          ディレクトリ ジャンクションを作成します。
    リンク      新しいシンボリック リンク名を指定します。
    ターゲット  新しいリンクが参照するパス (相対または絶対)
                を指定します。

なので一応各種スイッチに対応させたものを作りつつも、以前使った/Dしかメインから設定していません。

自分で使うかは別として、今後拡張できたらなと思っています。

試してみる

それでは作ったものを試してみます。
これで起動させます。

python main.py

試験用にこのようなファイルとフォルダを用意しました。

用意したサンプル

このパスをtargetに設定します。

次にlinkにリンクさせたいフォルダ……ショートカットのパスのようなものですね。
これをlinkに設定します。

今回は、targetと同じ階層、「C:\LinkTest\link」というフォルダをリンクさせるものとします。

入力したものがコチラ。

アプリにパスを入力

これで「Linkin'!ボタン」を押します。

するとこのようになります。

  • フォルダ:シンボリックリンクが作成される
  • コマンドプロンプト:mklinkの結果が表示される
  • デバッグ表示:linkとtargetのパスが表示される

デバッグ表示

作成されたシンボリックリンク

作成された「linkフォルダ(シンボリックリンク)」を開いてみると……

シンボリックリンクを開く

targetフォルダに作成した、targetFile.txtが、linkフォルダのパスとして表示されていますね!

無事、シンボリックリンクが作成できました。

作ってみて

簡単なアプリだったら、ほんと楽に作れるな……という感じですね。

ただレイアウト作成がネックかなと感じています。

構文的にはそんな難しくはないんですが、調整が難しいという印象です。
なんか楽に作れる方法あるのかな?

また今回のアプリの場合、イマイチなのが

  1. フォルダを文字列で入力しないといけない
  2. 結果がわからない(普通コマンドプロンプト見ないので)
  3. レイアウトいまいち?

といったところでしょうか。

結果が分からないのは、かなりの痛手です。
もしかしたら、コマンド実行結果を何かで取得できるのかな?(そこまで調べていない)

これをWindowsアプリ化(exe)に固めるといい感じですね。

参考ページ

今回こちらのページを参考にしました。

ありがとうございました。

kuroneko0208.hatenablog.com

takeshid.hatenadiary.jp

qiita.com

あとがき

いかがでしたでしょうか?

アプリは色々と粗いですが……

Kivy、オススメです(笑)

リスト表示とか作りたいんですが、イマイチいい感じの資料が見つからない……