質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.83%

  • Python

    6405questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    4883questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Windows 10

    816questions

    Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。

python3,kivyで、シリアルから受信したデータをTabbedPanel上に表示させたい

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 205

sv13vsarcb

score 2

2018/04/18 16:20 ソースコード更新しました

 前提・実現したいこと

python3とkivyを使って、シリアルポートから受信したデータを解析したものをGUI上に表示・一定時間毎に更新させたいのですが、上手くいかず困っております。

 発生している問題

シリアル受信~解析~コンソールに表示させるプログラムと、kivyを用いてGUIの枠を作成するプログラムを別々に作成することは出来たのですが、kivyのmainloopにシリアル受信~部分のプログラムを入れる方法が分からないといったような状況です。

以下のソースコードを実行すると取り合えずエラーは出ず、GUIの表示部分のみが実行され、GUIのウィンドウを閉じると解析部分が始まるといった動作です。

ご指導の程、何卒宜しくお願い致します。

 該当のソースコード

上がpyファイル、下がkvファイルです。

import serial
import binascii
import datetime
import struct

from kivy.app import App
from kivy.uix.tabbedpanel import TabbedPanel
from kivy.properties import StringProperty
from kivy.core.text import LabelBase, DEFAULT_FONT
from kivy.clock import Clock
from kivy.event import EventDispatcher

LabelBase.register(DEFAULT_FONT,"meiryo.ttc")

class List():

    s = serial.Serial('COM5',9600)

    list = []
    XB_list = []
    BT_list = []
    IO_list = []
    ML_list = []

    xbee = 0
    btid = 0
    reed = 0
    ser = 0
    time = 0

    print("start")

    def __init__(self):
        pass

    def receive_time(self,dt):
        time = datetime.datetime.now()
        self.time = (time.strftime('%Y年%m月%d日 %H:%M:%S'))
        print(self.time)

    def first_check(self):
        self.list = []
        num = 0
        print("check")
        while num <= 2:
            ser = self.s.read()
            data = binascii.b2a_hex(ser)
            dec = int(data,16)
            self.list.append(dec)
            num += 1

    def length_read(self):
        length = self.list[2]

        if length == 35:
            self.ser = self.s.read(length+1)

        else:
            print("read error")
            pass

    def sample(self):
        xbee = self.ser[2:9]
        btid = self.ser[18:30]
        reed = self.ser[33:35]

        self.xbee = str(binascii.hexlify(xbee), 'utf-8')
        self.btid = btid.decode()
        self.reed = reed.decode()

    def add_list(self):
        if((self.xbee in self.XB_list) == False):
            self.XB_list.append(self.xbee)

        else:
            pass

        if((self.btid in self.BT_list) == False):
            self.BT_list.append(self.btid)
            self.IO_list.append(self.reed)
            self.ML_list.append(0)

        elif((self.btid in self.BT_list) == True):
            no = self.BT_list.index(self.btid)
            self.IO_list[no] = self.reed

class Mado(TabbedPanel):
    print("window")
    pass

class TabbedPanelApp(App):
    time =  StringProperty()

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

    def build(self):    
        self.title = 'test'
        Clock.schedule_interval(lst.receive_time,5.0)
        print("build")
        return Mado()

lst = List()
tpa = TabbedPanelApp(lst)

print("print")

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

print("main2")
while True:
    lst.first_check()
    lst.length_read()
    lst.sample()
    lst.add_list()
    lst.receive_time()
    print(lst.XB_list)
    print(lst.BT_list)
    print(lst.IO_list)
# -*- coding: Shift-JIS -*
#:kivy 1.10.0

<PaddingBoxLayout@BoxLayout>:
    padding: 10

<Mado>:
    size_hint: 1, 1
    pos_hint: {'center_x': .5, 'center_y': .5}
    do_default_tab: False

    TabbedPanelItem:
        text: 'XB_List'
        Label:
            text: 'XB ID 1'

    TabbedPanelItem:
        text: 'BT_List'
        GridLayout:
            cols: 2
            rows: 2
            Label:
                text: 'BT ID 1'
            Button:
                text: 'BT ID 2'

    TabbedPanelItem:
        text: 'IO_List'
        Label:
            text: 'IO '

    TabbedPanelItem:
        text: 'Time'
        Label:
            text: str(app.time)


また、StringPropertyを用いて5秒ごとに現在の時刻をTabbedPanel上に表示、更新させようとしていますが、参照している場所に問題があるのでしょう。これも上手くいきません。
頂いた回答により一部解決しました
AttributeError: 'Window' object has no attribute 'time'

 補足情報

[Python] v3.6.3(32bit)
[kivy] v1.10.0

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • tachikoma

    2018/04/13 17:55

    Threadを使わないと難しいかなぁ。

    キャンセル

回答 2

checkベストアンサー

+4

私の環境(Linux)では

 Traceback (most recent call last):
   File "略/site-packages/serial/serialposix.py", line 265, in open
     self.fd = os.open(self.portstr, os.O_RDWR | os.O_NOCTTY | os.O_NONBLOCK)
 FileNotFoundError: [Errno 2] No such file or directory: 'COM5'

と出て動かないので実際に確かめられないですが、とりあえずソースコードを読んで気付いた事を挙げると

  • Kvファイルの最後の行のtext: 'str(root.time)'が間違いで、timeというPropertyを持っているのはTabbedPanelAppクラスなのでtext: str(app.time)とすべきです。
  • Windowクラスの名前は変えた方がいいです。
  • Kvファイル中の<TabbedPanel>:<Windowクラスの新しい名前>:に変えるべきです。現状だとTabbedPanel全てを汚染しているので。
  • 使ってないmoduleのimport文を消した方がいいです。(from kivy.core.window import Window と import time 他色々)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/18 11:42 編集

    ご回答ありがとうございます。

    シリアルポートに接続した通信モジュールが受信したデータを解析、表示させるために作成したプログラムですので、シリアルポート[COM5]に接続がないと動きません…
    取り合えず最初の```s = serial.Serial('COM5',9600)```を削除して頂ければ、(```ser = self.s.read()```部分でエラーは出ますが)今回問題となっている動作(GUIの表示部分のみが実行され、GUIのウィンドウを閉じると解析部分が始まる)を確認することができます。

    GUIウィンドウを表示させながらpyファイル最後のwhileの内容を行い、while内の処理で得た値をGUI上に表示させるのが目標なのですが、どのようにkivyのmain loop内にwhileの内容を入れたら良いのか、といった状況です。

    kvファイルの最後の行の変更、Windowクラスの名前の変更、Kvファイル中の<TabbedPanel>の変更を行ったところ、```AttributeError: 'Window' object has no attribute 'time'```は出なくなりました。
    ありがとうございます。
    しかし、Label上には何も表示されません…

    ご指摘された「Propertyを持っているクラス」の事、「使ってないimport文の削除」は非常に納得できたのですが、「TabbedPanel全てを汚染」については私のpython,kivyの理解が浅い為、よく分かりませんでした。何故クラス名がWindowだと問題があるのでしょうか。
    ご教示いただければ幸いです。

    キャンセル

  • 2018/04/18 21:30

    > どのようにkivyのmain loop内にwhileの内容を入れたら良いのか、といった状況です。

    Clock.schedule_interval()の使い方を知っているのなら、whileの中身をそのまま使った関数を定義して、それをClock.schedule_interval()に渡すだけですよ。今回の場合はこの関数はTabbedPanelAppのMethodの方が良いと思うのでTabbedPanelAppに以下のようなMethodを用意してあげて

    def polling(self, dt):
    whileループの中身

    それをbuild()内の「lst.receive_time」に代えてClock.chedule_interaval()に渡してあげればいいです。



    > しかし、Label上には何も表示されません…

    コード内にどこにもTabbedPanelAppのtimeプロパティに書き込む処理が無いので当然です。上のpolling()内で
    self.time = xxxxxxx
    と書き込んであげるのが良いと思います。



    > 「TabbedPanel全てを汚染」については

    <TabbedPanel>:
    TabbedPanelItem:
    と書いてしまうと今後作られる全てのTabbedPanelが始めからTabbedPanelItemを一つ持った状態になります。例えばですがBoxLayoutが最初からButtonが一つ入った状態になってたとしたらどう思いますか?そんな汎用性の無い部品はおかしいですよね。なのでKivy標準のWidgetをいじるのではなくて、自分で用意したクラス(今回の場合はMadoクラス)をいじるべきなんです。そうすればKivy標準のWidgetには一切影響を与えないで済みます。



    > 何故クラス名がWindowだと問題があるのでしょうか。

    これはWindowが絶対駄目というわけではないですが、Kivyが元から持っているWindowクラスと混同してしまうのでやめて欲しいです。(今回のようにコードを人に見せる場合は特に)。Windowに限らずですが基本KivyのClass名と被らないようにした方がBugが起こりにくく読みやすいので。とりあえず以下のコードで出てくるクラス名と同じ名前のクラスは絶対に作らないようにしたほうがいいです。

    from kivy.factory import Factory
    print(sorted(list(Factory.classes.keys())))



    こういった場所で質問する時なんですが、プロジェクトのコードをそのまま持ってくるのではなくて問題を再現するできるだけ最小限のコードを別に作って載せて欲しいです。今回の場合実はserial通信は全く関係ないので外せますし、日本語Font「meiryo.ttc」もどの環境にでもあるFontではないので使うのをやめて、「年月日」の代わりに「ymd」を使えば済むので。

    キャンセル

  • 2018/04/19 14:44

    知識、質問方法等至らない点も多かった中、回答、ご指摘頂きまして感謝しております。
    おかげ様で無事目標としていた動作の実現のみならず、動作や記述方法等についても理解が深まりました。
    大変丁寧な解説、本当にありがとうございました。

    キャンセル

0

kivyを使ったことがないので完全な当てずっぽですが、コンストラクタの部分を使ってlstをAppのインスタンスに渡してあげればいいんじゃないかなぁ。

class TabbedPanelApp(App):
    def __init__(self, lst):
        self.lst = lst

    def build(self):    
        self.title = 'test'
        Clock.schedule_interval(self.lst.receive_time, 5.0)
        print("build")
        return Window()

lst = List()
tpa = TabbedPanelApp(lst)

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/04/16 09:58

    早速のご回答ありがとうございました。
    なるほど確かにと思い試してみたものの、エラーが出てしまいました。
    line 110, in <module>
    TabbedPanelApp().run()
    TypeError: __init__() missing 1 required positional argument: 'lst'
    この場合、どのようにしたら良いでしょうか。

    キャンセル

  • 2018/04/16 10:26

    TabbedPanelApp().run()の部分をtpa.run()にしてみたらどうかな。コンストラクタが2回呼ばれてるので。

    キャンセル

  • 2018/04/16 12:40

    TabbedPanelApp().run()の部分をtpa.run()に変更してみたのですが、また別のエラーが起こってしまいました。
    Programs\Python\Python36-32\lib\site-packages\kivy\app.py", line 799, in run
    if not self.built:
    AttributeError: 'TabbedPanelApp' object has no attribute 'built'
    以下のリンクを参考にもう少し頑張ってみますが、ご意見頂ければ幸いです。
    https://stackoverflow.com/questions/36758038/kivy-python-countdown-app-project-kivy-has-no-attribute-built-error

    キャンセル

  • 2018/04/17 20:37

    __init__()を上書きしたのなら、その中で親の__init__()を呼ぶ必要がありますよ

    キャンセル

  • 2018/04/18 16:25

    こちらにもご回答ありがとうございます。
    おかげさまでAttributeError: 'TabbedPanelApp' object has no attribute 'built'エラーは出なくなりました。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.83%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    6405questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

  • Python 3.x

    4883questions

    Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

  • Windows 10

    816questions

    Windows 10は、マイクロソフト社がリリースしたOSです。Modern UIを標準画面にした8.1から、10では再びデスクトップ主体に戻され、UIも変更されています。PCやスマホ、タブレットなど様々なデバイスに幅広く対応していることが特徴です。