#python #matplotlib #event-handling #kivy
Вопрос:
Я пытаюсь эмулировать интерактивную функцию matplotlib с помощью kivy, где я намеревался построить график во всплывающем окне, в котором есть две кнопки: одна для следующего графика, другая для выхода из всплывающего окна и макет для построения фактического графика. В корневом окне есть переключатель kivy, который запустит всплывающее окно. Он изначально находится в выключенном состоянии, и я хотел бы сохранить его в выключенном состоянии после выхода из всплывающего окна. Код работает нормально, но мне нужно дважды нажать кнопку «Закрыть» во всплывающем окне, чтобы успешно выйти из окна, что должно произойти одним щелчком мыши.
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from matplotlib import pyplot as plt
import numpy as np
from kivy.garden.matplotlib import FigureCanvasKivyAgg
from kivy.uix.popup import Popup
Builder.load_file('label_custom.kv')
def add_plot():
signals = [[7, 89.6, 45.-56.34],
[16, 30.6, 25.-56.34], [20, 39.6, 15.-56.34], ]
for sig in signals:
plt.clf()
signal = np.array(sig)
# this will plot the signal on graph
plt.plot(signal)
# setting x label
plt.xlabel('Time(s)')
# setting y label
plt.ylabel('signal (norm)')
plt.grid(True, color='lightgray')
fig1 = plt.gcf()
yield fig1
class MyPopup(Popup):
start_btn = ObjectProperty(None)
graph_layout = ObjectProperty(None)
dismiss_button = ObjectProperty(None)
def __init__(self, **kwargs):
super(MyPopup, self).__init__(**kwargs)
self.plot = add_plot()
def testing(self):
self.graph_layout.clear_widgets()
fig = next(self.plot)
self.graph_layout.add_widget(FigureCanvasKivyAgg(fig))
def test(self):
self.dismiss()
App.get_running_app().root.switch.active = False
class MyBoxLayout(BoxLayout):
switch = ObjectProperty(None)
class MyApp(App):
def build(self):
box = MyBoxLayout()
return box
if __name__ == '__main__':
MyApp().run()
и файл киви:
#:import Factory kivy.factory.Factory
<MyPopup>:
start_btn: start_btn
graph_layout: graph_layout
dismiss_button: _dismiss_button
auto_dismiss: False
size_hint:.8, .8
BoxLayout:
canvas.before:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
size: self.size
pos: self.pos
orientation: "vertical"
padding: 20
spacing: 10
BoxLayout:
id: graph_layout
size_hint_y: .8
Button:
id: start_btn
text:"Click"
size_hint_y: .1
pos_hint:{'center_x': .5}
on_release: root.testing()
Button:
id: _dismiss_button
text: 'Close me!'
size_hint_y: .1
pos_hint:{'center_x': .5, 'y': 0}
on_release: root.test()
<MyBoxLayout>:
switch: tog_switch
canvas.before:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
size: self.size
pos: self.pos
orientation: "vertical"
padding: 20
spacing: 10
Switch:
id: tog_switch
on_active: Factory.MyPopup().open()
Ответ №1:
Решение довольно простое:
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from matplotlib import pyplot as plt
import numpy as np
from kivy.garden.matplotlib import FigureCanvasKivyAgg
from kivy.uix.popup import Popup
Builder.load_file('label_custom.kv')
def add_plot():
signals = [[7, 89.6, 45.-56.34],
[16, 30.6, 25.-56.34], [20, 39.6, 15.-56.34], ]
for sig in signals:
plt.clf()
signal = np.array(sig)
# this will plot the signal on graph
plt.plot(signal)
# setting x label
plt.xlabel('Time(s)')
# setting y label
plt.ylabel('signal (norm)')
plt.grid(True, color='lightgray')
fig1 = plt.gcf()
yield fig1
class MyPopup(Popup):
def __init__(self, **kwargs):
super(MyPopup, self).__init__(**kwargs)
self.plot = add_plot()
def testing(self):
self.graph_layout.clear_widgets()
try:
fig = next(self.plot)
except StopIteration:
App.get_running_app().root.set_switch_state()
else:
self.graph_layout.add_widget(FigureCanvasKivyAgg(fig))
class MyBoxLayout(BoxLayout):
switch = ObjectProperty(None)
def __init__(self, **kwargs):
super(MyBoxLayout, self).__init__(**kwargs)
self.popup = MyPopup()
def set_switch_state(self):
self.switch.active = not(self.switch.active)
self.popup.dismiss()
class MyApp(App):
def build(self):
box = MyBoxLayout()
return box
if __name__ == '__main__':
MyApp().run()
И файл kv:
<MyPopup>:
graph_layout: _graph_layout
auto_dismiss: False
size_hint:.8, .8
BoxLayout:
canvas.before:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
size: self.size
pos: self.pos
orientation: "vertical"
padding: 20
spacing: 10
BoxLayout:
id: _graph_layout
size_hint_y: .8
Button:
text:"Click"
size_hint_y: .1
pos_hint:{'center_x': .5}
on_release: root.testing()
Button:
text: 'Close me!'
size_hint_y: .1
pos_hint:{'center_x': .5, 'y': 0}
on_release: app.root.set_switch_state()
<MyBoxLayout>:
switch: tog_switch
canvas.before:
Color:
rgba: (1, 1, 1, 1)
Rectangle:
size: self.size
pos: self.pos
orientation: "vertical"
padding: 20
spacing: 10
Switch:
id: tog_switch
on_active: root.popup.open()