I’m having trouble with correctly calling functions from different classes.
I am making a simple game which calculates the score using the amount of time it takes to clear a level. There’s a stopwatch running in the background and I want to add a pause button that popup menu, and a resume button inside this popup menu.
The problem is that when calling the pause function from within the popup menu, it will also be returned inside the popup, instead of inside the main widget.
Here is a simplified version of the code:
import kivy from kivy.app import App from kivy.lang import Builder from kivy.properties import NumericProperty from kivy.uix.widget import Widget from kivy.uix.popup import Popup from kivy.clock import Clock root_widget = Builder.load_file('app.kv') class ExampleWidget(Widget): time = NumericProperty(0) paused = False stop = False # Keeping time def increment_time(self, interval): self.time += .1 print(self.time) # To check if stopwatch is running or not # Stop should mean that the stopwatch must reset when it starts again. # When paused it should resume when it starts again def stop_start_or_pause(self): # stop stopwatch if self.stop: Clock.unschedule(self.increment_time) print('Stopped') # Make sure time is 0 when restarting elif not self.stop and not self.paused: # Keeping time self.time = 0 Clock.schedule_interval(self.increment_time, .1) # Pause stopwatch elif self.paused: Clock.unschedule(self.increment_time) print("!!", self.time) # To make it easier to see if stopwatch actually resumes where it left off print('unscheduled') # Just to confirm and to make it a bit easier to see # resume stopwatch elif not self.paused: Clock.schedule_interval(self.increment_time, .1) class PopupMenu(Popup): example = ExampleWidget() class MyApp(App): ExampleWidget = ExampleWidget() def build(self): return ExampleWidget() MyApp().run()
#:import Factory kivy.factory.Factory <[email protected]> auto_dismiss: False size_hint_y: .8 size_hint_x: .9 title: 'Pause' example: app.ExampleWidget BoxLayout: Button: text: 'resume' on_press: root.example.paused = False on_release: root.dismiss(); root.example.stop_start_or_pause() size: self.size <ExampleWidget>: GridLayout: col: 2 rows: 3 size: root.size Button: text: 'start' size: self.size on_press: root.stop = False; root.stop_start_or_pause() Button: text: 'stop' size: self.size on_press: root.stop = True; root.stop_start_or_pause() Button: text: 'Pause menu' size: self.size on_press: root.paused = True on_release: Factory.PopupMenu().open(); root.stop_start_or_pause() Label: text: str(round(root.time)) size: self.size
I tried making a function and using Clock.schedule.interval() to keep checking if paused == True, but it keeps returning:
AttributeError: 'float' object has no attribute 'stopped'
This didn’t seem like efficient solution anyways, so I didn’t want to spend too much time on this function. I also tried to find ‘stupid’ mistakes (I.e. ‘,’ instead of ‘.’) but that was before I realised that the resume button returned a ‘second’ stopwatch instead of updating the one I actually wanted to use.
I hope that someone can help, and that my question is clear. English is not my first language so I sometimes have a hard time finding the best way to explain/ask questions.
Thank you in advance!
If I understand your question, the problem is with your
class MyApp(App): ExampleWidget = ExampleWidget() def build(self): return ExampleWidget()
This code is creating two instances of
ExampleWidget. One is returned in the
build() method, and one is saved as the
ExampleWidget attribute of
MyApp. Now, when you use the
ExampleWidget attribute of
MyApp, you are not referencing the
ExampleWidget that is the root of your GUI, so it has no effect on what appears on the screen. The fix is to just creat a single instance of
ExampleWidget, like this:
class MyApp(App): ExampleWidget = ExampleWidget() def build(self): return self.ExampleWidget
Answered By – John Anderson
Answer Checked By – Robin (BugsFixing Admin)