KIVY: How do I make a button to initiate my Paint app - python

I have a working Kivy code as given below. I am able to draw random shapes once I run it. Now, I want to enable drawing only after clicking the Hello button once. How should I modify my code?
Python code
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.graphics import Line
class Painter(Widget):
def on_touch_down(self, touch):
with self.canvas:
touch.ud["line"] = Line( points = (touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud["line"].points += [touch.x, touch.y]
class MainScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
presentation = Builder.load_file("main3.kv")
class MainApp(App):
def build(self):
return presentation
if __name__=="__main__":
MainApp().run()
kv file:
#:kivy 1.0.9
ScreenManagement:
MainScreen:
<MainScreen>:
name:"main"
FloatLayout:
Painter
Button:
text: "Hello"
font_size: 50
color: 0,1,0,1
size_hint: 0.3,0.2
pos_hint: {"right":1, "top":1}

How about making a new screen for painting.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, FadeTransition
from kivy.uix.widget import Widget
from kivy.graphics import Line
KV = '''
ScreenManagement:
MainScreen:
PaintScreen:
<MainScreen>:
name:"main"
FloatLayout:
Button:
text: "Go paint"
font_size: 50
color: 0,1,0,1
size_hint: 0.3,0.2
pos_hint: {"right":1, "top":1}
on_release:
root.manager.current = 'paint'
<PaintScreen#Screen>:
name: 'paint'
FloatLayout:
Button:
text: "Exit painting"
font_size: 40
color: 0,1,0,1
size_hint: 0.3,0.2
pos_hint: {"right":1, "top":1}
on_release:
root.manager.current = 'main'
Painter:
'''
class Painter(Widget):
def on_touch_down(self, touch):
with self.canvas:
touch.ud["line"] = Line( points = (touch.x, touch.y))
def on_touch_move(self, touch):
touch.ud["line"].points += [touch.x, touch.y]
class MainScreen(Screen):
pass
class ScreenManagement(ScreenManager):
pass
class MainApp(App):
def build(self):
return Builder.load_string(KV)
if __name__=="__main__":
MainApp().run()

You can use the a toggle button and link its state to the Painter:
...
Painter:
hello_active: hello_button.state == 'down'
ToggleButton:
id: hello_button
text: "Hello"
font_size: 50
color: 0,1,0,1
size_hint: 0.3,0.2
pos_hint: {"right":1, "top":1}
and in the python file...
class Painter(Widget):
hello_active = BooleanProperty(False)
def on_touch_down(self, touch):
if not self.hello_active:
return #nothing to see here ...
with self.canvas:
touch.ud["line"] = Line( points = (touch.x, touch.y))
def on_touch_move(self, touch):
if 'line' in touch.ud:
touch.ud["line"].points += [touch.x, touch.y]

Related

split gridlayout to can not draw in paint app kivy python

I designed this program
python code:
from random import random
from kivymd.app import MDApp as App
from kivymd.uix.widget import MDWidget as Widget
from kivy.graphics import Ellipse, Color, Line
from kivy.uix.screenmanager import ScreenManager, Screen
from kivymd.uix.button import MDIconButton
from kivy.lang import Builder
from kivy.properties import ObjectProperty
class Main(Screen):
draw = ObjectProperty(None)
class About(Screen):
pass
class Manager(ScreenManager):
mgr = ObjectProperty(None)
def cleaner(self):
self.mgr.draw.clean()
def color(self,color):
MyPaintWidget.color = color
class MyPaintWidget(Widget):
color = (0,0,0,1)
def clean(self):
self.canvas.clear()
def on_touch_down(self, touch):
# self.rect.pos = touch.pos
color = self.color
with self.canvas:
Color(*color)
d = 10
touch.ud['line'] = Line(points=(touch.x, touch.y),width = 5)
def on_touch_up(self,touch):
with self.canvas:
d = 10
Ellipse(pos=(touch.x - d / 2, touch.y - d / 2), size=(d, d))
def on_touch_move(self, touch):
# self.rect.pos = touch.pos
touch.ud['line'].points += [touch.x, touch.y]
#main_style = Builder.load_file("ms_paint.kv")
class MyPaintApp(App):
def build(self):
self.root = Builder.load_file("ms_paint.kv")
if __name__ == '__main__':
MyPaintApp().run()
kv file:
#:import get_color_from_hex kivy.utils.get_color_from_hex
Manager:
mgr: sc_mgr
Main:
id: sc_mgr
About:
<MyPaintWidget>:
on_touch_down: self.on_touch_down
on_touch_move: self.on_touch_move
<Main>:
name: "main"
draw: main_draw
BoxLayout:
orientation: "vertical"
MyPaintWidget:
id: main_draw
size_hint: 1, 0.9
GridLayout:
size_hint: 1, 0.1
cols: 7
padding: 10
#Button:
#text: "About"
#on_press:
#root.manager.current= "about"
#root.manager.transition.direction= "left"
MDIconButton:
icon: "eraser-variant"
on_press: root.manager.cleaner()
MDIconButton:
icon: "circle"
theme_icon_color: "Custom"
icon_color: (0,0,0,1)
on_press: root.manager.color((0,0,0,1))
MDIconButton:
icon: "circle"
theme_icon_color: "Custom"
icon_color: get_color_from_hex("#ff0000")
on_press: root.manager.color((255,0,0,1))
MDIconButton:
icon: "circle"
theme_icon_color: "Custom"
icon_color: get_color_from_hex("#00ff00")
on_press: root.manager.color((0,255,0,1))
MDIconButton:
icon: "circle"
theme_icon_color: "Custom"
icon_color: get_color_from_hex("#0000ff")
on_press: root.manager.color((0,0,255,1))
<About>:
name: "about"
BoxLayout:
orientation: "vertical"
padding: 10
Label:
size_hint: 1, 0.9
text: "This is a free and open source paint app, made by a teacher of HamRuyesh community."
Button:
size_hint: 1, 0.9
text:"Back to Main"
on_press:
root.manager.current= "main"
root.manager.transition.direction= "right"
My problem is that I do not want to draw a line in the bottom bar, which is a grid layout, and I just want to be able to draw from that part. please guide me.
..........................................................................................................................................
You can use StencilView to limit the drawing area.
Thus You might change the MyPaintWidget(Widget) as
class MyPaintWidget(BoxLayout, StencilView):

Kivy Inherit ScreenManager from FloatLayout

I am having trouble understanding how to inherit the functionality of one class into another with Kivy. I understand the error message ('LoadDialog_Directory' object has no attribute 'manager'), but I'm just not grasping exactly how to fix it. I believe I need to do something with the function below, but ultimately, I do not know.
def __init__(self, **kwargs):
super().__init__(**kwargs)
The goal of this script is to be able to select a specific driver as the path for the filechooser. I choose this method vs. others because most were using Kivy 1.11.1, this version has a lot of deprecated functions that do not work with 2.0.
.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang.builder import Builder
from kivy.uix.spinner import SpinnerOption
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.utils import platform
from kivy.properties import StringProperty
import os
import string
class WindowManager(ScreenManager):
pass
class MyOption(SpinnerOption):
pass
class LoadDialog_Directory(FloatLayout):
load = ObjectProperty(None)
cancel = ObjectProperty(None)
def dir_driver(self):
x = self.manager.get_screen("first")
return str(x.ids.drive_dir.text)
class FirstWindow(Screen):
def get_drives(self):
drives = ['%s:' % d for d in string.ascii_uppercase if os.path.exists('%s:' % d)]
return drives
def dismiss_popup(self):
self._popup.dismiss()
def show_load_directory(self):
content = LoadDialog_Directory(load=self.directroy_path, cancel=self.dismiss_popup)
self._popup = Popup(title="Load file", content=content, size_hint=(0.9, 0.9))
self._popup.open()
def directroy_path(self, path, filename):
self.ids.text_input_directory.text = str(filename[0])
self.dismiss_popup()
kv_main = Builder.load_file('main.kv')
#
class MyApp(App):
def build(self):
return kv_main
if __name__ == '__main__':
MyApp().run()
main.kv
#:include first.kv
WindowManager:
FirstWindow:
<LoadDialog_Directory>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
dirselect: True
path: root.dir_driver()
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)
first.kv
<FirstWindow>
name: 'first'
GridLayout:
cols: 1
BoxLayout:
orientation: "horizontal"
TextInput:
BoxLayout:
orientation: "horizontal"
Spinner:
id: drive_dir
text: "Root Drive"
halign: 'center'
option_cls: "MyOption"
values: root.get_drives()
Button:
text: "Set Result Directory"
on_release: root.show_load_directory()
TextInput:
id: text_input_directory
disabled: True
text: text_input_directory.text
BoxLayout:
size_hint: (0.01, 1)
orientation: "horizontal"
TextInput:
Side Note: The reason for the extra blank TextInput is because the Spinner will not function (show drivers) if it is taking too much of the App.
After a few hours of trail and error I finally got it to work, but I have no idea why it works. Here is what changed:
New variable in class LoadDialog_Directory(FloatLayout) - input_pth
Called input_pth into my content variable within class FirstWindow(Screen) function show_load_directory(self)
Set my filechooser.path to root.input_pth in the main.kv file.
I do not understand how the input_pth variable within content is able to reference the class LoadDialog_Directory(FloatLayout) without having to pass something like:
def __init__(self, input_pth, **kwargs):
super(LoadDialog_Directory, self).__init__()
self.input_pth = input_pth
.py
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang.builder import Builder
from kivy.uix.spinner import SpinnerOption
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.utils import platform
from kivy.properties import StringProperty
import os
import string
class WindowManager(ScreenManager):
pass
class MyOption(SpinnerOption):
pass
class LoadDialog_Directory(FloatLayout):
input_pth = StringProperty()
load = ObjectProperty()
cancel = ObjectProperty()
class FirstWindow(Screen):
def drive_list(self):
drives = ['%s:' % d for d in string.ascii_uppercase if os.path.exists('%s:' % d)]
return drives
def dismiss_popup(self):
self._popup.dismiss()
def show_load_directory(self):
content = LoadDialog_Directory(load=self.directroy_path, cancel=self.dismiss_popup, input_pth=self.ids.drive_dir.text)
self._popup = Popup(title="Load file", content=content, size_hint=(0.9, 0.9))
self._popup.open()
def directroy_path(self, path, filename):
self.ids.text_input_directory.text = str(filename[0])
self.dismiss_popup()
kv_main = Builder.load_file('main.kv')
#
class MyApp(App):
def build(self):
return kv_main
if __name__ == '__main__':
MyApp().run()
main.kv
#:include first.kv
WindowManager:
FirstWindow:
<LoadDialog_Directory>:
BoxLayout:
size: root.size
pos: root.pos
orientation: "vertical"
FileChooserListView:
id: filechooser
dirselect: True
path: root.input_pth
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)
first.kv
<FirstWindow>
name: 'first'
GridLayout:
cols: 1
BoxLayout:
orientation: "horizontal"
TextInput:
BoxLayout:
orientation: "horizontal"
Spinner:
id: drive_dir
halign: 'center'
option_cls: "MyOption"
values: root.drive_list()
Button:
text: "Set Result Directory"
on_release: root.show_load_directory()
TextInput:
id: text_input_directory
disabled: True
text: text_input_directory.text
BoxLayout:
size_hint: (0.01, 1)
orientation: "horizontal"
TextInput:

How use BoxLayout from KivyMD

Why can I move the button only horizontally using the vertical orientation of BoxLayout, and only vertically using the horizontal orientation? For example:
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
Screen:
BoxLayout:
orientation: 'vertical'
MDRaisedButton:
pos_hint: {'center_x': .3,'center_y': .5}
'''
class Test(MDApp):
def build(self):
return Builder.load_string(KV)
Test().run()
Horizontal orientation, also the default orientation:
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
Screen:
BoxLayout:
orientation: 'horizontal'
MDRaisedButton:
pos_hint: {'center_x': .3,'center_y': .5}
'''
class FindWord(MDApp):
def build(self):
return Builder.load_string(KV)
FindWord().run()
How to move widgets freely on both axes? Help please
from kivy.lang import Builder
from kivymd.app import MDApp
KV = '''
MDScreen:
MDBoxLayout:
adaptive_size: True
pos_hint: {'center_x': .3, 'center_y': .5}
MDRaisedButton:
text: "MDRaisedButton"
'''
class FindWord(MDApp):
def build(self):
return Builder.load_string(KV)
FindWord().run()
https://kivy.org/doc/stable/api-kivy.uix.floatlayout.html
https://kivy.org/doc/stable/api-kivy.uix.boxlayout.html

How to switch screens from a dynamically created button in kivy recycleview

Problem
I have a screen (OrderScreen) that populates with buttons if there is data to be processed. I would like the user to click one of the buttons to be brought to another screen (MenuScreen) to process the data. While my intention is to populate the next screen with data from the button, I am currently just trying to get the ScreenManager to change to the next screen after a button press. I added a pass_data() method to the OrderButton and tried to trigger the screen manager there but self.manager.current and root.manager.current were throwing exceptions. Any help would be greatly appreciated.
recycleview_test.py
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivy.uix.recycleview import RecycleView
from kivy.uix.screenmanager import ScreenManager, Screen
from random import randint
class MenuScreen(Screen):
def quit(self):
App.get_running_app.stop()
Window.close()
class OrderScreen(Screen):
pass
class OrderButton(Button):
def __init__(self, **kwargs):
super(OrderButton, self).__init__(**kwargs)
def pass_data(self):
print("button pushed")
class OrderScroll(RecycleView):
def __init__(self, **kwargs):
super(OrderScroll, self).__init__(**kwargs)
self.data = [{'text': str(f"Make {randint(10, 25)} items from package #{randint(1,4)}")} for x in range(12)]
class WindowManager(ScreenManager):
pass
class RecycleApp(App):
def build(self):
return WindowManager()
if __name__ == "__main__":
RecycleApp().run()
recycle.kv
#:import Factory kivy.factory.Factory
#: import ScreenManager kivy.uix.screenmanager.ScreenManager
#: import Screen kivy.uix.screenmanager.ScreenManager
#:import App kivy.app.App
<OrderScroll>:
viewclass: 'OrderButton'
manager: None
RecycleBoxLayout:
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
padding: 20
spacing: 10
<OrderButton>:
manager: None
font_size: 32
bold: True
on_release:
root.pass_data()
<WindowManager>:
id: screen_manager
OrderScreen:
id: order_screen
name: "OrderScreen"
manager: screen_manager
MenuScreen:
id: menu_screen
name: 'MenuScreen'
manager: screen_manager
<OrderScreen>:
BoxLayout:
orientation: "vertical"
Label:
text: "Data Buttons"
font_size: 64
size_hint_y: None
# pos_hint: {"x":0, "y":1}
height: 200
OrderScroll:
<MenuScreen>:
BoxLayout:
orientation: "vertical"
Label:
text: "Made it"
font_size: 64
FloatLayout:
Button:
text: 'Keep going'
font_size: 48
size_hint: .8,.5
pos_hint: {"center_x": .5, "center_y": .1}
FloatLayout:
Button:
text: 'Quit'
size_hint: .15,.3
pos_hint: {"center_x": .5, "center_y": .5}
on_release:
root.quit()
Try to create an object of screen manager:
class RecycleApp(App):
def build(self):
self.sm = WindowManager()
return self.sm
And then access it by:
App.get_running_app().sm.current = 'MenuScreen' # in Python
app.sm.current = 'MenuScreen' # in kv

Python KIVY: recursive DropDown

I would like to create a DropDown that contains 3 other DropDowns that contains 3 buttons each.
I would like the first DropDown to open three more DropDowns, when we click on one of them, three buttons appear, and in any case when a button appears, which is below down without display bug. When you click on a dropdown for se second time, it hides its children widgets.
I'm using this way to create a dropdown:
.py:
from kivy.app import App
from kivy.uix.dropdown import DropDown
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.properties import StringProperty
class MyScreenManager(ScreenManager):
button_text = StringProperty('Show possibilities')
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
self.dropdown = CustomDropDown(self)
def open_drop_down(self, widget):
self.dropdown.open(widget)
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
class CustomDropDown(DropDown):
def __init__(self, screen_manager, **kwargs):
super(CustomDropDown, self).__init__(**kwargs)
self.sm = screen_manager
def on_select(self, data):
self.sm.button_text = data
Builder.load_file("debug.kv")
class MyAppli(App):
def build(self):
return MyScreenManager()
if __name__ == '__main__':
MyAppli().run()
.kv:
<MyScreenManager>:
MyScreen:
AnchorLayout:
anchor_x: 'center'
anchor_y: 'top'
Button:
text: root.button_text
size:(200,50)
size_hint:(None,None)
on_release: root.open_drop_down(self)
<CustomDropDown>:
Button:
text:"Item 1"
size:(200,50)
size_hint:(None,None)
on_release: root.select("ONE")
Button:
text:"Item 2"
size:(200,50)
size_hint:(None,None)
on_release: root.select(self.text)
Button:
text:"Item 3"
size:(200,50)
size_hint:(None,None)
on_release: root.select("THREE")
Adding another custom drop down class and adding a button method to open/dismiss the second drop down. The open_drop2() method does the open/dismiss. Added padding to each Button in an attempt to show the cascading a bit. Additional cascading can be done using the same scheme, i.e., add a CustomDropDown3 class that is opened by a button in CustomDropDown2. Note that the dismiss_on_select: False in the kv file is required to be sure that the is2Displayed attribute is updated correctly.
.py:
from kivy.app import App
from kivy.properties import StringProperty
from kivy.uix.dropdown import DropDown
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
class MyScreenManager(ScreenManager):
button_text = StringProperty('Show possibilities')
def __init__(self, **kwargs):
super(MyScreenManager, self).__init__(**kwargs)
self.dropdown = CustomDropDown1(self)
def open_drop_down(self, widget):
self.dropdown.open(widget)
class MyScreen(Screen):
def __init__(self, **kwargs):
super(MyScreen, self).__init__(**kwargs)
class CustomDropDown1(DropDown):
def __init__(self, screen_manager, **kwargs):
super(CustomDropDown1, self).__init__(**kwargs)
self.sm = screen_manager
self.dropdown2 = CustomDropDown2(self.sm)
self.is2Displayed = False
def on_select(self, data):
self.sm.button_text = data
def open_drop2(self):
if not self.is2Displayed:
self.dropdown2.open(self)
self.is2Displayed = True
else:
self.dropdown2.dismiss()
self.is2Displayed = False
class CustomDropDown2(DropDown):
def __init__(self, screen_manager, **kwargs):
super(CustomDropDown2, self).__init__(**kwargs)
self.sm = screen_manager
def on_select(self, data):
self.sm.button_text = data
Builder.load_file("debug.kv")
class MyAppli(App):
def build(self):
return MyScreenManager()
if __name__ == '__main__':
MyAppli().run()
.kv:
<MyScreenManager>:
MyScreen:
FloatLayout:
Button:
text: root.button_text
size: (200, 50)
size_hint:(None,None)
pos_hint: {'center_x': 0.5, 'top': 1.0}
on_release: root.open_drop_down(self)
<CustomDropDown1>:
padding: [0,0,0,0]
Button:
text:"Item 1"
size:(200,50)
size_hint:(None,None)
text_size: self.size
valign: 'center'
padding: (10,0)
on_release: root.select(self.text)
Button:
text:"Item 2"
size:(200,50)
size_hint:(None,None)
text_size: self.size
valign: 'center'
padding: (10,0)
on_release: root.open_drop2()
Button:
text:"Item 3"
size:(200,50)
size_hint:(None,None)
text_size: self.size
valign: 'center'
padding: (10,0)
on_release: root.select(self.text)
<CustomDropDown2>:
dismiss_on_select: False
Button:
text:"Item 1,2"
size:(200,50)
size_hint:(None,None)
text_size: self.size
valign: 'center'
padding: (50,0)
on_release: root.select(self.text)
Button:
text:"Item 2,2"
size:(200,50)
size_hint:(None,None)
text_size: self.size
valign: 'center'
padding: (50,0)
on_release: root.select(self.text)
Button:
text:"Item 3,2"
size:(200,50)
size_hint:(None,None)
text_size: self.size
valign: 'center'
padding: (50,0)
on_release: root.select(self.text)

Categories

Resources