プログラミング: 2020年6月アーカイブ

LibreOffice のマクロを Python で書いた場合の、「OK」ボタンが1つだけのダイアログボックスと、「はい」「いいえ」の選択肢のあるダイヤログボックスの使い方。
情報をググってみても、なんか「表示させるまで」の情報や、「OK」ボタン一個だけの場合の情報ばかりが多かったので、具体的な例をあげとこう。

a.セルに値をセットする時、すでに値がセットされていたら上書きするか確認表示

 20200613_dialog1.jpg

b.読み込むファイルが無い時、その旨をアラート表示

 20200613_dialog2.jpg

ソースは以下のとおり。(@ty21kyさんの Qiita の記事を参考に)

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import uno
import datetime
import re
import os

CARD_DATA = '/data/number_cardid.csv'

class Bridge(object):

    def __init__(self):

        self._context = XSCRIPTCONTEXT.getComponentContext()
        self._desktop = XSCRIPTCONTEXT.getDesktop()
        self._frame = self._desktop.CurrentFrame
        self._window = self._frame.ContainerWindow
        self._toolkit = self._window.Toolkit

    def run_infodialog(self, title='', message=''):

        msgbox = self._toolkit.createMessageBox(self._window,
                                                'infobox',    # ヒントアイコン
                                                1,            # 「OK」ボタン
                                                title,
                                                message)
        msgbox.execute()
        msgbox.dispose()

    def run_querydialog(self, title='', message=''):

        msgbox = self._toolkit.createMessageBox(self._window,
                                                'querybox',   # 疑問符アイコン
                                                3,            # 「はい」「いいえ」ボタン
                                                title,
                                                message)
        return msgbox.execute()

def get_today(*args):

    doc = XSCRIPTCONTEXT.getDocument()
    sheet = doc.getSheets().getByName('Main')
    dt_now = (datetime.datetime.now()).strftime('%Y/%m/%d')
    kaisai_nengetsu = sheet.getCellRangeByName('C3')

    if kaisai_nengetsu.String:
        msg_box = Bridge()
        res = msg_box.run_querydialog(title='開催年月日セット', message='すでに値がセットされています。\n上書きでセットしますか?')

        if res != 2:    # 「はい」でなければ終了(res=2 はい res=3 いいえ)
            return

    kaisai_nengetsu.String = dt_now

def load_card_all(*args):

    doc = XSCRIPTCONTEXT.getDocument()
    sheet = doc.getSheets().getByName('Card')

    if not os.path.isfile(CARD_DATA):
        msg_box = Bridge()
        msg_box.run_infodialog(title='ファイルエラー', message='ファイルが存在しません\n' + CARD_DATA)
        return

    f = open(CARD_DATA)
    lines = f.readlines()
    f.close()
    i = 0;
    for line in lines:
        list = re.split("\|\|", line.rstrip('\n'))
        card = sheet.getCellByPosition(0, i)
        id = sheet.getCellByPosition(1, i)
        card.Value = list[0]
        id.String = list[1]
        i += 1

窓の大きさとかは他の方のブログを見ると、設定はできるのに無視されるようだ。

つーか、LibreOffice(OpenOffice.org も)の Python マクロについて書かれた本って無いのね。
まあ、マニアックなネタだからな(笑)

<追記>
エラーダイアログは「infobox」ではなく「errorbox」だよね。
ダイアログ表示関数にメッセージタイプも渡すように修正してもいいが、エラーはエラーで別関数を用意した方がソース的にはわかりやすいかな?

 20200614_windows3.jpg

LibreOffice の Python マクロを久しぶりに作っているので、「知っていたのに忘れてしまったこと」で小一時間ほど無駄にしてしまった(^^;

例えば以下のようなマクロを実行する時。

<略>
def get_today():
    '''
    今日の日付を取得して開催年月日にセット
    '''

    doc = XSCRIPTCONTEXT.getDocument()

    # シートを選択
    sheet = doc.getSheets().getByName('Main')

    # 今日の日付の取得(YYYY/MM/DD)
    dt_now = (datetime.datetime.now()).strftime('%Y/%m/%d')

    # 開催年月日のセルにセット
    # すでに日付が入っている時は更新するか確認する
    kaisai_nengetsu = sheet.getCellRangeByName('C3')

    if kaisai_nengetsu.String:
        msg_box = Bridge()
        res = msg_box.run_querydialog(title='開催年月日セット', message='すでに値がセットされています。\n上書きでセットしますか?')

        if res != 2:    # 「はい」でなければ終了
            return

    kaisai_nengetsu.String = dt_now
<略>

これを、「ツール」→「マクロ」→「マクロの管理」→「Python」でマクロを実行したときは問題ない。

20200612_libre1.jpg

しかし、これをフォームコントロールの「プッシュボタン」のイベントとして実行すると、

com.sun.star.uno.RuntimeException: Error during invoking function get_today in module file:///C:/Users/hoge/AppData/Roaming/LibreOffice/4/user/Scripts/python/m_main.py (<class 'TypeError'>: get_today() takes 0 positional arguments but 1 was given
  File "C:\Program Files\LibreOffice\program\pythonscript.py", line 921, in invoke
    ret = self.func( *args )
)

というエラーになってしまうのである。

20200612_libre2.jpg.jpg

get_today 関数の引数は無しなのに、ボタンのマクロ設定には m_main.py$get_today (user, Python) と何やら渡されてるから?
0 positional arguments(引数はゼロ個(無し))なのに、but 1 was given(しかし、引数がひとつ渡された)ってことよね?

そう、すっかり忘れていたのである。
ボタンで呼ばれるマクロの関数は、*args という任意の数の引数を受け取れる可変長引数を指定しないといけないことを・・・
でも、思い出したでぇ~(笑)

というわけで、関数宣言部を、

def get_today(*args):

と直したらエラーは消えたのでありました。めでたし、めでたし。

以前このブログでも何度かエントリーを書いた SONY RC-S380 で FeliCa カードを読み込んだ情報を Python で利用する話。

Windows 7 Professional で開発をしてたんだけど、今回、環境を Windows 10 Pro に移した。

その際、ちょっと Windows 7 の時何をやったかすっかり忘れてて、うろ覚えでセットアップして「プチはまり」をしたので環境構築についてメモっておく(^^;

ちなみに、Python 3.8.3 はすでにインストールされている。

1.WinUSB ドライバのインストール

https://zadig.akeo.ie/ からダウンロードした zadig-2.5.exe を使って WinUSB のインストールを行う。

RC-S380 を Windows 10 に接続したときに自動でインストールされた sonynfcport100c(v1.5.7.2)を WinUSB(v6.1.7600.16385)に Replace する。

・・・が、これ、本当に必要だったのか?Windows 7 のときには必要だったが、Windows 10 だと sonynfcport100c ドライバがインストールされているので、WinUSB ドライバを入れる必要があるのかどうなのか?

もし、このページを見てセットアップをしようと思っている人は、一度、この作業無しで RC-S380 が読めるか試してみてほしい。俺は面倒臭いので試さないけど(笑)

2.pip のバージョンアップ

必須ではないが、モジュールのインストールの度にワーニングが出るのでバージョンアップしておく。

コマンドプロンプトで、
python -m pip install --upgrade pip

3.nfcpy モジュールのインストール

コマンドプロンプトで、
pip3 install nfcpy

libusb1  1.8
ndeflib  0.3.3
nfcpy    1.0.3
pip      20.1.1
pyDes    2.0.1
pyserial 3.4
などがインストールされる。

4.libusb-1.0.dllのインストール

から最新版ダウンロード。
今日時点の最新版は、

ダウンロード後、展開したファイルを、Windows システムフォルダにコピー。

・64bit版
展開場所\MS64\dll\libusb-1.0.dll → C:\Windows\System32 にコピー

・32bit版
展開場所\MS32\dll\libusb-1.0.dll → C:\Windows\SysWOW64 にコピー

余談だが、64bit プログラムを格納する場所が System32 だとか、このわかりづらい構成はどうにかならんものか?(^^;>Windows

以上で、Windows 10 でも、Python プログラムの中から FeliCa カードが読めるはずだ。

ちなみに、作成したプログラムの中で HTTP プロトコルを使ってサーバにカード情報を飛ばしているので、requests モジュールも pip でインストールしないといけないのだが、これは、まあ、俺独自の話なので(笑)

このアーカイブについて

このページには、2020年6月以降に書かれたブログ記事のうちプログラミングカテゴリに属しているものが含まれています。

前のアーカイブはプログラミング: 2020年2月です。

次のアーカイブはプログラミング: 2020年7月です。

最近のコンテンツはインデックスページで見られます。過去に書かれたものはアーカイブのページで見られます。


月別 アーカイブ

電気ウナギ的○○ mobile ver.

携帯版「電気ウナギ的○○」はこちら