I am creating myself a password generator and I have run across this issue. I have put two checkboxes and one text input. Wherever I click on the screen, it deactivates/activates the bottom-most checkbox. You could run my code (it's the full code, nothing excluded) and see what happens.
.py
from kivy.app import App
from kivy.uix.screenmanager import Screen, ScreenManager
import string
sm = ScreenManager()
class main(Screen):
def generate(self):
include_num = self.ids.include_num.active
include_special = self.ids.include_special.active
letters = list(string.ascii_letters)
special = list(string.punctuation)
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
if self.ids.len_of_password.text:
pass
else:
self.ids.len_of_password.text = 'NEEDED'
class MyApp(App):
def build(self):
sm.add_widget(main(name='main'))
return sm
if __name__ == '__main__':
MyApp().run()
^^ I still haven't put the logic in because of the issue, please do not focus on giving me the logic. Rather, I am looking for a solution for the multiple checkboxes issue.
.kv
<main>
FloatLayout:
Label:
text: 'Length:'
font_size: 70
pos_hint: {'right': 0.85,'y': 0.3}
TextInput:
multiline: False
id: len_of_password
text: '20'
size_hint: 0.3, 0.15
font_size: self.height / 4 * 3
pos_hint: {'x': 0.55, 'y': 0.725}
Label:
text: 'Include numbers?'
font_size: 45
pos_hint: {'right': 0.85, 'y': 0.1}
CheckBox:
active: True
pos_hint: {'x': 0.2, 'y': 0.1}
id: include_num
Label:
text: 'Include special characters?'
font_size: 35
pos_hint: {'right': 0.85, 'top': 0.95}
CheckBox:
active: True
pos_hint: {'x': 0.2, 'top': 0.95}
id: include_special
Button:
text: 'Generate'
font_size: (self.height - len(self.text) * 2) / 2
size_hint: 0.5, 0.2
pos_hint: {'x': 0.25, 'y': 0.1}
on_release: root.generate()
Help is appreciated!
The problem is that the CheckBox is filling the entire main Screen. That happens because the default size_hint is (1,1). Try setting a size_hint for all the widgets in your kv.
Related
So I am making a notes app as a part of a bigger app. What I want is that every time before the user enters the screen, all the existing notes will be fetched from MongoDB and displayed.
Initially, I tried it with just a on_pre_enter event but then every time the I went to a different screen and came back, the last note from the database got written again on top of the existing labels.
So, then I added a on_pre_leave function but now what happens is that the first time, notes get displayed. But if you leave and come back, the whole screen is empty.
Any suggestions would be appreciated.
Current code:
class Reminders(Screen):
collection = db['Notes']
def on_pre_enter(self, *args):
records = self.collection.find({})
for record in records:
existing_lbl = Label(text=record['Note'],
size_hint=(0.2, None), text_size=(self.width, None))
self.ids.layout.add_widget(existing_lbl)
def on_leave(self, *args):
self.ids.layout.clear_widgets()
def add_note(self):
sm.switch_to(screens[6], direction='left')
def go_back(self):
sm.switch_to(screens[0], direction='right')
.kv file:
< Reminders >:
name: 'Reminders'
FloatLayout:
Label:
text: "Notes"
color: (0, 0.702, 0, 1)
font_size: 50
pos_hint: {'x': 0.1, 'top': 1}
size_hint: 0.2, 0.2
Button:
size_hint: 0.07, 0.07
background_normal: 'plus.png'
pos_hint: {'x': 0.78,'top': 0.94}
on_release: root.add_note()
ScrollView:
size_hint: 0.96, 0.6
pos_hint: {'x': 0.02, 'top': 0.7}
StackLayout:
id: layout
orientation: 'tb-lr'
SmoothButton:
text: "Back"
pos_hint: {'x': 0.8, 'top': 0.15}
size_hint: 0.15, 0.05
on_release: root.go_back()
Hows it going guys. I have been looking for two days now and I cant seem to connect the dots. Please forgive me I am somewhat experienced with python but OOP concepts are still a little unclear. I have seen a couple similar posts but the python is a little over my head.
What I am trying to do is set the temperature (and eventually humidity) in a separate screen (Button called Set Temp). Then have that set temp value from that screen show up on my main screen. I tried to tie the temperature value to a global variable (tep). Then when one would hit main menu button (within the set temp screen) and call a method within the main screen class that would reference that global tep variable. But when I do this nothing happens. I have tired to call it by ID, create a method within the main menu to explicitly update that variable but to no avail and vice versa but nothing seems to work. I tried looking how to refresh the screen but the examples were over my head. If someone could shed some light on this issue that would be awesome.
Thanks for taking the time to read my post!
python file
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.core.window import Window
from kivy.properties import ObjectProperty
from random import randint
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
Window.size = (600,250)
tep = 75
# Window Manager Class
class WindowManager(ScreenManager):
pass
# Main home menu Class
class MyTerrLayout(Screen):
internal_read = ObjectProperty(None)
external_read = ObjectProperty(None)
target_temp = ObjectProperty(None)
target_hum = ObjectProperty(None)
def set_temp(self):
global tep
self.ids._Target_Temp.text = str(tep)
print(str(tep))
# Temprature Screen Class / Window
class TempWindow(Screen):
temp_menu = ObjectProperty(None)
def sub_temp(self):
global tep
tep = tep - 1
self.temp_menu.text = str(tep)
def add_temp(self):
global tep
tep = tep + 1
self.temp_menu.text = str(tep)
def set_temp(self):
MyTerrLayout().set_temp()
# Humidity Class / Window
class HumWindow(Screen):
pass
# Builder Section
kv = Builder.load_file('terrlayoutV1.kv')
class TerrLayout(App):
def build(self):
return kv
if __name__=="__main__":
TerrLayout().run()
Kivy File
#:kivy 1.0.9
WindowManager:
MyTerrLayout:
TempWindow:
HumWindow:
<MyTerrLayout>:
name: "main"
internal_read: internal_reading
external_read: external_reading
target_temp: _Target_Temp
target_hum: _Target_Hum
GridLayout:
cols:2
RelativeLayout:
Label:
id: _internal
text: 'Internal Temp/Humidity'
size_hint: 0.5 , .166
pos_hint: {'x': .25, 'top': 1}
Label:
text: 'Target:'
font_size: 15
size_hint: 0.125 , .166
pos_hint: {'x': 0.1, 'top': 0.834}
Label:
id: _Target_Temp
size_hint: 0.125 , .166
pos_hint: {'x': .25, 'top': 0.834}
Label:
id: _Target_Hum
size_hint: 0.125 , .166
pos_hint: {'x': .38, 'top': 0.834}
Label:
text: 'Current:'
size_hint: 0.125 , .166
pos_hint: {'x': .55, 'top': 0.834}
Label:
id: internal_reading
text: '25C/35%'
size_hint: 0.125 , .166
pos_hint: {'x': .75, 'top': 0.834}
Label:
id: _external
text: 'External Temp/Humidity'
size_hint: 0.5, .166
pos_hint: {'x': .25, 'top': 0.668}
Label:
id: external_reading
size_hint: 0.5, .166
pos_hint: {'x': .25, 'top': 0.502}
Label:
id: _heatbed
text: 'Heatbed Temprature'
size_hint: 0.5, .166
pos_hint: {'x': 0.25, 'top': 0.336}
Label:
id: heatbed_reading
text: '80C'
size_hint: 0.5, .166
pos_hint: {'x': 0.25, 'top': 0.17}
StackLayout:
orientation: 'rl-tb'
spacing: 1.5
Button:
id: _Set_Temp
text: 'Set Temp'
size_hint: [.5, .25]
on_release: app.root.current = "Temp"
Button:
id: _Set_Hum
text: 'Set Humidity'
size_hint: [.5, .25]
on_release: app.root.current = "Hum"
Button:
id: _Set_Fan
text: 'Set Fan Time'
size_hint: [.5, .25]
Button:
id: _Set_Light
text: 'Set Light Time'
size_hint: [.5, .25]
Button:
id: _Tog_Light
text: 'Toggle Light'
size_hint: [.5, .25]
Button:
id: _Tog_Fan
text: 'Toggle Fan'
size_hint: [.5, .25]
Button:
id: _Dis_Mode
text: 'Display Mode'
size_hint: [1, .25]
<TempWindow>:
name: "Temp"
temp_menu: set_tep_menu
GridLayout:
cols: 2
Label:
id: set_tep_menu
size_hint: 1, .5
font_size: 32
StackLayout:
orientation: 'rl-tb'
Button:
text: "Increase Temp"
on_press: root.add_temp()
size_hint: [1, .3]
Button:
text: "Decrease Temp"
on_press: root.sub_temp()
size_hint: [1, .3]
Button:
text: "Main Menu"
on_release: app.root.current = "main"
on_release: root.set_temp() #calling method to set temp
size_hint: [1, .3]
<HumWindow>:
name: "Hum"
Button:
text: "Humidity"
on_release: app.root.current = "main"
Your code:
def set_temp(self):
MyTerrLayout().set_temp()
is creating a new instance of MyTerrLayout and calling set_temp() on that instance. However, that new instance of MyTerrLayout is not part of your GUI, so no changes are visible. To actually change your GUI, you need to call the set_temp() method of the MyTerrLayout instance that is in your GUI. To do that, change the set_temp() method of TempWindow to:
def set_temp(self):
terrLayout = self.manager.get_screen('main')
terrLayout.set_temp()
Based on an input (0, 1, 2 or 3) the kv.file or py.file should add a group of Toggle Buttons to the already existing layout. I tried a lot but can't seem to figure it out and would love some advice, since it is all still a bit new to me.
So when self.reminder() = 0, no Toggle Buttons are shown.
When self.reminder() = 1, one group of Toggle Buttons is shown.
When self.reminder() = 2, two groups of Toggle Buttons are shown.
When self.reminder() = 3, three groups of Toggle Buttons are shown.
self.reminder() will not excess the value of 3.
So I have got my .py file
import kivy
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
import csv
from kivy.core.window import Window
class WindowManager(ScreenManager):
pass
#Backgroundcolour
Window.clearcolor = (0.67, 0.83, 0.88, 1)
class DiaryToday(Screen):
user_id = 3
# reads how many reminders (aka Toggle Buttons) the user wants from csv file
# used for textlabel, this textlabel will not show if reminder == 0 (is stated in kv file)
def reminder(self):
with open('users.csv') as file: #TO DO: needs to be adjusted to global ID
reader = csv.DictReader(file)
for row in reader:
if row['id'] == str(self.user_id): #TO DO: needs to be adjusted to global ID
if row['mood_rem'] == 'Zero':
return(0)
else:
return(row['mood_rem'][0])
# TO DO: STORES in CSV file which emoji you clicked
def mood_value(self, mood):
print (mood)
#Takes care of which group of ToggleButtons is shown in the Diary Screen
def add(self):
if root.reminder() == 0:
#should add or show no Toggle Buttons
if root.reminder() == 1:
#should add or show 1 set of Toggle Buttons
if root.reminder() == 2:
#should add or show 2 sets of Toggle Buttons
if root.reminder()== 3:
#should add or show 3 sets of Toggle Buttons
class LoopApp(App):
def build(self):
return DiaryToday()
if __name__ == '__main__':
LoopApp().run()
And my .kv file
<DiaryToday>:
name: "diarytoday"
answer: answer
diaryinput: diaryinput
id: test
FloatLayout:
Button:
background_color: 0.1, 0.5, 0.6, 1
pos_hint:{'center_y':0.05, 'center_x': 0.5}
font_size: 18
size_hint: 0.1, 0.05
text: "Save"
Button:
pos_hint:{'center_y':0.95, 'center_x': 0.175}
background_color: 0.1, 0.5, 0.6, 1
font_size: 18
size_hint: 0.15, 0.05
text: "Previous day"
Label:
pos_hint:{'center_y':0.95, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
text: 'date'
font_size: 22
Label:
pos_hint:{'center_y':0.87, 'center_x': 0.5}
font_size: 18
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
text: 'Question'
TextInput:
font_size: 14
size_hint: 0.8, 0.1
pos_hint:{'center_y':0.78, 'center_x': 0.5}
id: answer
Label:
pos_hint:{'center_y':0.67, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
font_size: 18
text: 'My Diary'
TextInput:
font_size: 14
size_hint: 0.8, 0.22
pos_hint:{'center_y':0.51, 'center_x': 0.5}
id: diaryinput
Label:
pos_hint:{'center_y':0.36, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
font_size: 18
text: ' ' if root.reminder() == 0 else 'How are you feeling?'
BoxLayout:
id: ToggleButtonGroup1
pos_hint: {'center_y':0.26, 'center_x': 0.5}
size_hint: 0.5, 0.1
ToggleButton:
background_normal: 'VerysadEmoji1.png'
background_down: 'VerysadEmoji2.png'
group: "emojis"
size_hint: 0.5, 1.3
on_press: root.mood_value(1)
ToggleButton:
background_normal: 'SadEmoji1.png'
background_down: 'SadEmoji2.png'
group: "emojis"
size_hint: 0.5, 1.3
on_press: root.mood_value(2)
ToggleButton:
background_normal: 'MediumEmoji1.png'
background_down: 'MediumEmoji2.png'
group: "emojis"
size_hint: 0.5, 1.3
on_press: root.mood_value(3)
ToggleButton:
background_normal: 'HappyEmoji1.png'
background_down: 'HappyEmoji2.png'
group: "emojis"
size_hint: 0.5, 1.3
on_press: root.mood_value(4)
ToggleButton:
background_normal: 'VeryHappyEmoji1.png'
background_down: 'VeryHappyEmoji2.png'
group: "emojis"
size_hint: 0.5, 1.3
on_press: root.mood_value(5)
Label:
pos_hint:{'center_y':0.19, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
font_size: 18
text: "Here will come Toggle Button Group 2"
Label:
pos_hint:{'center_y':0.12, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
font_size: 18
text: "Here will come Toggle Button Group 3"
Thanks!
You can define a class that is the Toggle Button Group that you want to add. Something like this:
class SomeToggles(BoxLayout):
group = StringProperty('') # this will be the group for the ToggleButtons
Then the add() method can be:
#Takes care of which group of ToggleButtons is shown in the Diary Screen
def add(self):
if self.reminder() == 0:
print('0')
#should add or show no Toggle Buttons
if self.reminder() == 1:
print('1')
self.ids.toggles.add_widget(SomeToggles(group=str(self.grp_count)))
self.grp_count += 1
#should add or show 1 set of Toggle Buttons
if self.reminder() == 2:
print('2')
#should add or show 2 sets of Toggle Buttons
if self.reminder()== 3:
print('3')
#should add or show 3 sets of Toggle Buttons
The above only handles the case where self.reminder() returns 1, but the others would be similar. Of course, the grp_count (which is just a construct of mine to define the group property) needs to be added:
class DiaryToday(Screen):
grp_count = 0
For this to work, a container with id of toggles must be defined. This will be another BoxLayout that contains the first set of Toggle Buttons as well as the added ones. So the modified kv file looks like:
<DiaryToday>:
name: "diarytoday"
answer: answer
diaryinput: diaryinput
id: test
FloatLayout:
Button:
background_color: 0.1, 0.5, 0.6, 1
pos_hint:{'center_y':0.05, 'center_x': 0.5}
font_size: 18
size_hint: 0.1, 0.05
text: "Save"
Button:
pos_hint:{'center_y':0.95, 'center_x': 0.175}
background_color: 0.1, 0.5, 0.6, 1
font_size: 18
size_hint: 0.15, 0.05
text: "Previous day"
Label:
pos_hint:{'center_y':0.95, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
text: 'date'
font_size: 22
Label:
pos_hint:{'center_y':0.87, 'center_x': 0.5}
font_size: 18
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
text: 'Question'
TextInput:
font_size: 14
size_hint: 0.8, 0.1
pos_hint:{'center_y':0.78, 'center_x': 0.5}
id: answer
Label:
pos_hint:{'center_y':0.67, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
font_size: 18
text: 'My Diary'
TextInput:
font_size: 14
size_hint: 0.8, 0.22
pos_hint:{'center_y':0.51, 'center_x': 0.5}
id: diaryinput
Label:
pos_hint:{'center_y':0.36, 'center_x': 0.5}
size_hint: 0.1, 0.05
color: 0.1, 0.5, 0.6, 1
font_size: 18
text: ' ' if root.reminder() == 0 else 'How are you feeling?'
BoxLayout: # this contains all the Toggle Button groups
id: toggles
orientation: 'vertical'
pos_hint: {'center_y':0.26, 'center_x': 0.5}
size_hint_y: None
height: self.minimum_height
BoxLayout:
id: ToggleButtonGroup1
pos_hint: {'center_y':0.26, 'center_x': 0.5}
size_hint: 0.5, None
height: self.minimum_height
ToggleButton:
background_normal: 'VerysadEmoji1.png'
background_down: 'VerysadEmoji2.png'
group: "emojis"
size_hint: 0.5, None
height: 40
on_press: root.mood_value(1)
ToggleButton:
background_normal: 'SadEmoji1.png'
background_down: 'SadEmoji2.png'
group: "emojis"
size_hint: 0.5, None
height: 40
on_press: root.mood_value(2)
ToggleButton:
background_normal: 'MediumEmoji1.png'
background_down: 'MediumEmoji2.png'
group: "emojis"
size_hint: 0.5, None
height: 40
on_press: root.mood_value(3)
ToggleButton:
background_normal: 'HappyEmoji1.png'
background_down: 'HappyEmoji2.png'
group: "emojis"
size_hint: 0.5, None
height: 40
on_press: root.mood_value(4)
ToggleButton:
background_normal: 'VeryHappyEmoji1.png'
background_down: 'VeryHappyEmoji2.png'
group: "emojis"
size_hint: 0.5, None
height: 40
on_press: root.mood_value(5)
<SomeToggles>:
pos_hint: {'center_y':0.26, 'center_x': 0.5}
size_hint: 0.5, None
height: self.minimum_height
ToggleButton:
group: root.group
size_hint: 0.5, None
height: 40
ToggleButton:
group: root.group
size_hint: 0.5, None
height: 40
ToggleButton:
group: root.group
size_hint: 0.5, None
height: 40
The above kv also includes the <SomeToggles> rule that defines how the new Toggle Button group is built. You will also need to provide a mechanism for calling self.reminder(). I just added that call to the mood_value() method.
I am new to both Python and Kivy. We are developping this application for an assignment and I am working on the preferences page. My labels, textinputs, togglebuttons and button are all in the right place and working, but I am struggling with how I can get the output of these buttons.
Basically, I would like to print the output like this, when someone presses the confirm button:
Name: Blabla
Mood reminders: 2 per day
Diary reminders: 1 per day
I figured on_press would not work since that would print a value everytime a button is pressed instead of only when confirm is pressed.
Right now my .py code looks like this
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
# Builder.load_file('preferences.kv')
class MyFloatLayout(FloatLayout):
name = ObjectProperty(None)
def mood_buttons(self):
pass
def diary_buttons(self):
pass
def print_specs(self):
print("Name: " + self.name.text
class PreferencesApp(App):
def build(self):
return MyFloatLayout()
if __name__ == '__main__':
PreferencesApp().run()
And my .kv language file looks like this
<Label>
font_size: 20
<TextInput>
font_size: 20
<Checkbox>
size_hint_x: .20
<MyFloatLayout>:
name: name
FloatLayout:
Label:
text: "Name: "
size_hint: 0.4, 0.08
pos_hint:{"x": 0.1, "center_y": 0.85}
TextInput:
id: name
multiline: False
size_hint: 0.4, 0.07
pos_hint:{"x":0.5,"center_y":0.85}
Label:
text: "How many mood reminders would you like?"
size_hint: 0.5, 0.1
pos_hint: {"center_x": 0.5, "top": 0.75}
BoxLayout:
pos_hint: {'center_x': 0.5, 'y': 0.55}
size_hint: 0.8, 0.1
ToggleButton:
text:"Zero"
id: m0
group: "mood_popups"
on_press: self.mood_buttons()
ToggleButton:
text:"1 per day"
id: m1
group: "mood_popups"
ToggleButton:
text:"2 per day"
id: m2
group: "mood_popups"
ToggleButton:
text:"3 per day"
id: m3
group: "mood_popups"
Label:
text: "How many diary reminders would you like?"
size_hint: 0.5, 0.1
pos_hint: {"center_x": 0.5, "top": 0.55}
BoxLayout:
pos_hint: {'center_x': 0.5, 'y': 0.35}
size_hint: 0.8, 0.1
ToggleButton:
text:"Zero"
id: d0
group: "diary_popups"
ToggleButton:
text:"1 per day"
id: d1
group: "diary_popups"
ToggleButton:
text:"1 per two days"
id: d2
group: "diary_popups"
ToggleButton:
text:"1 per week"
id: d3
group: "diary_popups"
Button:
text: 'Confirm'
size_hint: 0.5, 0.1
pos_hint: {"x": 0.25, "top": 0.2}
on_press: root.print_specs()
You can access all the Buttons in a group using the get_widgets() method. So your print_specs() method can be:
def print_specs(self):
print("Name: " + self.name.text)
# get mood reminder
mood_reminder = ''
for toggle in ToggleButton.get_widgets('mood_popups'):
if toggle.state == 'down':
mood_reminder = toggle.text
break
print('Mood reminders:', mood_reminder)
# get diary reminder
diary_reminder = ''
for toggle in ToggleButton.get_widgets('diary_popups'):
if toggle.state == 'down':
diary_reminder = toggle.text
break
print('Diary reminders:', diary_reminder)
I am creating an app with Screen Manager.
I want to get text input from one screen click Next and then use it in a label for another screen and save the value as a global variable.
My question is: How to make it work, because it doesn't work the way I want it to. The label is always 0 and is never the value I type in. The value of the global variable never changes.
main.py file:
from kivy.app import App
from kivy.properties import StringProperty, NumericProperty, ObjectProperty
from kivy.uix.screenmanager import ScreenManager, Screen
global var
var = 0
class FirstScreen(Screen):
global var
def SaveResult(self, text):
global var
g = int(text)
return var
class SecondScreen(Screen):
global var
a = NumericProperty('')
a = str(var)
and my test.kv
ScreenManager:
id: screen_manager
FirstScreen:
id: screen1
name: "FirstScreen"
manager: screen_manager
SecondScreen:
id: screen2
name: "SecondScreen"
manager: screen_manager
<FirstScreen>:
FloatLayout:
canvas.before:
Color:
rgba: 0.1, 0.1, 0.1, 1
Rectangle:
# self here refers to the widget i.e BoxLayout
pos: self.pos
size: self.size
TextInput:
id: text_input
multiline: False
size_hint_x: .4
size_hint_y: .1
pos_hint: {'x': .1, 'y': .20}
Button:
background_color: 0.2, 0.7, 1, 1,
font_size: root.width / 15
id: btn1
text: "Next"
on_press:
root.SaveResult(text_input.text)
root.manager.current = 'SecondScreen'
size_hint_x: .4
size_hint_y: .1
pos_hint: {'x': .5, 'y': .20}
<SecondScreen>:
FloatLayout:
canvas.before:
Color:
rgba: 0.1, 0.1, 0.1, 1
Rectangle:
# self here refers to the widget i.e BoxLayout
pos: self.pos
size: self.size
Label:
color: 0.2, 0.7, 1, 1,
font_size: root.width / 15
id: lb1
text: root.a
size_hint_x: .4
size_hint_y: .2
pos_hint: {'x': .3, 'y': .8}