kivy: открыть всплывающее окно tcp event - PullRequest
0 голосов
/ 07 мая 2020
• 1000 .

Цель

Приложение kivy должно прослушивать события TCP от внешнего сервера, при этом определенные триггеры вызывают различные вещи в приложении kivy. В этом случае я хочу, чтобы внешний сервер мог открывать всплывающее окно в приложении.

Иллюстративный код

Я принял следующий (рабочий) демонстрационный код из другого ответа SO, который я больше не может найти, поэтому извиняюсь за плагиат, но это не намеренно.

server.py

import socket

serversocket = socket.socket()

host = 'localhost'
port = 54545

serversocket.bind(('', port))
serversocket.listen(1)
clientsocket,addr = serversocket.accept()

print("got a connection from %s" % str(addr))

while True:
    msg = input("> ")
    clientsocket.send(msg.encode('utf-8'))

client.py

import socket

class MySocket:
    def __init__(self,host="localhost",port=54545):
        self.sock = socket.socket()
        self.sock.connect((host, port))

    def get_data(self):
        return self.sock.recv(1024)

main.py

import kivy

from kivy.app import App
from kivy.event import EventDispatcher
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from threading import Thread

from client import *

kivy.require('1.9.1')


class MyEventDispatcher(EventDispatcher):
    def __init__(self, **kwargs):
        self.register_event_type('on_test')
        super(MyEventDispatcher, self).__init__(**kwargs)

    def do_something(self, value):
        self.dispatch('on_test', value)

    def on_test(self, *args):
        print('I am dispatched', args)
        CustomPopup().open()

class CustomPopup(Popup):
    pass

class MainScreen(Label):
    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

        self.sock = MySocket()
        Thread(target=self.get_data).start()

    def get_data(self):
        while True:
            self.text = self.sock.get_data().decode('utf-8').strip()

            if self.text == 'click':
                MyEventDispatcher().do_something(self.text)

class MyApp(App):
    def build(self):
        return MainScreen()


if __name__ == "__main__":
    MyApp().run()

my.kv

<MainScreen>:
    Button:
        text: 'I do nothing'

<CustomPopup>:
    title: 'Popup window'
    size_hint: .5, .5
    auto_dismiss: False

    GridLayout:
        cols: 1
        Label:
            size_hint: .9, .9
            halign: 'center'
            valign: 'middle'
            text: 'message text goes here'
            text_size: self.width, None

        Button:
            text: 'A: Close'
            on_release: root.dismiss()

        Button:
            text: 'B: Close'
            on_release: root.dismiss()

Все это работает в что я могу отправить слово-триггер click с сервера, и откроется всплывающее окно, у него есть несколько работающих кнопок-заполнителей. Ура.

Проблема, однако, в том, что мне, кажется, нужна фиктивная кнопка на главном экране приложения, чего я не хочу. Если я просто исключу бит <MainScreen> из файла .kv, отправка ключевого слова click приведет к:

I am dispatched ('click',)
Segmentation fault (core dumped)

, но я могу отправить любую другую строку, и она будет отображаться на экране, как ожидалось.

Итак, основные c вопросы:

  1. Как мне заставить это работать так, как нужно, и
  2. Почему размещение нефункциональной кнопки экран заставляет всплывающее окно работать?

Спасибо!

...