I'm trying to add in a helper text in Kivy Md which pops up if an invalid password is entered. However the helper text that I use is quite long and therefore doesn't fit. Does anyone know how I can move it or make it fit somehow. Below is an image of my issue:
Below is the relevant section of code:
def AddToRecord(self, email, passw, name, cpass):
email.error = False
passw.error = False
name.error = False
cpass.error = False
NewEmail = email.text
NewName = name.text
NewPassword = passw.text
ConfirmPassword = cpass.text
if len(NewName) and len(NewEmail) and len(NewPassword) and len(ConfirmPassword)> 0:
if (len(NewPassword)>8 and any(char in (set(string.punctuation)) for char in (NewPassword)) and
any(char in (set(string.punctuation)) for char in (NewPassword)) and
any(char in (set(string.ascii_uppercase)) for char in (NewPassword)) and
any(char in (set(string.ascii_lowercase)) for char in (NewPassword)) and
any(char in (set(string.digits)) for char in (NewPassword))):
if NewPassword == ConfirmPassword:
# Connect to or create a new database
conn = sqlite3.connect('UserRecords.db')
# Create a cursor object to execute SQL commands
cursor = conn.cursor()
# Create a table to store the records
cursor.execute('''CREATE TABLE IF NOT EXISTS users (name TEXT, email TEXT, password TEXT)''')
# Insert the user's information into the table
cursor.execute("INSERT INTO users (name, email, password) VALUES (?, ?, ?)", (NewName, NewEmail, NewPassword))
# Committing the changes and closing the connection to the database file
conn.commit()
conn.close()
else:
cpass.helper_text = "The passwords you have entered do not match"
cpass.error = True
else:
passw.helper_text = """Your password needs to be a minium of 8 characters and must
contain a number, lowercase letter, upper case letter and special character (#!#$, ETC)"""
passw.error = True
else:
if len(NewName) <1 and len(NewEmail) >0:
name.error = True
elif len(NewPassword) <1 and len(NewEmail) >0:
passw.helper_text = "This is a required feild"
passw.error = True
elif len(ConfirmPassword) <1 and len(NewEmail) >0:
cpass.helper_text = "This is required field"
cpass.error = True
Below is the relevant section of KV file:
<SignupScreen>:
ScrollView:
FloatLayout:
size_hint: (1, 1.3)
MDIconButton:
icon: "keyboard-backspace"
pos_hint: {"center_x": 0.35, "center_y": 0.97}
on_release:
root.manager.current = "menu"
Image:
source: "Images/RegisterImage.png"
size_hint_x: 0.4
size_hint_y: 0.75
allow_stretch: True
pos_hint: {"center_x": 0.5, "center_y": 0.75}
MDLabel:
text: "Sign up"
halign: "center"
pos_hint: {"center_x": 0.387, "center_y": 0.54}
font_size: 30
font_style: "H5"
EmailField:
id: email_widget
hint_text: "Email"
pos_hint: {"center_x": 0.5, "center_y": 0.48}
size_hint_x: None
width: "250dp"
NameField:
id: name_widget
hint_text: "Name"
pos_hint: {"center_x": 0.5, "center_y": 0.39}
size_hint_x: None
width: "250dp"
PasswordField:
id: passw_widget
size_hint_x: None
width: "250dp"
hint_text: "Password"
pos_hint: {"center_x": 0.5, "center_y": 0.3}
ConfirmPasswordField:
id: cpass_widget
size_hint_x: None
width: "250dp"
hint_text: "Confirm Password"
pos_hint: {"center_x": 0.5, "center_y": 0.21}
MDFillRoundFlatButton:
text: "Sign up"
pos_hint: {"center_x": 0.5, "center_y": 0.12}
md_bg_color: 0.3607, 0.3882, 1
size_hint: 0.3, 0
on_release:
app.AddToRecord(root.ids.email_widget.ids.email_field, root.ids.passw_widget.ids.text_field, root.ids.name_widget.ids.name_field,
root.ids.cpass_widget.ids.text_field)
MDLabel:
text: "by continuing you agree to the"
font_size: 15
halign: 'center'
pos_hint: {"center_y": 0.08}
MDTextButton:
text: "Terms and Conditions"
font_size: 15
pos_hint: {"center_x": 0.5, "center_y": 0.066}
theme_text_color: "Custom"
text_color: 0.3607, 0.3882, 1
#Custom buttons and text fields are located below
<PasswordField>:
size_hint_y: None
height: text_field.height
MDTextField:
id: text_field
hint_text: root.hint_text
text: root.text
password: True
icon_left: "lock"
##need to try and fix this helper text, attempt below. It is labeled attempt 1
helper_text: "Your password needs to be a minium of 8 characters and must contain a number, lowercase letter, upper case letter and special character (#!#$, ETC)"
helper_text_mode: "on_error"
MDIconButton:
icon: "eye-off"
pos_hint: {"center_y": .5}
pos: text_field.width - self.width + dp(8), 0
theme_text_color: "Hint"
on_release:
self.icon = "eye" if self.icon == "eye-off" else "eye-off"
text_field.password = False if text_field.password is True else True
##this label needs to be fixed or alternative solution's - attempt 1
#MDLabel:
#id: passw_helper
#text: ""
#font_size: 20
#halign: 'left'
#pos_hint: {"center_y": -0.1}
<ConfirmPasswordField>:
size_hint_y: None
height: text_field.height
MDTextField:
id: text_field
hint_text: root.hint_text
text: root.text
password: True
icon_left: "lock"
helper_text: ""
helper_text_mode: "on_error"
MDIconButton:
icon: "eye-off"
pos_hint: {"center_y": .5}
pos: text_field.width - self.width + dp(8), 0
theme_text_color: "Hint"
on_release:
self.icon = "eye" if self.icon == "eye-off" else "eye-off"
text_field.password = False if text_field.password is True else True
<EmailField>:
size_hint_y: None
height: email_field.height
MDTextField:
id: email_field
hint_text: root.hint_text
text: root.text
icon_left: "email"
helper_text: "Please enter a valid email"
validator: "email"
helper_text_mode: "on_error"
<NameField>:
size_hint_y: None
height: name_field.height
MDTextField:
id: name_field
hint_text: root.hint_text
text: root.text
icon_left: "account"
helper_text: "This is a required field"
helper_text_mode: "on_error"
Any help is much appreicated!
Try adding line breaks in your error string. This way will you can control how the line wraps.
ie.
helper_text: "Your password needs to be a minium of 8 characters \nand must contain a number, lowercase letter, upper case \nletter and special character (#!#$, ETC)"
helper_text_mode: "on_error"
This still won't fit inside the box but at least it will look better.
Related
How can I change the mouse pointer to 'hand' when hovering over a button present in a screen along with a different widget in kivy python?
I tried creating two functions in a python file. But it changes the mouse cursor for the entire page. How can I change the cursor for just the button present on the page?
#Kivy design file
<Loginpage>:
name: "login"
Image:
source: 'background.jpg'
allow_stretch: True
keep_ratio: False
Screen:
MDCard:
size_hint: None,None
size: 400, 550
pos_hint: {"center_x":0.5,"center_y":0.5}
elevation: 10
padding: 25
spacing: 25
orientation: 'vertical'
MDLabel:
id: welcome_label
text: "Welcome"
font_size: 40
halign: 'center'
size_hint_y: None
height: self.texture_size[1]
padding_y:15
font_style: 'H2'
MDTextField:
id: uid
hint_text: "Username"
icon_right: "account"
size_hint_x: None
width: 200
font_size: 20
pos_hint: {"center_x": 0.5}
MDTextField:
id: pwd
hint_text: "Password"
icon_right: "lock"
size_hint_x: None
width: 200
font_size: 20
pos_hint: {"center_x": 0.5}
password: True
MDRoundFlatButton:
text: "LOG IN"
font_size: 12
pos_hint: {"center_x": 0.5}
on_press: root.logger()
MDRoundFlatButton:
text: "CLEAR"
font_size: 12
pos_hint: {"center_x": 0.5}
on_press: root.clear()
MDLabel:
id: login_label
text: "Invalid Login"
font_size: 14
halign: 'center'
size_hint_y: None
height: self.texture_size[1]
pos_hint: {"center_x": 0.5}
padding_y:15
theme_text_color:'Custom'
text_color: 1,0,0,1
Widget:
size_hint_y: None
height: 10
Python File:
class Loginpage(Screen):
def enter(self, *args):
Window.set_system_cursor('hand')
class Loginpage(Screen):
def enter(self, *args):
Window.set_system_cursor('hand')
def leave(self, *args):
Window.set_system_cursor('arrow')
def logger(self):
'''code to login'''
I'm stuck in this problem, I'm using a dialog so that the user can change his password but i cant access the textfield text from the DashboardGerente class...
main.py
class Content(BoxLayout):
old_pass_tf = ObjectProperty()
new_pass_tf = ObjectProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.app = MDApp.get_running_app()
def show_passnew(self,widget):
if widget.state == "normal":
self.ids.new_pass.password = True
else:
self.ids.new_pass.password = False
def show_passold(self,widget):
if widget.state == "normal":
self.ids.old_pass.password = True
else:
self.ids.old_pass.password = False
class DashboardGerente(Screen):
dialog = None
cont = Content()
def Logout(self):
wm = MDApp.get_running_app().root
wm.current = "Login"
def teste(self):
print(Login.username)
def show_alert_dialog(self):
if not self.dialog:
self.dialog = MDDialog(
title = "Alterar palavra-passe",
text = "Palavra-passe antiga",
content_cls=Content(),
type="custom",
buttons=[
MDFlatButton(
text="Cancelar",
text_color=rgba(0,0,0,1),
on_release = self.cancelar
),
MDFlatButton(
text="Alterar",
text_color = rgba(0,0,0,1),
on_release = self.change_pass
),
],
)
self.dialog.open()
def cancelar(self,obj):
self.dialog.dismiss()
def change_pass(self, obj):
#i want to access the textfield text here
pass
.kv file
<Content>:
orientation: "vertical"
spacing: "12dp"
size_hint_y: None
height: "120dp"
id: content_dialog_change_pass
MDTextField:
id: old_pass
hint_text: "Palavra-passe antiga"
mode: "rectangle"
required: False
color: 1, 0, 1, 1
line_color_focus: 0.5, 0, 1, 1
icon_right: "shield-key"
size_hint: .9, None
password: True
GridLayout:
cols:2
MDCheckbox:
on_press: root.show_passold(self)
size_hint: None, None
height: 5
width: 20
MDLabel:
text: "Mostrar Palavra-passe"
font_size: "13px"
color: 0,0,0,.4
MDTextField:
id: new_pass
hint_text: "Palavra-passe nova"
mode: "rectangle"
required: False
color: 1, 0, 1, 1
line_color_focus: 0.5, 0, 1, 1
icon_right: "shield-key"
size_hint: .9, None
password: True
GridLayout:
cols:2
MDCheckbox:
on_press: root.show_passnew(self)
size_hint: None, None
height: 10
width: 20
MDLabel:
text: "Mostrar Palavra-passe"
font_size: "13px"
color: 0,0,0,.4
<DashboardGerente#FloatLayout>:
name: "DashboardGerente"
MDBottomNavigation:
panel_color: get_color_from_hex("#c300ff")
text_color: 0,0,0,1
MDBottomNavigationItem: ## Perfil do utilizador
name: 'Profile'
text: 'Perfil'
icon: 'account'
badge_icon: "numeric-10"
MDCard:
border_radius: 20
radius: [15]
size_hint:None, None
size: 300, 400
pos_hint: {"center_x": 0.5, "center_y": 0.5}
elevation: 10
orientation: "vertical"
AnchorLayout:
anchor_x: "left"
anchor_y: "top"
MDIconButton:
id:logout
text_color: 0,0,0,1
on_release: root.Logout(), root.teste()
icon: "account-arrow-left"
GridLayout:
cols: 2
padding: 40,0,0,0
MDLabel:
text: "ID: "
MDLabel:
text: "5000"
MDLabel:
text: "Nome: "
MDLabel:
text: "nome"
MDLabel:
text: "Cargo: "
MDLabel:
text: "cargo"
MDLabel:
text: "Salário: "
MDLabel:
text: "1000"
MDLabel:
text: "Secção: "
MDLabel:
text: "Frutaria"
MDRaisedButton:
text: "Mudar palavra-passe"
md_bg_color: 0.5, 0, 1, 1
on_press: root.teste()
pos_hint: {"center_x": 0.5, "center_y": 0.5}
on_release: root.show_alert_dialog()
MDBottomNavigationItem:
name: 'Providers'
text: 'Fornecedores'
icon: 'truck'
MDLabel:
text: 'Mail'
halign: 'center'
MDBottomNavigationItem:
name: 'Products'
text: 'Produtos'
icon: 'shopping'
badge_icon: "numeric-10"
MDLabel:
text: 'Mail'
halign: 'center'
MDBottomNavigationItem:
name: 'Employes'
text: 'Empregados'
icon: 'account-multiple'
badge_icon: "numeric-10"
MDRaisedButton:
text: "Adicionar funcionários"
md_bg_color: 0.5, 0, 1, 1
pos_hint: {"center_x": 0.5, "center_y": 0.5}
MDBottomNavigationItem:
name: 'Sections'
text: 'Secções'
icon: 'storefront'
badge_icon: "numeric-10"
MDLabel:
text: 'Mail'
halign: 'center'
This are my project files that matter for now, how can i get the .text value from the old_pass textfield in the DashboardGerente class?
I would suggest as follows,
Create a property, say, user_input = StringProperty("") in your App's subclass. then in kv lang of Content class,
MDTextField:
id: old_pass
on_text: app.user_input = self.text
Now use this in any method of DashboardGerente as MDApp.get_running_app().user_input
I'me working on a project and I'm using kivy.
I want to crete an app and I need multiple pages so I'm using ScreenManages.
I also need to take User Input in one of the pages and save it, so I've used MDTextField for take the text and a button to save the data.
When i press the button the app should take the data from the text field and save it in a file with sqlite3, but when I press the button it give me a really strange error.
I've tried to rewrite only that page of the app without the ScreenManager and it works.
How can I make it work also with the ScreenManager ?
(How can I get the User Input using MDTextField and ScreenManager)
I will show you some lines of code to make you understand better:
This is the Kivy Code:
<AddWindow>:
name: "add"
MDTextField:
id: account_link
hint_text: "Link"
helper_text: "Insert the Link of the WebSite to enter in the website from this app"
helper_text_mode: "on_focus"
line_color_normal: app.theme_cls.accent_color
pos_hint: {"center_x": 0.5, "center_y": 0.8}
size_hint_x: None
width: 1200
This is the code to take the data from the Text Field (that part of code it's executed when the user presses the submit button):
data = self.root.ids["account_link"].text
This is the error i get when i press the button:
data = self.root.ids["account_link"].text
KeyError: 'account_link'
Note that the documentation says:
ids are added to the root widget’s ids dictionary.
Poorly worded documentation, because they elsewhere refer to "root widget" as the root of the entire GUI. But in this case "root widget" is the root of the rule where the ids are defined. In your case that might be the AddWindow rule (not 100% sure due to the indentation of your kv snippet). If that is the case, then you need a reference to the instance of AddWindow that appears in your GUI:
data = addwindow_instance.ids["account_link"].text
Without seeing more of your code, I can only guess at the appropriate method to access the instance of AddWindow.
With the addition of a complete code, I can now help you. Here is a modified version of your add_passwd() method:
def add_passwd(self):
# get a reference to the AddWindow Screen
addwindow_instance = self.root.get_screen('add')
# use that instance to access the MDTextFields
account_link = addwindow_instance.ids["account_link"].text
account_name = addwindow_instance.ids["md_account_name"].text
account_nickname = addwindow_instance.ids["md_account_nickname"].text
email = addwindow_instance.ids["md_email"].text
passwd = addwindow_instance.ids["md_passwd"].text
#TEST
print(account_link)
print(account_name)
print(account_nickname)
print(email)
print(passwd)
Note that this also requires a couple corrections to your kv. Wherever you have anything like:
id: "some_id"
it should be changed to:
id: some_id
One example is id: "md_account_name".
This is More of my code:
# Screens
class MainWindow(Screen):
pass
class AddWindow(Screen):
pass
class WindowManager(ScreenManager):
pass
KV = """
WindowManager:
MainWindow:
AddWindow:
<MainWindow>:
name: "main"
MDRoundFlatButton:
text: "Add"
pos_hint: {"center_x": 0.5, "center_y": 0.7}
on_press:
app.root.current = "add"
root.manager.transition.direction = "left"
MDRoundFlatButton:
text: "Show"
pos_hint: {"center_x": 0.5, "center_y": 0.6}
on_press:
app.root.current = "show"
MDTextButton:
text: "Account"
pos_hint: {"center_x": 0.5, "center_y": 0.1}
on_press:
app.root.current = "settings"
root.manager.transition.direction = "up"
<AddWindow>:
name: "add"
MDRaisedButton:
text: "BACK"
md_bg_color: 0, 0, 0, 1
pos_hint: {"x": 0.01, "y": 0.93}
on_release:
app.root.current = "main"
root.manager.transition.direction = "right"
MDTextField:
id: account_link
hint_text: "Link"
helper_text: "Insert the Link of the WebSite to enter in the website from
this app"
helper_text_mode: "on_focus"
line_color_normal: app.theme_cls.accent_color
pos_hint: {"center_x": 0.5, "center_y": 0.8}
size_hint_x: None
width: 1200
MDTextField:
id: "md_account_name"
hint_text: "Account"
helper_text: "Insert the Name of the Account You Want to Save"
helper_text_mode: "on_focus"
line_color_normal: app.theme_cls.accent_color
pos_hint: {"center_x": 0.5, "center_y": 0.7}
size_hint_x: None
width: 1200
MDTextField:
id: "md_account_nickname"
hint_text: "Nickname"
helper_text: "Insert the Nickname You Have in the Account"
helper_text_mode: "on_focus"
line_color_normal: app.theme_cls.accent_color
pos_hint: {"center_x": 0.5, "center_y": 0.6}
size_hint_x: None
width: 1200
MDTextField:
id: "md_email"
hint_text: "Email"
helper_text: "Insert the Email You Created the Account with"
helper_text_mode: "on_focus"
line_color_normal: app.theme_cls.accent_color
pos_hint: {"center_x": 0.5, "center_y": 0.5}
size_hint_x: None
width: 1200
MDTextField:
id: "md_passwd"
hint_text: "Password"
helper_text: "Insert Your Password of the Account"
helper_text_mode: "on_focus"
line_color_normal: app.theme_cls.accent_color
pos_hint: {"center_x": 0.5, "center_y": 0.4}
size_hint_x: None
width: 1200
MDFillRoundFlatButton:
text: "Submit"
pos_hint: {"center_x": 0.5, "center_y": 0.1}
on_press: app.add_passwd()
"""
class App(MDApp):
def build(self):
self.title = "Safed" #The Name of the App is "Safed": "Save" + "Saved"
self.theme_cls.theme_style = "Dark" # Light
self.theme_cls.primary_palette = "Blue"
return Builder.load_string(KV)
def add_passwd(self):
account_link = AddWindow_istance.ids["account_link"].text
account_name = self.root.ids["md_account_name"].text
account_nickname = self.root.ids["md_account_nickname"].text
email = self.root.ids["md_email"].text
passwd = self.root.ids["md_passwd"].text
#TEST
print(account_link)
print(account_name)
print(account_nickname)
print(email)
print(passwd)
if __name__ == "__main__":
App().run()
I am trying to restructure the kivymd project file but I am not able to place the navigation bar at the place at which it is normally. I cannot see why this is happening (see pictures and code below).
This is how it looks like
and this is how it should look like
I am using the three files app.py, app.kv and labels.py (for injecting labels from a *.py file).
# app.kv
# -*- coding: utf-8 -*-
import os
import kivy.app
from kivy.lang import Builder
from application.kivymd.list import BaseListItem
from application.kivymd.material_resources import DEVICE_TYPE
from application.kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase
from application.kivymd.theming import ThemeManager
# User defined imports
from kivy.core.window import Window
Window.fullscreen = "auto"
class HackedDemoNavDrawer(MDNavigationDrawer):
# DO NOT USE
def add_widget(self, widget, index=0):
if issubclass(widget.__class__, BaseListItem):
self._list.add_widget(widget, index)
if len(self._list.children) == 1:
widget._active = True
self.active_item = widget
# widget.bind(on_release=lambda x: self.panel.toggle_state())
widget.bind(on_release=lambda x: x._set_active(True, list=self))
elif issubclass(widget.__class__, NavigationDrawerHeaderBase):
self._header_container.add_widget(widget)
else:
super(MDNavigationDrawer, self).add_widget(widget, index)
class MainApp(kivy.app.App):
theme_cls = ThemeManager()
title = "Application"
def build(self):
main_widget = Builder.load_file(
os.path.join(os.path.dirname(__file__), "./app.kv")
)
# self.theme_cls.theme_style = 'Dark'
main_widget.ids.text_field_error.bind(
on_text_validate=self.set_error_message,
on_focus=self.set_error_message)
self.bottom_navigation_remove_mobile(main_widget)
return main_widget
def bottom_navigation_remove_mobile(self, widget):
# Removes some items from bottom-navigation demo when on mobile
if DEVICE_TYPE == 'mobile':
widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_2)
if DEVICE_TYPE == 'mobile' or DEVICE_TYPE == 'tablet':
widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_1)
def set_error_message(self, *args):
if len(self.root.ids.text_field_error.text) == 2:
self.root.ids.text_field_error.error = True
else:
self.root.ids.text_field_error.error = False
def on_pause(self):
return True
def on_stop(self):
pass
if __name__ == '__main__':
MainApp().run()
This is the app.kv file which is injected into the app.py file
# app.kv
#:import Toolbar application.kivymd.toolbar.Toolbar
#:import MDNavigationDrawer application.kivymd.navigationdrawer.MDNavigationDrawer
#:import NavigationLayout application.kivymd.navigationdrawer.NavigationLayout
#:import NavigationDrawerDivider application.kivymd.navigationdrawer.NavigationDrawerDivider
#:import NavigationDrawerToolbar application.kivymd.navigationdrawer.NavigationDrawerToolbar
#:import NavigationDrawerSubheader application.kivymd.navigationdrawer.NavigationDrawerSubheader
#:import MDCheckbox application.kivymd.selectioncontrols.MDCheckbox
#:import MDSwitch application.kivymd.selectioncontrols.MDSwitch
#:import MDTextField application.kivymd.textfields.MDTextField
#:import MDThemePicker application.kivymd.theme_picker.MDThemePicker
#:import labels application.labels
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
id: nav_drawer
NavigationDrawerToolbar:
title: labels.NAVIGATION
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.DASHBOARD
on_release: app.root.ids.scr_mngr.current = 'dashboard'
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.SYSTEM_INSPECTOR
on_release: app.root.ids.scr_mngr.current = 'system_inspector'
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.SYSTEM_PARAMETERS
on_release: app.root.ids.scr_mngr.current = 'system_parameters'
BoxLayout:
orientation: 'vertical'
halign: "center"
Toolbar:
id: toolbar
title: labels.APPLICATION_NAME
md_bg_color: app.theme_cls.primary_color
background_palette: 'Primary'
background_hue: '500'
left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]]
#right_action_items: [['dots-vertical', lambda x: app.root.toggle_nav_drawer()]]
ScreenManager:
id: scr_mngr
Screen:
name: 'dashboard'
MDLabel:
font_style: 'Body1'
theme_text_color: 'Primary'
text: "This is the dashboard!"
size_hint_x:None
width: '250dp'
halign: "center"
pos_hint: {"center_x": 0.50, "center_y": 0.75}
MDCheckbox:
id: grp_chkbox_1
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.25, 'center_y': 0.5}
MDCheckbox:
id: grp_chkbox_2
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDSwitch:
size_hint: None, None
size: dp(36), dp(48)
pos_hint: {'center_x': 0.75, 'center_y': 0.5}
_active: False
Screen:
name: 'system_inspector'
MDLabel:
font_style: 'Body1'
theme_text_color: 'Primary'
text: "This is the system_inspector page!"
size_hint_x:None
width: '250dp'
halign: "center"
pos_hint: {"center_x": 0.50, "center_y": 0.75}
MDCheckbox:
id: grp_chkbox_1
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.25, 'center_y': 0.5}
MDCheckbox:
id: grp_chkbox_2
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDSwitch:
size_hint: None, None
size: dp(36), dp(48)
pos_hint: {'center_x': 0.75, 'center_y': 0.5}
_active: False
Screen:
name: 'system_parameters'
BoxLayout:
orientation: "horizontal"
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: dp(48)
spacing: 10
MDTextField:
hint_text: "No helper text"
input_filter: "float"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
input_filter: "int"
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: dp(48)
spacing: 10
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
Screen:
name: 'textfields'
ScrollView:
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: dp(48)
spacing: 10
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
MDTextField:
hint_text: "Persistent helper text"
helper_text: "Text is always here"
helper_text_mode: "persistent"
MDTextField:
id: text_field_error
hint_text: "Helper text on error (Hit Enter with two characters here)"
helper_text: "Two is my least favorite number"
helper_text_mode: "on_error"
MDTextField:
hint_text: "Max text length = 10"
max_text_length: 10
MDTextField:
hint_text: "required = True"
required: True
helper_text_mode: "on_error"
MDTextField:
multiline: True
hint_text: "Multi-line text"
helper_text: "Messages are also supported here"
helper_text_mode: "persistent"
MDTextField:
hint_text: "color_mode = \'accent\'"
color_mode: 'accent'
MDTextField:
hint_text: "color_mode = \'custom\'"
color_mode: 'custom'
helper_text_mode: "on_focus"
helper_text: "Color is defined by \'line_color_focus\' property"
line_color_focus: self.theme_cls.opposite_bg_normal # This is the color used by the textfield
MDTextField:
hint_text: "disabled = True"
disabled: True
Screen:
name: 'nav_drawer'
HackedDemoNavDrawer:
# NavigationDrawerToolbar:
# title: "Navigation Drawer Widgets"
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: "Badge text ---->"
badge_text: "99+"
NavigationDrawerIconButton:
active_color_type: 'accent'
text: "Accent active color"
NavigationDrawerIconButton:
active_color_type: 'custom'
text: "Custom active color"
active_color: [1, 0, 1, 1]
NavigationDrawerIconButton:
use_active: False
text: "Use active = False"
NavigationDrawerIconButton:
text: "Different icon"
icon: 'alarm'
NavigationDrawerDivider:
NavigationDrawerSubheader:
text: "NavigationDrawerSubheader"
NavigationDrawerIconButton:
text: "NavigationDrawerDivider \/"
NavigationDrawerDivider:
Here is the labels.py file for injecting the labels into the kv file.
# labels.py
APPLICATION_NAME = "Application"
NAVIGATION = "Navigation"
DASHBOARD = "Dashboard"
SYSTEM_INSPECTOR = "System Inspector"
SYSTEM_PARAMETERS = "System Parameters"
Solution
You might have a kv file with a name, main.kv
With KivyMD installed on my machine, and some minor changes, the KivyMD App ran fine.
Example
app.py
# app.py
# -*- coding: utf-8 -*-
import os
from kivy.app import App
from kivy.lang import Builder
from kivymd.list import BaseListItem
from kivymd.material_resources import DEVICE_TYPE
from kivymd.navigationdrawer import MDNavigationDrawer, NavigationDrawerHeaderBase
from kivymd.theming import ThemeManager
# User defined imports
from kivy.core.window import Window
# Window.fullscreen = "auto"
class HackedDemoNavDrawer(MDNavigationDrawer):
# DO NOT USE
def add_widget(self, widget, index=0):
if issubclass(widget.__class__, BaseListItem):
self._list.add_widget(widget, index)
if len(self._list.children) == 1:
widget._active = True
self.active_item = widget
# widget.bind(on_release=lambda x: self.panel.toggle_state())
widget.bind(on_release=lambda x: x._set_active(True, list=self))
elif issubclass(widget.__class__, NavigationDrawerHeaderBase):
self._header_container.add_widget(widget)
else:
super(MDNavigationDrawer, self).add_widget(widget, index)
class MainApp(App):
theme_cls = ThemeManager()
title = "Application"
def build(self):
main_widget = Builder.load_file(
os.path.join(os.path.dirname(__file__), "./app.kv")
)
# self.theme_cls.theme_style = 'Dark'
main_widget.ids.text_field_error.bind(
on_text_validate=self.set_error_message,
on_focus=self.set_error_message)
self.bottom_navigation_remove_mobile(main_widget)
return main_widget
def bottom_navigation_remove_mobile(self, widget):
# Removes some items from bottom-navigation demo when on mobile
if DEVICE_TYPE == 'mobile':
widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_2)
if DEVICE_TYPE == 'mobile' or DEVICE_TYPE == 'tablet':
widget.ids.bottom_navigation_demo.remove_widget(widget.ids.bottom_navigation_desktop_1)
def set_error_message(self, *args):
if len(self.root.ids.text_field_error.text) == 2:
self.root.ids.text_field_error.error = True
else:
self.root.ids.text_field_error.error = False
def on_pause(self):
return True
def on_stop(self):
pass
if __name__ == '__main__':
MainApp().run()
labels.py
# labels.py
APPLICATION_NAME = "Application"
NAVIGATION = "Navigation"
DASHBOARD = "Dashboard"
SYSTEM_INSPECTOR = "System Inspector"
SYSTEM_PARAMETERS = "System Parameters"
app.kv
# app.kv
#:kivy 1.11.0
#:import Toolbar kivymd.toolbar.Toolbar
#:import MDNavigationDrawer kivymd.navigationdrawer.MDNavigationDrawer
#:import NavigationLayout kivymd.navigationdrawer.NavigationLayout
#:import NavigationDrawerDivider kivymd.navigationdrawer.NavigationDrawerDivider
#:import NavigationDrawerToolbar kivymd.navigationdrawer.NavigationDrawerToolbar
#:import NavigationDrawerSubheader kivymd.navigationdrawer.NavigationDrawerSubheader
#:import MDCheckbox kivymd.selectioncontrols.MDCheckbox
#:import MDSwitch kivymd.selectioncontrols.MDSwitch
#:import MDTextField kivymd.textfields.MDTextField
#:import MDThemePicker kivymd.theme_picker.MDThemePicker
#:import labels labels
NavigationLayout:
id: nav_layout
MDNavigationDrawer:
id: nav_drawer
NavigationDrawerToolbar:
title: labels.NAVIGATION
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.DASHBOARD
on_release: app.root.ids.scr_mngr.current = 'dashboard'
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.SYSTEM_INSPECTOR
on_release: app.root.ids.scr_mngr.current = 'system_inspector'
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: labels.SYSTEM_PARAMETERS
on_release: app.root.ids.scr_mngr.current = 'system_parameters'
BoxLayout:
orientation: 'vertical'
halign: "center"
Toolbar:
id: toolbar
title: labels.APPLICATION_NAME
md_bg_color: app.theme_cls.primary_color
background_palette: 'Primary'
background_hue: '500'
left_action_items: [['menu', lambda x: app.root.toggle_nav_drawer()]]
#right_action_items: [['dots-vertical', lambda x: app.root.toggle_nav_drawer()]]
ScreenManager:
id: scr_mngr
Screen:
name: 'dashboard'
MDLabel:
font_style: 'Body1'
theme_text_color: 'Primary'
text: "This is the dashboard!"
size_hint_x:None
width: '250dp'
halign: "center"
pos_hint: {"center_x": 0.50, "center_y": 0.75}
MDCheckbox:
id: grp_chkbox_1
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.25, 'center_y': 0.5}
MDCheckbox:
id: grp_chkbox_2
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDSwitch:
size_hint: None, None
size: dp(36), dp(48)
pos_hint: {'center_x': 0.75, 'center_y': 0.5}
_active: False
Screen:
name: 'system_inspector'
MDLabel:
font_style: 'Body1'
theme_text_color: 'Primary'
text: "This is the system_inspector page!"
size_hint_x:None
width: '250dp'
halign: "center"
pos_hint: {"center_x": 0.50, "center_y": 0.75}
MDCheckbox:
id: grp_chkbox_1
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.25, 'center_y': 0.5}
MDCheckbox:
id: grp_chkbox_2
group: 'test'
size_hint: None, None
size: dp(48), dp(48)
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
MDSwitch:
size_hint: None, None
size: dp(36), dp(48)
pos_hint: {'center_x': 0.75, 'center_y': 0.5}
_active: False
Screen:
name: 'system_parameters'
BoxLayout:
orientation: "horizontal"
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: dp(48)
spacing: 10
MDTextField:
hint_text: "No helper text"
input_filter: "float"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
input_filter: "int"
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: dp(48)
spacing: 10
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
Screen:
name: 'textfields'
ScrollView:
BoxLayout:
orientation: 'vertical'
size_hint_y: None
height: self.minimum_height
padding: dp(48)
spacing: 10
MDTextField:
hint_text: "No helper text"
MDTextField:
hint_text: "Helper text on focus"
helper_text: "This will disappear when you click off"
helper_text_mode: "on_focus"
MDTextField:
hint_text: "Persistent helper text"
helper_text: "Text is always here"
helper_text_mode: "persistent"
MDTextField:
id: text_field_error
hint_text: "Helper text on error (Hit Enter with two characters here)"
helper_text: "Two is my least favorite number"
helper_text_mode: "on_error"
MDTextField:
hint_text: "Max text length = 10"
max_text_length: 10
MDTextField:
hint_text: "required = True"
required: True
helper_text_mode: "on_error"
MDTextField:
multiline: True
hint_text: "Multi-line text"
helper_text: "Messages are also supported here"
helper_text_mode: "persistent"
MDTextField:
hint_text: "color_mode = \'accent\'"
color_mode: 'accent'
MDTextField:
hint_text: "color_mode = \'custom\'"
color_mode: 'custom'
helper_text_mode: "on_focus"
helper_text: "Color is defined by \'line_color_focus\' property"
line_color_focus: self.theme_cls.opposite_bg_normal # This is the color used by the textfield
MDTextField:
hint_text: "disabled = True"
disabled: True
Screen:
name: 'nav_drawer'
HackedDemoNavDrawer:
# NavigationDrawerToolbar:
# title: "Navigation Drawer Widgets"
NavigationDrawerIconButton:
icon: 'checkbox-blank-circle'
text: "Badge text ---->"
badge_text: "99+"
NavigationDrawerIconButton:
active_color_type: 'accent'
text: "Accent active color"
NavigationDrawerIconButton:
active_color_type: 'custom'
text: "Custom active color"
active_color: [1, 0, 1, 1]
NavigationDrawerIconButton:
use_active: False
text: "Use active = False"
NavigationDrawerIconButton:
text: "Different icon"
icon: 'alarm'
NavigationDrawerDivider:
NavigationDrawerSubheader:
text: "NavigationDrawerSubheader"
NavigationDrawerIconButton:
text: "NavigationDrawerDivider \/"
NavigationDrawerDivider:
Output
I have created a simple login, registration, and menu screen that utilize buttons and TextInputs. When i load the app up, the buttons and TextInputs have normal textures, however when i interact with any of the buttons or TextInputs, the textures glitch for all the buttons and TextInputs in the app.
HandwritingRecognition.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
import DatabaseManagement
DatabaseManagement.Create()
USER = ''
class Login_Screen(Screen):
def Login(self):
global USER
USER = self.ids.Username.text
Found = DatabaseManagement.Find_User(self)
if Found:
print("Direct Entry")
self.manager.current = "Login_Successful"
else:
print("Wrong Password")
self.manager.current = "Login_Failed"
def registration(self):
self.manager.current = "Registration_Screen"
class Login_Successful(Screen):
def ChangePassword(self):
self.manager.current = "Change_Password"
def DeleteAccount(self):
global USER
DatabaseManagement.Delete_User(USER)
self.manager.current = "Login_Screen"
def MainScreen(self):
self.manager.current = "Login_Screen"
class Change_Password(Screen):
pass
class LoginConfirmationScreen(Screen):
pass
class Registration_Screen(Screen):
def MainScreen(self):
DatabaseManagement.Data_Entry(self)
self.manager.current = "Login_Screen"
class Login_Failed(Screen):
def MainScreen(self):
self.manager.current = "Login_Screen"
class RootWidget(ScreenManager):
pass
class MainApp(App):
def build(self):
return RootWidget()
if __name__ == "__main__":
MainApp().run()
MainApp.kv
<RootWidget>:
id: Main
Login_Screen:
id: login
name: "Login_Screen"
Change_Password:
id: ChangePass
name: 'Change_Password'
Login_Failed:
id: Failed
name: "Login_Failed"
Login_Successful:
id: Success
name: 'Login_Successful'
Registration_Screen:
id: register
name: 'Registration_Screen'
<Login_Screen>:
GridLayout:
rows:3
cols:2
Label:
text: "Username:"
font_size: 20
TextInput:
id: Username
multiline: False
hint_text: 'Enter your Username'
Label:
text: "Password"
font_size: 20
TextInput:
id: Passwrd
multiline: False
hint_text: 'Enter your Password'
password: True
Button:
text: "Register"
background_color: (1,0,0,1)
on_press: root.registration()
Button:
text: "Sign In"
on_press: root.Login()
<Registration_Screen>:
GridLayout:
rows:4
cols:2
Label:
text: 'First Name:'
font_size: 20
TextInput:
id: FirstName
multiline: False
hint_text: 'Enter your First Name'
Label:
text: 'Surname'
font_size: 20
TextInput:
id: Surname
multiline: False
hint_text: 'Enter your Surname'
Label:
text: 'Password'
font_size: 20
TextInput:
id: Passwrd
multiline: False
hint_text: 'Enter your Password'
password: False
Button:
text: "Create Account"
on_press: root.MainScreen()
<Change_Password>
FloatLayout:
Label:
text: 'Change Password'
pos_hint: {"center_x":0.5, "y":0.75}
font_size: '25sp'
size_hint: 0.5,0.25
Label:
text:'Old Password:'
pos_hint: {"x":0.2, "y":0.6}
font_size: '25sp'
size_hint: 0.3,0.1
TextInput:
pos_hint: {"x": 0.5,"y": 0.6}
size_hint: 0.3,0.1
id: OldPass
multiline: False
password: True
<Login_Successful>:
FloatLayout:
Label:
text: 'Main Menu'
pos_hint: {"center_x":0.5, "y":0.75}
font_size: '25sp'
size_hint: 0.5,0.25
Button:
text: 'Handwriting Recognition'
pos_hint: {"center_x":0.5, "y":0.5}
size_hint: 0.44,0.2
Button:
text: 'Change Password'
pos_hint: {"center_x":0.38, "y":0.27}
size_hint: 0.2,0.2
on_press: root.ChangePassword()
Button:
text: 'Delete Account'
pos_hint: {"center_x":0.38, "y":0.05}
size_hint: 0.2,0.2
on_press: root.DeleteAccount()
Button:
text: 'Log Out'
pos_hint: {"center_x":0.62, "y":0.05}
size_hint: 0.2,0.2
on_press: root.MainScreen()
<Login_Failed>:
BoxLayout:
orientation: "vertical"
Label:
text: "Login Failed"
Button:
text: "Try again"
on_press: root.MainScreen()
DatabaseManagement.py
import sqlite3
conn = sqlite3.connect('HandwritingRecognition.db')
c = conn.cursor()
def Create():
c.execute('CREATE TABLE IF NOT EXISTS Users(FirstName TEXT, Surname TEXT, Username TEXT, Passwrd TEXT)')
def Data_Entry(self):
FirstName = self.ids.FirstName.text
Surname = self.ids.Surname.text
Username = FirstName+Surname
Passwrd = self.ids.Passwrd.text
c.execute("INSERT INTO Users (FirstName,Surname,Username,Passwrd) VALUES(?,?,?,?)",(FirstName,Surname,Username,Passwrd))
conn.commit()
def Find_User(self):
finduser = ('SELECT * FROM Users WHERE Username = ? AND Passwrd = ?')
c.execute(finduser,[(self.ids.Username.text),(self.ids.Passwrd.text)])
data = c.fetchall()
if data:
return True
else:
return False
def Delete_User(USER):
c.execute("DELETE FROM Users WHERE Username = ?",(USER,))
conn.commit()
Here is the screenshot of the application as it is loaded before clicking anything:
Application On Loadup
https://i.stack.imgur.com/cJi27.png
Here is the screenshot after i interact with a TextInput box:
Application after Interaction
https://i.stack.imgur.com/HwZaz.png
I have edited the MainApp.kv to only use FloatLayouts, but i am still getting the same glitch.
<RootWidget>:
id: Main
Login_Screen:
id: login
name: "Login_Screen"
Change_Password:
id: ChangePass
name: 'Change_Password'
Login_Failed:
id: Failed
name: "Login_Failed"
Login_Successful:
id: Success
name: 'Login_Successful'
Registration_Screen:
id: register
name: 'Registration_Screen'
<Login_Screen>:
FloatLayout:
Label:
text: "Login"
font_size: '30sp'
pos_hint: {"center_x":0.5,"y":0.8}
size_hint: 0.4,0.3
Label:
text: "Username:"
font_size: '20sp'
pos_hint: {"center_x": 0.25, "y":0.6}
size_hint: 0.4, 0.25
TextInput:
id: Username
multiline: False
pos_hint: {"center_x": 0.75, "y":0.6}
size_hint: 0.45, 0.15
hint_text: 'Enter your Username'
Label:
text: "Password"
font_size: '20sp'
pos_hint: {"center_x": 0.25, "y":0.3}
size_hint: 0.4, 0.15
TextInput:
id: Passwrd
multiline: False
pos_hint: {"center_x": 0.75, "y":0.3}
size_hint: 0.45, 0.15
hint_text: 'Enter your Password'
password: True
Button:
text: "Register"
pos_hint: {"center_x": 0.25, "y":0}
size_hint: 0.4, 0.15
#background_color: (1,0,0,1)
on_press: root.registration()
Button:
pos_hint: {"center_x": 0.75, "y":0}
size_hint: 0.4, 0.15
text: "Sign In"
on_press: root.Login()
<Registration_Screen>:
FloatLayout:
Label:
text: 'Create an Account'
font_size: '20sp'
pos_hint: {"center_x": 0.5, "y": 0.8}
size_hint: 0.4,0.2
Label:
text: 'First Name:'
font_size: '20sp'
pos_hint: {"center_x": 0.25, "y": 0.6}
size_hint: 0.2, 0.15
TextInput:
id: FirstName
multiline: False
pos_hint: {"center_x": 0.6, "y": 0.6}
size_hint: 0.4, 0.15
hint_text: 'Enter your First Name'
Label:
text: 'Surname'
font_size: '20sp'
pos_hint: {"center_x": 0.25, "y": 0.45}
size_hint: 0.2, 0.15
TextInput:
id: Surname
multiline: False
hint_text: 'Enter your Surname'
pos_hint: {"center_x": 0.6, "y": 0.45}
size_hint: 0.4, 0.15
Label:
text: 'Password'
font_size: '20sp'
pos_hint: {"center_x": 0.25, "y": 0.3}
size_hint: 0.2, 0.15
TextInput:
id: Passwrd
multiline: False
pos_hint: {"center_x": 0.6, "y": 0.3}
size_hint: 0.4, 0.15
hint_text: 'Enter your Password'
password: True
Label:
text: 'Confirm Password'
font_size: '20sp'
pos_hint: {"center_x": 0.25,"y": 0.15}
size_hint: 0.2, 0.15
TextInput:
id: PasswrdConfirm
multiline: False
pos_hint: {"center_x": 0.6, "y": 0.15}
size_hint: 0.4,0.15
hint_text: "Please confirm password"
password: True
Button:
text: "Create Account"
pos_hint: {"center_x": 0.5, "y": 0}
size_hint: 0.6, 0.15
on_press: root.MainScreen()
<Change_Password>
FloatLayout:
Label:
text: 'Change Password'
pos_hint: {"center_x":0.5, "y":0.75}
font_size: '25sp'
size_hint: 0.5,0.25
Label:
text:'Old Password:'
pos_hint: {"x":0.2, "y":0.6}
font_size: '25sp'
size_hint: 0.3,0.1
TextInput:
pos_hint: {"x": 0.5,"y": 0.6}
size_hint: 0.3,0.1
id: OldPass
multiline: False
password: True
<Login_Successful>:
FloatLayout:
Label:
text: 'Main Menu'
pos_hint: {"center_x":0.5, "y":0.75}
font_size: '25sp'
size_hint: 0.5,0.25
Button:
text: 'Handwriting Recognition'
pos_hint: {"center_x":0.5, "y":0.5}
size_hint: 0.44,0.2
Button:
text: 'Change Password'
pos_hint: {"center_x":0.38, "y":0.27}
size_hint: 0.2,0.2
on_press: root.ChangePassword()
Button:
text: 'Delete Account'
pos_hint: {"center_x":0.38, "y":0.05}
size_hint: 0.2,0.2
on_press: root.DeleteAccount()
Button:
text: 'Log Out'
pos_hint: {"center_x":0.62, "y":0.05}
size_hint: 0.2,0.2
on_press: root.MainScreen()
<Login_Failed>:
FloatLayout:
Label:
text: "Login Failed"
pos_hint: {"center_x": 0.5, "y": 0.75}
size_hint: 0.5,0.25
Button:
text: "Try again"
pos_hint: {"center_x":0.5, "y": 0.05}
size_hint: 0.44, 0.2
on_press: root.MainScreen()
The Screen Widget is a RelativeLayout SubClass. It tends to run into a lot of problems. I'd suggest subclassing all Screens to a FloatLayout first:
<Login_Screen>:
FloatLayout:
GridLayout:
rows:3
cols:2
This typically fixes the most unpredictability that comes with screens.