I have in my app some images , each image belongs to a screen and when I press a button I try to get another screen but a random one. I think I am pretty close to do what I want to do but for 2 days I am stuck at this stage.. when i run my code in the console i have this error
" AttributeError: 'ScreenManager' object has no attribute 'random_screen' "
And I really don't know where to put that attribute ... please heeeelppp ! :((
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from random import choice
class MyScreens(Screen):
screens = ["Q1", "Q2", "Q3"] # ........
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.random_screen()
def random_screen(self, *_):
self.source = choice(self.screens)
class Q1(Screen):
pass
class Q2(Screen):
pass
class Q3(Screen):
pass
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
sm.add_widget(Q2(name='Q2'))
sm.add_widget(Q2(name='Q3'))
return sm
if __name__ == '__main__':
TestApp().run()
<Q1>:
Image:
source: 'Q1.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: app.root.random_screen()
<Q2>:
Image:
source: 'Q2.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_press: app.root.random_screen()
<Q3>:
Image:
source: 'Q3.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_press: app.root.random_screen()
You got a lot of bugs in there...
Myscreen class isn't connected to your other classes or kv file at all, so that function will not be found at all.
Your 3rd add.widget call adds the 'Q2' screen instead of Q3
Screen does not have a self.source parameter. You need to use the screenmanager to change screens. root.manager.current = 'Q#' would be the correct way.
This worked for me...
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
import random
class Q1(Screen):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
class Q2(Screen):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
class Q3(Screen):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
class TestApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
sm.add_widget(Q2(name='Q2'))
sm.add_widget(Q3(name='Q3'))
return sm
if __name__ == '__main__':
TestApp().run()
KV file
<Q1>:
Image:
source: 'Q1.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = root.random_screen()
<Q2>:
Image:
source: 'Q2.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = root.random_screen()
<Q3>:
Image:
source: 'Q3.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = root.random_screen()
You could also put the method in the app class and in the kv file call it by using
app.random_screen()
Just means you don't have to repeat the same method in each screen class.
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
import random
class Q1(Screen):
Pass
class Q2(Screen):
Pass
class Q3(Screen):
Pass
class TestApp(App):
def random_screen(self):
screens = ['Q1', 'Q2', 'Q3']
return random.choice(screens)
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
sm.add_widget(Q2(name='Q2'))
sm.add_widget(Q3(name='Q3'))
return sm
if __name__ == '__main__':
TestApp().run()
kV:
<Q1>:
Image:
source: 'Q1.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = app.random_screen()
<Q2>:
Image:
source: 'Q2.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = app.random_screen()
<Q3>:
Image:
source: 'Q3.png'
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: root.manager.current = app.random_screen()
Another thing to consider, and I am not sure how this would work as I haven't used images like the way you are doing, but you could have the button change the image rather then change the screen... In the app class you could have a string property that is changed in the same way the button changes your screen. In the kv file, have the image source reference this string property, app.Pic for example below...
from kivy.app import App
from kivy.uix.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen
import random
class Q1(Screen):
Pass
class TestApp(App):
Pic = StringProperty('Q1.png')
def random_pic(self):
Pics = ['Q1.png', 'Q2.png', 'Q3.png']
self.Pic = random.choice(Pics)
def build(self):
sm = ScreenManager()
sm.add_widget(Q1(name='Q1'))
return sm
if __name__ == '__main__':
TestApp().run()
kV:
<Q1>:
Image:
source: app.Pic
FloatLayout:
size: root.width, root.height/2
Button:
size_hint: 0.3, 0.25
pos_hint: {"x":0.09, "top":1.16}
background_color: 1, 1, 1, 0.2
on_release: app.random_pic()
I know this isnt another answer to your original question but as per the above comment here is a really paired back quiz app, to give you an idea of how you can change the question and the answers and use the same buttons and screen...
I put everything into the app class, it makes it easier to access from the kv file. I tried to add in a few comments to try and expalin the code
from kivy.app import App
from kivy.properties import StringProperty, BooleanProperty,ObjectProperty, NumericProperty
from kivy.uix.screenmanager import ScreenManager, Screen
TestBank = {1 : {"Current Question": "Press 3", "Correct Answer": "3", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]},
2 : {"Current Question": "Press 4", "Correct Answer": "4", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]},
3 : {"Current Question": "Press 1", "Correct Answer": "1", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]},
4 : {"Current Question": "Press 2", "Correct Answer": "2", "Chosen Answer": "", "Multiple Chocies": ["1","2","3","4"]}}
def CreateTest(A_Test = TestBank):
#do something to randomise your test, maybe select a certain number of questions or merge several test banks etc...
return A_Test
class MenuScreen(Screen):
pass
class ResultScreen(Screen):
pass
class TestScreen(Screen):
pass
class QuizApp(App):
TestCurrentQuestion = StringProperty()
'This is updated when next question is selcted'
ChosenAnswerText = StringProperty()
'Every time an answer is selected this property is updated with the selected answer, then the label is automatically updated'
CurrentQuestion = NumericProperty(1)
'The Next and Previous buttons change this property up or down'
TotalQuestions = 4
AnswerButtonA = StringProperty()
AnswerButtonB = StringProperty()
AnswerButtonC = StringProperty()
AnswerButtonD = StringProperty()
'These are the four answer buttons, the Next and Previous buttons update these properties with the answer options, the button texts are then autmatically updated'
Score = NumericProperty()
def StartTest(self):
self.Test = CreateTest() #The test is created
self.UpdateQuestionAndAnswerButtons() #This method updates the text properties that updates all the buttons
def NextQuestion(self):
self.CurrentQuestion +=1 #changes the current question property +1
self.UpdateQuestionAndAnswerButtons() #This method updates the text properties that updates all the buttons
def PreviousQuestion(self):
self.CurrentQuestion -=1 #changes the current question property -1
self.UpdateQuestionAndAnswerButtons() #This method updates the text properties that updates all the buttons
def UpdateChosenAnswer(self, button):
self.Test[self.CurrentQuestion]["Chosen Answer"] = button.text #so that a score can be calculated, the chosen answer is stored in the dictionary TestBank
self.ChosenAnswerText = self.Test[self.CurrentQuestion]["Chosen Answer"] #ChosenAnswerProperty is updated, this then updates the label so the chosen answer appears on screen
def UpdateQuestionAndAnswerButtons(self):
self.TestCurrentQuestion = self.Test[self.CurrentQuestion]["Current Question"]
#TestCurrentQuestion is the property, it is updated to ["Current Question"] for the Test Dic
self.AnswerButtonA, self.AnswerButtonB, self.AnswerButtonC, self.AnswerButtonD = self.Test[self.CurrentQuestion]["Multiple Chocies"]
#["Multiple Chocies"] is a list containing 4 items, so the four properties are updated in one line
self.ChosenAnswerText = self.Test[self.CurrentQuestion]["Chosen Answer"]
#The chosen answer is updated, this is needed here incase the previous button is selcted, the previous selected answer will be updated to avoid confusion for the user
def CalculateScore(self):
score = 0
for Question in self.Test.keys():
if self.Test[Question]["Chosen Answer"]== self.Test[Question]["Correct Answer"]:
score+=1
self.Score = score
def build(self):
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(ResultScreen(name='result'))
sm.add_widget(TestScreen(name='test'))
return sm
QuizApp().run()
And the KV file
<ResultScreen>
BoxLayout:
orientation: "vertical"
padding: "20px"
spacing: "20px"
BoxLayout:
Label:
text: f"Your Score was {app.Score} out of {app.TotalQuestions}\n {round(app.Score/app.TotalQuestions*100)}%"
Label:
text: "PASS" if app.Score/app.TotalQuestions*100 >= 70 else "FAIL" #pass mark is 70%
Button:
text: "Good Bye"
on_press: app.get_running_app().stop()
<MenuScreen>
BoxLayout:
orientation: "vertical"
padding: "20px"
spacing: "20px"
Label:
text:"Wecome to the Test App"
Button:
text: "New Test"
on_press: app.StartTest(); root.manager.current = "test"
<TestScreen>
BoxLayout:
orientation: "vertical"
BoxLayout:
padding: "20px"
orientation: "vertical"
Label:
text: app.TestCurrentQuestion
halign: "center"
Label:
text: app.ChosenAnswerText
GridLayout:
padding: "20px"
spacing: "20px"
cols: 2
rows: 2
Button:
text: app.AnswerButtonA
on_press: app.UpdateChosenAnswer(self)
Button:
text: app.AnswerButtonB
on_press: app.UpdateChosenAnswer(self)
Button:
text: app.AnswerButtonC
on_press: app.UpdateChosenAnswer(self)
Button:
text: app.AnswerButtonD
on_press: app.UpdateChosenAnswer(self)
BoxLayout:
size_hint: (1,None)
orientation: "horizontal"
padding: "20px"
spacing: "20px"
Button:
text: "Previous"
size_hint: (0.3,1)
on_press: app.PreviousQuestion()
disabled: True if app.CurrentQuestion == 1 else False
Button:
text: "Submit"
size_hint: (0.4,1)
on_press: app.CalculateScore(); root.manager.current = "result"
Button:
text: "Next"
on_press: app.NextQuestion();
size_hint: (0.3,1)
disabled: True if app.CurrentQuestion == app.TotalQuestions else False
Related
I am using the FileChooserListView from kivy and have run into a overlapping text on scroll with screens that another user came across as well. I looked through their post on GitHub and read that some people are using the plyer FileChooser. I also saw that someone mentioned that it has to do with the Building function of the .kv file. I created a new kivy app and the problem did not occur, but when I return to my older app (no changes of any kind) the problem still occurs.
Sorry for the long post, but I am unsure how these two kivy app codes are different. Am I calling something twice that is causing the FileChooser to "hold" it's position? I am not oppose to using plyer's FileChooser, but could someone give me an example on how to implement it?
testing_kivy.py
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
import os
def train_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class TrainingWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=train_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class WindowManager(ScreenManager):
pass
kv_training = Builder.load_file('testing_kivy.kv')
class MyApp(App):
def build(self):
return kv_training
if __name__ == '__main__':
MyApp().run()
testing_kivy.kv
WindowManager:
TrainingWindow:
<TrainingWindow>
name: "training"
BoxLayout:
orientation: "vertical"
Button:
text: "Select Training Images"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Select Training Annots"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Set Parameters"
font_size: 32
on_release:
app.root.current = "parameters_train"
root.manager.transition.direction = "up"
Button:
text: "Back"
font_size: 16
on_release:
app.root.current = "select"
root.manager.transition.direction = "right"
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
Older_app.py
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.spinner import SpinnerOption
import os
import pandas as pd
def invalid_login():
app = App.get_running_app()
app.root.current = "main"
# Create a BoxLayout to add multiple lines or buttons to a PopUp
box = BoxLayout()
# Create PopUp
pop = Popup(
title="Invalid Password",
size_hint=(None, None), size=(200, 100),
content=box,
auto_dismiss=False
)
# Dismiss PopUp
box.add_widget(Button(text="Close", on_release=pop.dismiss))
pop.open()
def model_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
def train_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
def train_model_load(path, filename):
download_path = os.path.join(path, filename[0])
print(download_path)
class MainWindow(Screen):
def login(self):
if self.ids.password.text == "password":
self.ids.password.text = ""
app = App.get_running_app()
app.root.current = "select"
else:
self.ids.password.text = ""
invalid_login()
class SelectWindow(Screen):
pass
class LoadDialog(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
class TrainingWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=train_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class ModelWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=model_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class TrainModelWindow(Screen):
def show_load_list(self):
content = LoadDialog(load=train_model_load, cancel=self.dismiss_popup)
self._popup = Popup(title="Load a file list", content=content, size_hint=(1, 1))
self._popup.open()
def dismiss_popup(self):
self._popup.dismiss()
class ParametersTrainModelWindow(Screen):
pass
class ParametersTrainWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
class OverViewTrainWindow(Screen):
pass
class OverViewTrainModelWindow(Screen):
pass
class OverViewModelWindow(Screen):
pass
class MyOption(SpinnerOption):
pass
kv_main= Builder.load_file('main.kv')
class MyApp(App):
def build(self):
return kv_main
if __name__ == '__main__':
MyApp().run()
main.kv
#:import utils kivy.utils
#:include select.kv
#:include training.kv
#:include model.kv
#:include train_model.kv
#:include parameters_train.kv
#:include parameters_train_model.kv
#:include overview_train_model.kv
#:include overview_train.kv
#:include overview_model.kv
WindowManager:
MainWindow:
SelectWindow:
TrainingWindow:
ModelWindow:
TrainModelWindow:
ParametersTrainWindow:
ParametersTrainModelWindow
OverViewTrainWindow:
OverViewTrainModelWindow:
OverViewModelWindow:
<MainWindow>
name: "main"
GridLayout:
cols: 1
BoxLayout:
orientation: "vertical"
canvas.before:
Color:
rgba: 0,0,0,1
Rectangle:
pos: self.pos
size: self.size
Label:
size_hint: 1, 1
text: "SPECPHASE"
font_size: 50
color:
utils.get_color_from_hex('#FF0000')
Label:
size_hint: 1, 1
text: "Object Detection App"
font_size: 40
BoxLayout:
size_hint: 1, 0.005
canvas.before:
Color:
rgba: (1,1,1,1)
Rectangle:
size: self.size
pos: self.pos
BoxLayout:
orientation: "horizontal"
size_hint: (0.35, 0.35)
padding: (0,0,25,0)
Label:
font_size: 20
text: "Password"
size_hint: (0.5, 0.35)
pos_hint: {'x': 1, 'y': 0.4}
background_color: (0,0,0,1)
canvas.before:
Color:
rgba: self.background_color
Rectangle:
size: self.size
pos: self.pos
TextInput:
id: password
multiline: False
size_hint: (0.5, 0.35)
pos_hint: {'x': 1, 'y': 0.4}
focus: True
background_color:
utils.get_color_from_hex('#18B8D9')
cursor_color: (0,0,0,1)
password: True
Button:
text: "Submit"
on_release: root.login()
select.kv
<SelectWindow#Screen>:
name: "select"
GridLayout:
cols: 1
GridLayout:
cols: 2
Button:
text: "Train"
font_size: 32
on_release:
app.root.current = "training"
root.manager.transition.direction = "right"
Button:
text: "Model"
font_size: 32
on_release:
app.root.current = "model"
root.manager.transition.direction = "left"
Button:
text: "Train & Model"
font_size: 32
on_release:
app.root.current = "train_model"
root.manager.transition.direction = "up"
training.kv
<TrainingWindow#Screen>:
name: "training"
BoxLayout:
orientation: "vertical"
Button:
text: "Select Training Images"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Select Training Annots"
font_size: 32
on_release: root.show_load_list()
Button:
text: "Set Parameters"
font_size: 32
on_release:
app.root.current = "parameters_train"
root.manager.transition.direction = "up"
Button:
text: "Back"
font_size: 16
on_release:
app.root.current = "select"
root.manager.transition.direction = "right"
<LoadDialog>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
BoxLayout:
size_hint_y: None
height: 30
Button:
text: "Cancel"
on_release: root.cancel()
Button:
text: "Load"
on_release: root.load(filechooser.path, filechooser.selection)
After taking a break from this for while and restarting my brain, I was able to find the problem.
Not included in my question, I have a couple more .kv files that have a similar layout to the training.kv. They are used to access other screens. I found that I was calling FileChooserListView in each screen and I belive that is why I was seeing the stacking problem. I ended up removing all of them except for the one in my training.kv file and all is working.
I am currently learning Kivy, and cannot figure out how to change the background colour of the button when it is clicked on. I know the colour changes by default to a shade of blue, but I do not want this to happen. I have the following code...
-----Python Script----
import kivy
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.lang import Builder
class WindowManager(ScreenManager):
pass
class HomeScreen(Screen):
pass
class NotesScreen(Screen):
pass
class PaintingScreen(Screen):
pass
class CalculatorScreen(Screen):
pass
class ContactsScreen(Screen):
pass
class DictionairyScreen(Screen):
pass
kv = Builder.load_file("multi_pages.kv")
class MyApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyApp().run()
----.kv file----
WindowManager:
HomeScreen:
NotesScreen:
PaintingScreen:
CalculatorScreen:
ContactsScreen:
DictionairyScreen:
<HomeScreen>:
name: "home"
FloatLayout:
Button:
text: "Notes"
pos_hint: {"x": .325, "top": .875}
size_hint: .35, .12
font_size: 20
background_color: -1, 1, 1, 1
Button:
text: "Painting"
pos_hint: {"x": .325, "top": .725}
size_hint: .35, .12
font_size: 20
color: 1, 1, 1, 1
background_color: -1, -1, -1, 0.3
on_press:
print("Clicked")
on_release:
print("Released")
on_state:
print("my current state is {}".format(self.state))
Button:
text: "Calculator"
pos_hint: {"x": .325, "top": .575}
size_hint: .35, .12
font_size: 20
Button:
text: "Contacts"
pos_hint: {"x": .325, "top": .425}
size_hint: .35, .12
font_size: 20
Button:
text: "Dictionairy"
pos_hint: {"x": .325, "top": .275}
size_hint: .35, .12
font_size: 20
Any and all help is much appreciated! Thanks
For anyone reading this in the future, I've sorted it, you have to do it in Python. Below is my code...
----.py file---
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import ObjectProperty
from kivy.uix.screenmanager import Screen, ScreenManager
class WindowOne(Screen):
pass
class WindowManager(Screen, ScreenManager):
pass
kv_file = Builder.load_file("style.kv")
class MyApp(App):
def build(self):
return kv_file
if __name__ == "__main__":
MyApp().run()
----.kv file----
WindowManager:
WindowOne:
<WindowOne>:
name: "Home"
btn: btn
btn2: btn2
FloatLayout:
Button:
text: "Hello world"
size_hint: 0.2, 0.2
pos_hint: {"x": 0, "top": 0.4}
background_normal: ""
background_color: 1, .5, 1, 1
id: btn
on_press:
print("Pressed button 1")
btn.background_color = RGB = .1, -.4, 1, 1
on_release:
print("Released button 1")
btn.background_color = RGB = 1, .5, 1, 1
Button:
text: "Goodbye world"
size_hint: .2, .2
pos_hint: {"x": 0.4, "top": 0.4}
background_normal: ""
background_color: .3, 1, -.7, 1
id: btn2
on_press:
print("Pressed button 2")
btn2.background_color = RGB = 1, -1, -.7, 1
on_release:
print("Released button 2")
btn2.background_color = RGB = .3, 1, -.7, 1
I am trying to create a dropdown list that is called when a button is submitted. After the drop down list is called i want the value of the button to be set to the button in the dropdown list that has been selected. I then want to retrieve this value back in my code to carry out some logic. I found this question that has been previously asked and it outlines exactly what i would like to achieve Python, Kivy. Get text from dynamically created buttons with a dropdown. However, i tried incorporating the answer in my code but for some reason the drop down list does not appear. I would really appreciate if someone could help me out and tell me what is it i am doing in correctly.
Scrap.py
from kivy.app import App
from kivy.uix.checkbox import CheckBox
from kivy.uix.button import Button
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.properties import ObjectProperty
from kivy.core.window import Window
from kivy.uix.dropdown import DropDown
import datetime as dt
Window.size = (800,600)
class CustomDropDown(DropDown):
def __init__(self, **kwargs):
super(CustomDropDown, self).__init__(**kwargs)
self.add_buttons()
def add_buttons(self):
for index in range(10):
btn = Button(text='Value %d' % index, size_hint_y=None, height=44)
btn.bind(on_release=lambda btn: self.select(btn.text))
self.add_widget(btn)
class MainWindow(Screen):
check_solid = ObjectProperty(False)
check_water = ObjectProperty(False)
check_boiling = ObjectProperty(False)
s_id = str(dt.datetime.now().strftime("%y%m%d%H%M"))
def btn(self):
print(self.check_solid.state)
print(self.check_water.state)
print(self.check_boiling.state)
class MyScreenManager(ScreenManager):
def Run_Draws_Test(self, value):
print(value)
class Checkbox(CheckBox):
pass
class ScrapApp(App):
title = "Chemistry Sample Requests"
def build(self):
return MyScreenManager()
if __name__ == '__main__':
ScrapApp().run()
scrap.kv
#:import Factory kivy.factory.Factory
<Button>:
size_hint: 0.1,0.1
<Label>:
size_hint: 0.1,0.1
<Checkbox>:
size_hint: 0.1,0.1
<TextInput>:
size_hint: 0.2,0.1
multiline: False
<CustomDropDown>:
on_select:
app.root.ids.MainWindow.ids.mainbutton.text = '{}'.format(args[1])
app.root.Run_Draws_Test(args[1])
<MainWindow>:
orientation: "vertical"
check_solid: solid_check
check_boiling: boiling_check
check_water: water_check
FloatLayout:
Label:
text: "Sample ID: "
pos_hint: {"x":0.05, "top":0.95}
Label:
text: root.s_id
pos_hint: {"x":0.2, "top": 0.95}
Label:
text: "Plant ID: "
pos_hint: {"x":0.05, "top": 0.8}
Button:
id: mainbutton
text: "Choose"
pos: 400,400
size_hint: None,None
size: 150, 50
on_release: Factory.CustomDropDown().open(self)
Label:
text: "Formulation: "
pos_hint: {"x":0.05, "top": 0.65}
TextInput:
id: id_formulation
pos_hint: {"x":0.2, "top": 0.65}
Label:
text: "Solids Test: "
pos_hint: {"x":0.05, "top": 0.5}
Checkbox:
id: solid_check
pos_hint: {"x":0.25, "top": 0.5}
Label:
text: "Water Content Test: "
pos_hint: {"x":0.05, "top": 0.35}
Checkbox:
id: water_check
pos_hint: {"x":0.25, "top": 0.35}
Label:
text: "Boiling Point: "
pos_hint: {"x":0.05, "top": 0.2}
Checkbox:
id: boiling_check
pos_hint: {"x":0.25, "top": 0.2}
Button:
text: "Submit"
pos_hint: {"x": 0.7, "top": 0.5}
on_release: root.btn()
<MyScreenManager>:
canvas.before:
Color:
rgba: 0.5, 0.5, 0.5, 0.5
Rectangle:
pos: 0,0
size: 800, 600
MainWindow:
id: MainWindow
name: 'MainWindow'
I've run into bugs like this before. I don't know if Kivy is working as intended with this or how to fix it. Anyone with more knowledge than me, I'd be glad to hear the reasoning to this.
class CustomDropDown(DropDown):
def __init__(self, **kwargs):
super(CustomDropDown, self).__init__(**kwargs)
self.add_buttons()
def add_buttons(self):
for index in range(10):
#btn = Button(text='Value %d' % index, size_hint_y=None, height=44)
btn = Button(text='Value %d' % index)
btn.size_hint_y = None
btn.height = 44
btn.bind(on_release=lambda btn: self.select(btn.text))
self.add_widget(btn)
These kind of things cause me nothing but frustration.
i am trying to make an app, a game actually that will display random screens when the "NEXT" button is touched, so i made the screens and the labels to be displayed on each screen but i cant get it to display a random screen when the "NEXT" button is touched, it just follows a pattern, would anyone help me here? heres the code:
#: import FadeTransition kivy.uix.screenmanager.FadeTransition
#: import Image kivy.uix.image.Image
#: import SoundLoader kivy.core.audio.SoundLoader
ScreenManagement:
transition: FadeTransition()
MainScreen:
GameScreen:
GameScreen2:
GameScreen3:
GameScreen4:
<Button>:
font_size: 12
size_hint: 0.2, 0.1
<MainScreen>:
name: "main"
FloatLayout:
Button:
text: "START GAME"
color: 1,0,1,1
pos_hint: {"x": 0, "y":0}
on_release: app.root.current = "game"
Button:
text: "QUIT"
color: 1,0,0,1
pos_hint: {"x": .8, "y": 0}
on_release: quit()
Button:
text: "SOUND"
color: 0,1,0,1
pos_hint: {"x":.2 , "y": .4}
on_press: app.play_sound1()
<GameScreen>:
name: "game"
FloatLayout:
Label:
text: "Python\nSnowden\nMr.Robot"
font_size: 40
color: 0,1,0,1
pos_hint: {"x":0, "y": 0}
Button:
text: "Home"
on_release: app.root.current = "main"
color: 1,0,0,1
pos_hint: {"right":1, "top":1}
Button:
text: "Next"
on_release: app.root.current = "game2"
color: 0,1,0,1
pos_hint: {"x":0, "y":0}
<GameScreen2>:
name: "game2"
FloatLayout:
Label:
text: "Banana\n\nOrange\n\nTea\n\nSleep"
font_size: 40
color: 0,1,0,1
pos_hint: {"x":0, "y": 0}
Button:
text: "Home"
on_release: app.root.current = "main"
color: 1,0,0,1
pos_hint: {"right":1, "top":1}
Button:
text: "Next"
on_release: app.root.current = "game3"
color: 0,1,0,1
pos_hint: {"x": 0, "y": 0}
<GameScreen3>:
name: "game3"
FloatLayout:
Label:
text: "Assembly\n\nRuby\n\nC"
font_size: 40
color: 0,1,0,1
pos_hint: {"x":0, "y":0}
Button:
text: "Home"
on_release: app.root.current = "main"
color: 1,0,0,1
pos_hint: {"right":1, "top":1}
Button:
text: "Next"
on_release: app.root.current = "game4"
color: 0,1,0,1
pos_hint: {"x": 0, "y": 0}
<GameScreen4>:
name: "game4"
FloatLayout:
Label:
text: "Prolog\n\nPygame\n\nC++"
font_size: 40
color: 0,1,0,1
pos_hint: {"x":0, "y":0}
Button:
text: "Home"
on_release: app.root.current = "main"
color: 1,0,0,1
pos_hint: {"right":1, "top":1}
the above is the kv code, sorry for the mess im an amateur when it comes to kivy
and heres the python side code:
from kivy.app import App
from kivy.clock import Clock
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.widget import Widget
from kivy.core.audio import SoundLoader
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
class MainScreen(Screen):
pass
class GameScreen(Screen):
pass
class GameScreen2(Screen):
pass
class GameScreen3(Screen):
pass
class GameScreen4(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("quora.kv")
class MainApp(App):
def build(self):
self.load_sounds()
return presentation
def load_sounds(self):
self.sounds = {}
for i in range(10):
fname = 'sound' + str(i+1) + '.wav'
self.sounds[i] = SoundLoader.load(fname)
def play_sound1(self):
sound = self.sounds.get(0)
if sound is not None:
sound.volume = 0.5
sound.play()
def play_sound2(self):
sound = self.sounds.get(1)
if sound is not None:
sound.volume = 0.5
sound.play()
if __name__ == "__main__":
MainApp().run()
this is the sample i made for you because the original one is way bigger than this i dont know how to use somewhat of a LOOP to generate screen so i made more that 20 screens on the original code so, and if you could help me figure out how can i STOP THE MENU SONG when i hit the "START" BUTTON, so that i can hit the "SONG" BUTTON on SCREEN1 to PLAY its SONG i would be gratefull. thanks you for the patience.
Display random screens when the "NEXT" button is touched
Use screen_names
screen_names
List of the names of all the Screen widgets added. The list is
read only.
screens_names is an AliasProperty and is read-only. It is updated
if the screen list changes or the name of a screen changes.
Snippets
#:import choice random.choice
...
Button:
text: "Next"
on_release:
root.manager.current = choice(root.manager.screen_names[1:])
color: 0,1,0,1
pos_hint: {"x":0, "y":0}
Stop / Play Music
You might want to use a ToggleButton instead of Button for playing music. Please refer to the example below.
Example
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.togglebutton import ToggleButton
from kivy.core.audio import SoundLoader
from kivy.properties import ObjectProperty
class MusicScreen(Screen):
enter = ObjectProperty(None)
text_input = ObjectProperty(None)
stop = ObjectProperty(None)
musicbutton = ToggleButton()
class ScreenManagement(ScreenManager):
pass
class MainApp(App):
sound = ObjectProperty(None, allownone=True)
def build(self):
return ScreenManagement()
def on_state(self, state, filename):
print("ONSTATE!!!")
print("\tstate=", state)
if self.sound is None:
self.sound = SoundLoader.load(filename)
# stop the sound if it's currently playing
if self.sound.status != 'stop':
self.sound.stop()
if state == "down":
self.sound.volume = .5
self.sound.play()
else: # if state == "normal":
if self.sound:
self.sound.stop()
# self.sound.unload()
self.sound = None
if __name__ == "__main__":
MainApp().run()
main.kv
#:kivy 1.11.0
<ScreenManagement>:
MusicScreen:
name: 'music'
<MusicScreen>:
text_input: text_input
id: "music"
name: "music"
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
rootpath: "/home/iam/Music/"
on_selection: text_input.text = self.selection and self.selection[0] or ''
TextInput:
id: text_input
size_hint_y: None
height: 50
multiline: False
ToggleButton:
size_hint: 1, .2
text: "Play/Stop By File"
on_state: app.on_state(self.state, text_input.text)
ToggleButton:
id: musicbutton
size_hint: 1, .2
text: "Play/Stop By Title"
on_state: app.on_state(self.state, text_input.text)
I'm new to kivy and I'm trying to create a drag and drop app where if the image is dropped onto the gridlayout the image is shown on the app as shown below. I'm trying to get the file_path of the image and then using the file_path to display it on the gridlayout but unfortunately, that is not working. Any help would be greatly appreciated!
This is the current image
This is what I want after dragging the image
Kv file
# Custom button
<CustButton#Button>:
font_size: 32
background_normal: 'Colour_yellow.png'
background_down: 'Colour_blue.png'
<Cust2#Button>:
font_size: 32
background_normal: 'Colour_red.png'
background_down: 'Colour_blue.png'
<Cust3#Button>:
font_size: 32
background_normal: 'Colour_white.png'
background_down: 'Colour_blue.png'
<Cust4#Button>:
font_size: 32
background_normal: 'Colour_blue.png'
background_down: 'Colour_white.png'
<CalcGridLayout>:
id: calculator
display: entry
rows: 5
padding: 10
spacing: 10
BoxLayout:
spacing: 100
size_hint: .5, None
Cust2:
text: "Whats the intensity you want?"
BoxLayout:
size_hint: .5, None
TextInput:
id: entry
font_size: 70
multiline: False
hint_text: "Type here"
BoxLayout:
spacing: 100
size_hint: .5, None
Cust4:
text: "Drag and Drop picture below:"
on_release: root.build1()
#THIS IS WHERE I'M STUCK ON
BoxLayout:
Image:
source: root._on_file_drop(file_path)
BoxLayout:
size_hint: 1, .3
spacing: 10
CustButton:
text: "Click here for \n reduced size"
CustButton:
text: "Click here for pos \n and intensity of \n each pixel"
on_release: root.reduced_image()
CustButton:
text: "Click here \n for graph"
CustButton:
text: "Click here \n for all"
CustButton:
text: "Extra"
Python file
import kivy
kivy.require("1.9.0")
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
Window.clearcolor = (0.5, 0.5, 0.5, 1)
class CalcGridLayout(GridLayout):
def reduced_image(self):
#ignore
def build1(self):
Window.bind(on_dropfile=self._on_file_drop)
return
def _on_file_drop(self, window, file_path):
print(file_path)
return file_path
class dropdownApp(App):
def build(self):
return CalcGridLayout()
dropApp = dropdownApp()
dropApp.run()
Solution
Please refer to the snippets, and complete example for details.
kv file
Remove on_release: root.build1()
Replace source: root._on_file_drop(file_path) with id: img
Snippet
BoxLayout:
spacing: 100
size_hint: .5, None
Cust4:
text: "Drag and Drop picture below:"
BoxLayout:
Image:
id: img
Python Code
Add import statement, from kivy.properties import StringProperty
Declare property, filePath = StringProperty('') in class CalcGridLayout().
Add constructor to class CalcGridLayout() and move Window.bind(on_dropfile=self._on_file_drop) from build1() method
Remove build1() method
In _on_file_drop() method, replace return file_path with self.filePath = file_path.decode("utf-8") self.ids.img.source = self.filePath and self.ids.img.reload()
Snippet
from kivy.properties import StringProperty
...
class CalcGridLayout(GridLayout):
filePath = StringProperty('')
def __init__(self, **kwargs):
super(CalcGridLayout, self).__init__(**kwargs)
Window.bind(on_dropfile=self._on_file_drop)
def reduced_image(self):
print(self.filePath)
def _on_file_drop(self, window, file_path):
print(file_path)
self.filePath = file_path.decode("utf-8") # convert byte to string
self.ids.img.source = self.filePath
self.ids.img.reload() # reload image
Window ยป on_dropfile Event
on_dropfile(filename)
Event called when a file is dropped on the application.
Warning
This event currently works with sdl2 window provider, on pygame window
provider and OS X with a patched version of pygame. This event is left
in place for further evolution (ios, android etc.)
Example
main.py
import kivy
kivy.require("1.11.0")
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.properties import StringProperty
Window.clearcolor = (0.5, 0.5, 0.5, 1)
class CalcGridLayout(GridLayout):
filePath = StringProperty('')
def __init__(self, **kwargs):
super(CalcGridLayout, self).__init__(**kwargs)
Window.bind(on_dropfile=self._on_file_drop)
def reduced_image(self):
print(self.filePath)
def _on_file_drop(self, window, file_path):
print(file_path)
self.filePath = file_path.decode("utf-8") # convert byte to string
self.ids.img.source = self.filePath
self.ids.img.reload() # reload image
class DragDropApp(App):
def build(self):
return CalcGridLayout()
if __name__ == "__main__":
DragDropApp().run()
dragdrop.kv
#:kivy 1.11.0
# Custom button
<CustButton#Button>:
background_normal: "/home/iam/Pictures/AppImages/Colors/yellow.png" # 'Colour_yellow.png'
background_down: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
text_size: self.size
halign: 'center'
valign: 'middle'
<Cust2#Button>:
font_size: 32
background_normal: "/home/iam/Pictures/AppImages/Colors/red.png" # 'Colour_red.png'
background_down: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
<Cust3#Button>:
font_size: 32
background_normal: "/home/iam/Pictures/AppImages/Colors/white.png" # 'Colour_white.png'
background_down: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
<Cust4#Button>:
font_size: 32
background_normal: "/home/iam/Pictures/AppImages/Colors/blue.png" # 'Colour_blue.png'
background_down: "/home/iam/Pictures/AppImages/Colors/white.png" # 'Colour_white.png'
<CalcGridLayout>:
id: calculator
display: entry
rows: 5
padding: 10
spacing: 10
BoxLayout:
spacing: 100
size_hint: .5, None
Cust2:
text: "Whats the intensity you want?"
BoxLayout:
size_hint: .5, None
TextInput:
id: entry
font_size: 70
multiline: False
hint_text: "Type here"
BoxLayout:
spacing: 100
size_hint: .5, None
Cust4:
text: "Drag and Drop picture below:"
BoxLayout:
Image:
id: img
BoxLayout:
size_hint: 1, .3
spacing: 10
CustButton:
text: "Click here for \n reduced size"
CustButton:
text: "Click here for pos \n and intensity of \n each pixel"
on_release: root.reduced_image()
CustButton:
text: "Click here \n for graph"
CustButton:
text: "Click here \n for all"
CustButton:
text: "Extra"
Output