I think this question is very basic, but it stops me for two days.
I want to make a simple Kivy-GUI-App. Drag a folder to a ScrollView, then the ScrollView show the files in the folder.
Here is where am I:
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
class DropApp(App):
def build(self):
box = BoxLayout()
scrV = ScrollView(width = 300, height = 400, size_hint_x=None, size_hint_y=None)
box.add_widget(scrV)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(100):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
scrV.add_widget(layout)
Window.bind(on_dropfile=self.handledrops(widget = scrV))
return box
def handledrops(self, widget, filename, *args):
if widget.collide_point(*Window.mouse_pos):
print(filename)
if __name__ == '__main__':
DropApp().run()
NOTE: drop to a widget not the window.
I did a lot of googling, studied a lot of examples. I cannot find what's wrong with the code.
Most examples on internet use a lot of classes. But what I want is window, button, label.... I try to understand what's class, what's init, what's self., what's super(). But they make the code abstract. So I avoid them as possible as i can. Hope someone can help me what's wrong with this code.
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.scrollview import ScrollView
from kivy.uix.gridlayout import GridLayout
class DropApp(App):
def build(self):
box = BoxLayout()
self.scrV = ScrollView(width = 300, height = 400, size_hint_x=None, size_hint_y=None)
box.add_widget(self.scrV)
layout = GridLayout(cols=1, spacing=10, size_hint_y=None)
layout.bind(minimum_height=layout.setter('height'))
for i in range(100):
btn = Button(text=str(i), size_hint_y=None, height=40)
layout.add_widget(btn)
self.scrV.add_widget(layout)
Window.bind(on_dropfile=self.handledrops)
return box
def handledrops(self, window_object, filename):
if self.scrV.collide_point(*Window.mouse_pos):
print(filename)
if __name__ == '__main__':
DropApp().run()
Related
My app (using kivy) needs to substitute text with widgets inside an unspecified number of buttons using iteration. I don't use kv language. Only the last button displays any content.
My app should display an unspecified number of buttons. Simplified example:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
class Layout(Widget):
def __init__(self, app):
super().__init__()
self.layout = BoxLayout(orientation='vertical', size=Window.size)
contents = ['text1', 'text2', 'text3']
for text in contents:
button = Button(height=300, size_hint=(1, None))
button.text = text
self.layout.add_widget(button)
self.add_widget(self.layout)
class MyApp(App):
def build(self):
self.form = Layout(self)
return self.form
def on_pause(self):
return True
if __name__ in ('__main__', '__android__'):
MyApp().run()
Only instead of text buttons display images with descriptions. I change the code:
import kivy
kivy.require('2.0.0')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.image import Image
class Layout(Widget):
def __init__(self, app):
super().__init__()
self.layout = BoxLayout(orientation='vertical', size=Window.size)
contents = [('img1', 'text1'), ('img2', 'text2'), ('img3', 'text3')]
for img, text in contents:
button = Button(height=300, size_hint=(1, None))
button_layout = BoxLayout(orientation='vertical', size_hint=(1, 1))
label = Label(text=text)
image = Image(source=f'{img}.jpg', size_hint=(1, 1), allow_stretch=True)
button_layout.add_widget(image)
button_layout.add_widget(label)
button.add_widget(button_layout)
self.layout.add_widget(button)
self.add_widget(self.layout)
class MyApp(App):
def build(self):
self.form = Layout(self)
return self.form
def on_pause(self):
return True
if __name__ in ('__main__', '__android__'):
MyApp().run()
And only the last button displays content.
As far as I can understand, at some point Python automatically gets read of the content of the previous button. How can I prevent it? Also what is the best way to center it?
I'm not a native speaker, so sorry for bad grammar. Thank you in advance.
After some days looking for an answer, I finally decided that it was time to ask some more experienced users ! Here is my problem : in the following piece of code (simplified version of the original code), when I open the Dialog by clicking on the button, the opened window doesn't have the right size, and so one part of the GridLayout is appearing outside this popup.
I anyone has an idea, thanks in advance !
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivymd.uix.dialog import MDDialog
class AppClass(MDApp):
def build_toolbar(self):
button = Button(text="Press")
button.bind(on_press=self.popup)
return button
def build(self):
self.theme_cls.theme_style = "Dark"
layout = BoxLayout(orientation='vertical')
toolbar = self.build_toolbar()
layout.add_widget(toolbar)
return layout
#==============================
def popup(self, instance):
print("called")
panel = self.build_settings_panel()
self.dialog = MDDialog(
type="custom",
title="Settings",
content_cls=panel
)
self.dialog.open()
def build_settings_panel(self):
panel = GridLayout(cols=2, row_default_height=100)
for i in range(4):
panel.add_widget(Label(text="Number"))
panel.add_widget(Label(text=str(i)))
return panel
if __name__ == '__main__':
AppClass().run()
It appears that the problem is the size of the panel. way to fix that is to just calculate that size and set it in the build_settings_panel():
def build_settings_panel(self):
row_height = 100
total_height = 0
panel = GridLayout(cols=2, row_default_height=row_height)
for i in range(4):
panel.add_widget(Label(text="Number"))
panel.add_widget(Label(text=str(i)))
total_height +=row_height
panel.height = total_height
return panel
You can try:
row_default_height=9
In your code:
from kivymd.app import MDApp
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivymd.uix.dialog import MDDialog
class AppClassjbsidis(MDApp):
def build_toolbar(self):
button = Button(text="Press")
button.bind(on_press=self.popup)
return button
def build(self):
self.theme_cls.theme_style = "Dark"
layout = BoxLayout(orientation='vertical')
toolbar = self.build_toolbar()
layout.add_widget(toolbar)
return layout
#==============================
def popup(self, instance):
print("called")
panel = self.build_settings_panel()
self.dialog = MDDialog(
type="custom",
title="[color=ffffff]Settings",
content_cls=panel
)
self.dialog.open()
def build_settings_panel(self):
panel = GridLayout(cols=2, row_default_height=9)
for i in range(4):
panel.add_widget(Label(text="Number"))
panel.add_widget(Label(text=str(i)))
return panel
if __name__ == '__main__':
AppClassjbsidis().run()
Pictures:
I am experimenting with Kivy. When I tried using a screen manager, when the application runs, there is a black screen, nothing appears
That is my code. I have no idea what is the problem. It seems that the GridLayout doesn't get displayed on the screen.
import kivy
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import *
from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
class load_file_screen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.my_layout = GridLayout(cols=1)
self.my_layout.cols = 1
self.label = Label(text="Loading files from here")
self.button = Button(text="Click to change")
self.button.bind(on_press=self.changer)
self.my_layout.add_widget(self.label)
self.my_layout.add_widget(self.button)
def changer(self, *args):
self.manager.current = "ViewFile"
class view_file_screen(Screen):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.my_layout = GridLayout(cols=1)
self.label = Label(text="View File here")
self.button = Button(text="Click to change")
self.button.bind(on_press=self.changer)
self.my_layout.add_widget(self.label)
self.my_layout.add_widget(self.button)
def changer(self, *args):
self.manager.current = "LoadFile"
class my_app(App):
def build(self):
self.my_screen_manger = ScreenManager(transition=SlideTransition())
self.my_screen_manger.add_widget(load_file_screen(name="LoadFile"))
self.my_screen_manger.add_widget(view_file_screen(name="ViewFile"))
# self.my_screen_manger.current = "LoadFile"
return self.my_screen_manger
application = my_app()
application.run()
In both your view_file_screen and your load_file_screen, you need to add the line:
self.add_widget(self.my_layout)
in the __init__() method.
i would like to ask for favor here for python kivy desktop application, i have small problem but it is so annoying. the problem that i have is switching between two buttons (Yes Button and No Button) in kivy Popup with keyboard "Tab key" is not working and also i want to be able pressing "Enter key" for the selected button processing the function.
here is my Popup looks like:
Popup screenshot
and the code of the popup is as follow:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
class testWindow(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def yes_btn(instance):
print("this function is called.")
contents = BoxLayout(orientation='vertical')
content_text = Label(text="Lanjutkan Transaksi?")
pop_btn = BoxLayout(spacing=10)
btn_yes = Button(text='Ya', size_hint_y=None, height=40)
btn_no = Button(text='Tidak', size_hint_y=None, height=40)
pop_btn.add_widget(btn_yes)
pop_btn.add_widget(btn_no)
contents.add_widget(content_text)
contents.add_widget(pop_btn)
pop_insert = Popup(title="Confirmation Message", content=contents, size_hint=(None, None), size=(300, 300))
btn_yes.bind(on_release=yes_btn)
btn_no.bind(on_release=pop_insert.dismiss)
pop_insert.open()
class testApp(App):
def build(self):
return testWindow()
if __name__ == '__main__':
m = testApp()
m.run()
The popup is functioned properly when i click the button using mouse. as the popup picture above, i would like to make Yes Button focused and when i press "Enter key" popup dismiss and running the function i want. meanwhile to switch between button just press "Tab key".
i have been trying to find the way to solve the problems but still got no result, so please if anyone know how to solve my problem help me.
Here is a modification of your code that I think does what you want:
from kivy.app import App
from kivy.core.window import Window
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.uix.popup import Popup
from kivy.uix.label import Label
from kivy.uix.behaviors import FocusBehavior
# This is a Button that also has focus behavior
class FocusButton(FocusBehavior, Button):
first_focus = BooleanProperty(False)
def on_parent(self, widget, parent):
# if first_focus is set, this Button takes the focus first
if self.first_focus:
self.focus = True
class MyPopup(Popup):
def keydown(self, window, scancode, what, text, modifiers):
if scancode == 13:
for w in self.walk():
if isinstance(w, FocusButton) and w.focus:
w.dispatch('on_press')
def keyup(self, key, scancode, codepoint):
if scancode == 13:
for w in self.walk():
if isinstance(w, FocusButton) and w.focus:
w.dispatch('on_release')
def on_dismiss(self):
Window.unbind(on_key_down=self.keydown)
Window.unbind(on_key_up=self.keyup)
Builder.load_string('''
# provide for a small border that indicates Focus
<FocusButton>:
canvas.before:
Color:
rgba: 1,1,1,1
Rectangle:
pos: self.x-2, self.y-2
size: (self.size[0]+4, self.size[1]+4) if self.focus else (0,0)
''')
class testWindow(BoxLayout):
def __init__(self, **kwargs):
super().__init__(**kwargs)
def yes_btn(instance):
print("this function is called.")
contents = BoxLayout(orientation='vertical')
content_text = Label(text="Lanjutkan Transaksi?")
pop_btn = BoxLayout(spacing=10)
# set first_focus to True for this Button
self.btn_yes = FocusButton(text='Ya', size_hint_y=None, height=40, first_focus=True)
self.btn_no = FocusButton(text='Tidak', size_hint_y=None, height=40)
pop_btn.add_widget(self.btn_yes)
pop_btn.add_widget(self.btn_no)
contents.add_widget(content_text)
contents.add_widget(pop_btn)
pop_insert = MyPopup(title="Confirmation Message", content=contents, size_hint=(None, None), size=(300, 300))
self.btn_yes.bind(on_release=yes_btn)
self.btn_no.bind(on_release=pop_insert.dismiss)
# bind to get key down and up events
Window.bind(on_key_down=pop_insert.keydown)
Window.bind(on_key_up=pop_insert.keyup)
pop_insert.open()
class testApp(App):
def build(self):
return testWindow()
if __name__ == '__main__':
m = testApp()
m.run()
This code adds FocusBehavior to a Button to create a FocusButton, and adds key down and key up processing to the MyPopup class.
i have a kivy code that makes a label, button and a text box. i want to put the textbox next to the button and not under it, how can i do that?
import socket
import sys
import os
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.textinput import TextInput
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
from kivy.uix.popup import Popup
from kivy.uix.bubble import Bubble
from kivy.uix.gridlayout import GridLayout
from kivy.uix.label import Label
class TextInputApp(App):
def build(self):
layout = BoxLayout(padding=10, orientation='vertical')
btn1 = Button(text="OK", size_hint=(0.49, 0.1),pos_hint={'x': .51, 'center_y': .5})
btn1.bind(on_press=self.buttonClicked)
layout.add_widget(btn1)
self.txt1 = TextInput(multiline=False, text='',
size_hint=(0.5, 0.1))
layout.add_widget(self.txt1)
self.lbl1 = Label(text="Write your guess in the blank text box", size_hint=(1, None), height=30)
layout.add_widget(self.lbl1)
return layout
def buttonClicked(self,btn):
print "hi"
TextInputApp().run()
You could create another BoxLayout with horizontal orientation to harbor the Button and TextInput.
class TextInputApp(App):
def build(self):
layout = BoxLayout(padding=10, orientation='vertical')
# Second boxlayout
layout2 = BoxLayout()
# Add BoxLayout do main layout
layout.add_widget(layout2)
# Drop old size and pos_hints
btn1 = Button(text="OK")
btn1.bind(on_press=self.buttonClicked)
# Add Button to secondary boxlayout
layout2.add_widget(btn1)
self.txt1 = TextInput(multiline=False, text='',
size_hint=(0.5, 0.1))
layout.add_widget(self.txt1)
# Drop size_hint
self.lbl1 = Label(text="Write your guess in the blank text box")
layout2.add_widget(self.lbl1)
return layout
If you want to change the size of the Button and TextInput, you can set that in the secondary BoxLayout:
layout2 = BoxLayout(size_hint_y=None, height=30)