Popup and the corrupted table showing in kivy - python

I'm a newbie in Python and Kivy as well, so I have some trouble.
When I use kivy popup with showing the table (using "PrettyTable" module) I get broken view of this table.
My python code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from prettytable import PrettyTable
class GeneralForm(BoxLayout):
def RUN(self):
def TABLE():
x = PrettyTable(["City name", "Area", "Population"])
x.align["City name"] = "l" # Left align city names
x.padding_width = 1 # One space between column edges and contents (default)
x.add_row(["Adelaide",1295, 1158259])
x.add_row(["Brisbane",5905, 1857594])
return str(x)
popup = Popup(title='Test popup', content=Label(text=TABLE()), auto_dismiss=False)
popup.open()
class TimeTable(App):
def build(self):
return GeneralForm()
if __name__ == '__main__':
TimeTable().run()
My .kv code:
<GeneralForm>:
orientation: "vertical"
BoxLayout:
Button:
id: but
text: "Show!"
on_press: root.RUN()

Your problem is that the default label font is not a monospace font, where every character has the same width. You can instead set the font_name property to one that is. Possibly just 'DroidSansMono' will work, using the mono font kivy bundles.

Related

How to automatically update Kivy label created inside Python using Kivy properties

I want to implement the following:
Create a Kivy label inside python using add_widget() function. However, I want to benefit from the fact that the label is automatically updated when the text variable has changed (in my case self.gui_data.number). I know that I could achieve this when adding the label inside the .kv file, however this is not possible in my case since I need to build up parts of the GUI in run time.
Below you see code for a minimal example. There is a button add label which adds the label and the goal is that if one presses the decrement button, the label changes. Unfortunately this is not the case.
Any help is appreciated. Thanks!
main.py
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.widget import Widget
import parameters
from kivy.properties import StringProperty
from kivy.event import EventDispatcher
class PongBall(Widget):
gui_data = parameters.Data()
def add_label(self):
self.gui_data.number = self.gui_data.number + '5'
label = Label(text=str(self.gui_data.number))
self.ids.board.add_widget(label)
def decrement(self):
self.gui_data.number = self.gui_data.number + '6'
def reset_parameters(self):
self.gui_data.reset()
class PongApp(App):
def build(self):
game = PongBall()
return game
if __name__ == '__main__':
PongApp().run()
parameters.py
from kivy.properties import StringProperty
from kivy.event import EventDispatcher
class Data(EventDispatcher):
number = StringProperty("0")
def reset(self):
self.number = "0"
pong.kv
<PongBall>:
BoxLayout:
orientation: "vertical"
id: board
Button:
text: "Add label"
on_press: root.add_label()
Button:
text: "Decrement"
on_press: root.decrement()
Button:
text: "Reset parameters"
on_press: root.reset_parameters()
In order to do what you want, you need a Property that you can bind to. In the modified version of your code below, I have added a number Property to the PongBall class.
class PongBall(Widget):
gui_data = Data()
number = StringProperty(gui_data.number) # Property for binding
def add_label(self):
self.gui_data.number = self.gui_data.number + '5'
label = Label(text=str(self.gui_data.number))
# bind to the number Property
self.bind(number=partial(self.number_changed, label))
self.ids.board.add_widget(label)
def number_changed(self, label, pongball, number):
# change the Label text
label.text = number
def decrement(self):
self.gui_data.number = self.gui_data.number + '6'
def reset_parameters(self):

displaying a variable in a popup window with kivy

I am trying to make a program that reads the dictionary after the user inputs their name and assigns a random selection based on weighted values in the dictionary. As of now the logic for selecting a random value from the dictionary is working but I have it printing to the console. I would like it to appear in a popup window (which i have but cannot get the output variable to show up there)
four.kv
WindowManager:
MainWindow:
<MainWindow>:
name:'main'
player_python:player_kv
GridLayout:
cols:1
GridLayout:
cols:2
Label:
text:'Player:'
TextInput:
id: player_kv
multiline: False
Button:
text: 'Random'
on_press: root.btn()
<P>:
output:output
FloatLayout:
Label:
id: output
main4.py
import kivy
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.widget import Widget
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
from kivy.uix.popup import Popup
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import StringProperty
import random
#from Dict import *
#### example dictionary
character = {
'John':
{'Water': 2, #50%
'Fire': 1, #25%
'Earth': 1,}, #25%
'Bill':
{'Water': 1, #25%
'Fire': 2, #50%
'Earth': 1,}} #25%
####
class MainWindow(Screen):
player_python = ObjectProperty(None)
output = StringProperty('')
def btn(self):
show_popup()
player = self.player_python.text
weighted_list = []
for c in character[player]:
for w in range(character[player][c]):
weighted_list.append(c)
self.output= random.choice(weighted_list)
print(self.output) ###### instead of this printing to console I want it to display in popup window
self.player_python.text = ''
class P(FloatLayout):
pass
def show_popup():
show = P()
popupWindow = Popup(title='random character', content=show, size_hint=(None,None),size=(400,400) )
popupWindow.open()
class WindowManager(ScreenManager):
pass
kv = Builder.load_file('four.kv')
class FourApp(App):
def build(self):
return kv
if __name__ == '__main__':
FourApp().run()
https://gist.github.com/PatrickToole/00cc72cdd7ff5146976e5d92baad8e02
Thanks in advance
-P
I haven't tested this code, but try passing self.output to your show_popup() method. This would mean changing your btn() method to something like:
def btn(self):
player = self.player_python.text
weighted_list = []
for c in character[player]:
for w in range(character[player][c]):
weighted_list.append(c)
self.output= random.choice(weighted_list)
print(self.output) ###### instead of this printing to console I want it to display in popup window
self.player_python.text = ''
show_popup(self.output)
And in the show_popup() method:
def show_popup(output):
show = P()
show.output.text = output
popupWindow = Popup(title='random character', content=show, size_hint=(None,None),size=(400,400) )
popupWindow.open()
As I mentioned, I haven't tested this code, but something like this should work.

Kivy. Changing Layouts

I'm something of a newbie to Python and Kivy. After making some progress, I've hit a brick wall and no amount of internet searching can find an answer.
I have a python/kivy script which starts with a GridLayout selection menu. Then I would like to "Click Next" and replace the GridLayout with a BoxLayout to display the output. The Python script is:
import sys
from kivy.app import App
from kivy.uix.label import Label
from kivy.uix.checkbox import CheckBox
from kivy.uix.gridlayout import GridLayout
from kivy.uix.pagelayout import PageLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
from kivy.properties import StringProperty, ListProperty, DictProperty
from kivy.uix.widget import Widget
from brp_stats import *
from dice_roller import *
#from display import *
race = ''
statblock = ''
class Test(GridLayout):
def printcharacter(self,my_sb,my_cr,my_scm,my_scb):
printable_stats = print_stats(my_sb)
printable_rolls = print_rolls(my_cr)
printable_scm = print_scm(my_scm)
printable_scb = print_scb(my_scb)
self.clear_widgets()
self.add_widget(Label(text_size=(300, None),
text='Stats\n' + str(printable_stats)))
self.add_widget(Label(text_size=(300, None),
text='Rolls\n' + str(printable_rolls)))
self.add_widget(Label(text_size=(300, None),
text='SCM\n' + str(printable_scm)))
self.add_widget(Label(text_size=(300, None),
text='SCB\n' + str(printable_scb)))
wayout = Button(text='Way Out')
self.add_widget(wayout)
wayout.bind(on_press=self.canvas.clear)
# def bar():
# print ("BAR")
def human(self,a,b):
if b==True:
self.Status="human"
race=self.Status
statblock = human()
characteristic_rolls = rolls(statblock)
skill_category_modifiers = scm(statblock)
skill_category_bonuses = scb(statblock)
# TestApp.foo()
# Test.bar()
Test.printcharacter( \ self,statblock,characteristic_rolls,skill_category_modifiers,skill_category_bonuses)
class TestApp(App):
# def foo():
# print ("FOO")
def build(self):
self.title="BRP Character Generator"
return Test()
#### MAIN CODE ####
if __name__ == '__main__':
TestApp().run()
And the KV script is
<Test>:
cols: 2
canvas:
Color:
rgb: .2,.2,.2
Rectangle:
pos: self.pos
size: self.size
Label:
text: 'Human'
CheckBox:
group: 'race_group'
on_active: root.human(*args)
Button:
text: 'Next'
on_press: printcharacter()
What's happening is I select an option (Human in this example). It should wait until I click Next before displaying the results. However, as soon as I select Human, it immediately prints the result, in a GridLayout. Two questions spring to mind, which I'm hoping the experts here can help with:
1) Why does the Select screen not wait until I have clicked Next before displaying the results?
2) How do I swap the layout from Grid to Box when I display the second screen?
Any pointers or suggestions would be gratefully received.
Regards,
Colin
Your Checkbox calls Test.human(*args) when it is active (pressed/selected), and the last line of Test.human() calls Test.printcharacter() which explains why it is printing before you hit the 'Next' button.
Since your Test class inherits from GridLayout the widgets you add to a root Test layout will be added as if to a GridLayout. There are several ways to handle switching the layout to a BoxLayout, one of which would be to not inherit directly from a particular Layout class and instead add/remove different Layout widgets to Test as needed.
For example, Test could start off with a GridLayout child widget that is the parent of the Label, CheckBox, and Button widgets. Then when you want to switch layouts for printing your results, you clear those widgets and start by adding a BoxLayout to Test.

Is ScreenManager compatible with DropDown in Kivy?

I want to generate a dropdown-list in my second screen managed by Kivys ScreenManager. If I do so, I get this traceback:
...
File "C:/Users/ORANG/PycharmProjects/waldi/playground/cw.py", line 76, in on_text
instance.drop_down.open(instance)
File "C:\Kivy-1.9.0-py2.7-win32-x64\kivy27\kivy\uix\dropdown.py", line 215, in open
'Cannot open a dropdown list on a hidden widget')
kivy.uix.dropdown.DropDownException: Cannot open a dropdown list on a hidden widget
This is the code, which is basically the same as in this
example, just embedded in a screenmanager scenario simple as can be:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.dropdown import DropDown
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.textinput import TextInput
from kivy.properties import ListProperty, StringProperty
import re
from kivy.lang import Builder
Builder.load_string('''
<Lieferant>:
ComboLayout:
Label:
text: 'Label'
ComboEdit:
size_hint: .5, .3
pos_hint: {'center':(.5, .5)}
# `args` is the keyword for arguments passed to `on_text` in kv language
on_text: self.parent.on_text(self, args[1])
''')
class ComboEdit(TextInput):
"""
This class defines a Editable Combo-Box in the traditional sense
that shows it's options
"""
options = ListProperty(('',))
'''
:data:`options` defines the list of options that will be displayed when
touch is released from this widget.
'''
def __init__(self, **kw):
ddn = self.drop_down = DropDown()
ddn.bind(on_select=self.on_select)
super(ComboEdit, self).__init__(**kw)
def on_options(self, instance, value):
ddn = self.drop_down
# clear old options
ddn.clear_widgets()
for option in value:
# create a button for each option
but = Button(text=option,
size_hint_y=None,
height='36sp',
# and make sure the press of the button calls select
# will results in calling `self.on_select`
on_release=lambda btn: ddn.select(btn.text))
ddn.add_widget(but)
def on_select(self, instance, value):
# on selection of Drop down Item... do what you want here
# update text of selection to the edit box
self.text = value
class ComboLayout(BoxLayout):
rtsstr = StringProperty("".join(("Substrate1,,,Substrate1,,,Substrate1,,,",
"Substrate1,,,Substrate1,,,Substrate_coating",
",,,silicon,,,silicon_Substrate,,,substrate_",
"silicon,,,")))
def on_text(self, instance, value):
if value == '':
instance.options = []
else:
match = re.findall("(?<=,{3})(?:(?!,{3}).)*?%s.*?(?=,{3})" % value, \
self.rtsstr, re.IGNORECASE)
# using a set to remove duplicates, if any.
instance.options = list(set(match))
instance.drop_down.open(instance)
class Intro(Screen):
pass
class Lieferant(Screen):
pass
class CWApp(App):
def build(self):
sm = ScreenManager()
sm.add_widget(Intro(name='Intro'))
sm.add_widget(Lieferant(name='Lieferant'))
return sm
if __name__ == '__main__':
CWApp().run()
Is it possible to combine them? How would you do this?
This code is running if I just comment this line out, which adds a screen before the screen with the dropdown:
sm.add_widget(Intro(name='Intro'))
Ok - for this question I got the "Tumbleweed Badget" - LOL
I admit it's a very special one and makes obvious, how much I am a beginner here. So I asked another question based on the same problem and spend some effort to make it easier to understand the code and to reproduce it. This paid off! Look here for the solution if you tumble once into that kind of problem: Is it a bug in Kivy? DropDown + ScreenManager not working as expected

Kivy accordion interaction

I have images loading in the kivy accordion and I want to print out the x and y coordinates below the images when I press the mouse button. I can't for the life of my figure this out. Every time I add anything it seems like it shuts the whole program down. I know that the widget I have will print to the console but I want to print it to the screen.
Here is the code I am using:
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.widget import Widget
class MouseWidget(Widget):
def on_touch_down(self, touch):
print(touch)
class MyApp(App):
def build(self):
root = Accordion(orientation='horizontal')
item= AccordionItem(title='Picture1')
src = "picture1.png"
image = Image(source=src,pos=(200, 100))
# add image to AccordionItem
item.add_widget(image)
root.add_widget(item)
item= AccordionItem(title='Picture2')
src = "picture2.png"
image = Image(source=src,pos=(200, 100))
# add image to AccordionItem
item.add_widget(image)
root.add_widget(item)
return root
if __name__ == '__main__':
MyApp().run()
Here's a simple modification to your program that adds the touch position to a label below the image, using kivy language to automatically bind to the necessary properties so that the display is updated when they change.
I'm not sure what problems you had in particular, so let me know if the way it works is not clear!
from kivy.uix.accordion import Accordion, AccordionItem
from kivy.uix.image import Image
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.properties import ObjectProperty, StringProperty
from kivy.uix.boxlayout import BoxLayout
Builder.load_string('''
<MouseWidget>:
image: image
label: label
orientation: 'vertical'
Image:
id: image
source: root.source
Label:
id: label
size_hint_y: None
height: 50
text: 'no touch detected'
''')
class MouseWidget(BoxLayout):
image = ObjectProperty()
label = ObjectProperty()
source = StringProperty()
def on_touch_down(self, touch):
if self.image.collide_point(*touch.pos):
self.label.text = str(touch.pos)
def on_touch_up(self, touch):
self.label.text = 'no touch detected'
class MyApp(App):
def build(self):
root = Accordion(orientation='horizontal')
item= AccordionItem(title='Picture1')
src = "picture1.png"
image = MouseWidget(source=src)
# add image to AccordionItem
item.add_widget(image)
root.add_widget(item)
item= AccordionItem(title='Picture2')
src = "picture2.png"
image = MouseWidget(source=src)
# add image to AccordionItem
item.add_widget(image)
root.add_widget(item)
return root
if __name__ == '__main__':
MyApp().run()
Every time I add anything it seems like it shuts the whole program down.
This sounds like your changes crashed the program. You should check the output of your program by running it in a terminal. It will print information about the error that can help you track down your mistakes.

Categories

Resources