I'm quite new to kivy and programming in general, and am having issues with my code. I simplified it down a lot to try get to the root issue, but it still seems to be not be working. Basically this kivy file is supposed to produce an orange square, and then change the size of the square to an integer value produced by a sensor at COM7. So far, at startup a square is produced, and the sensor does successfully pass integer values to python. I tried changing the value of the NumericProperty "first_rect," but no matter how I try to redefine first_rect, it's value doesn't change, and the size of the rectangle never changes. I have the feeling that there is something very small and straightforward missing, but I'm not sure what it is.
Any help would be greatly appreciated!
.py file
import serial
import time
from functools import partial
from kivy.uix.widget import Widget
from kivy.app import App
#kivy.require("1.10.0")
from kivy.clock import *
from kivy.uix.screenmanager import ScreenManager, Screen, SlideTransition
from kivy.properties import ObjectProperty, NumericProperty
from kivy.properties import StringProperty
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.slider import Slider
from kivy.uix.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.config import Config
from kivy.lang import Builder
from functools import partial
import time
i = 10
class Bar(Widget):
pass
class Trial(Screen):
rect1 = ObjectProperty(None)
# Clock.schedule_interval(Trial().update, 1.0/60.0)
def update(self):
ser = serial.Serial('COM7', 9600, timeout=0)
thing = [0,0]
a = 1
while a==1:
Byte = ser.readline()
Byte = Byte.decode('utf-8')
Byte = Byte.strip()
Byte_proc = Byte.split(',')
if Byte_proc[0] != '':
try:
if Byte_proc[1] != '':
Byte_proc[0] = int(Byte_proc[0])
Byte_proc[1] = int(Byte_proc[1])
TestTrial_SmallApp().first_rect = Byte_proc[0]
print(TestTrial_SmallApp().first_rect)
dummy_var = int(Byte_proc[0])
print(dummy_var)
a = 0
return dummy_var
except:
pass
time.sleep(.02)
class TestTrial_SmallApp(App):
first_rect = NumericProperty(100)
def build(self):
#Builder.load_file('TestTrial.kv')
Trial().add_widget(Bar())
Clock.schedule_interval(lambda dt: Trial().update(), 1.0/60.0)
# Trial().rect1.bind(pos = (200,200))
Trial().update()
return Trial()
TestTrial_SmallApp().run()
.kv file
#:import utils kivy.utils
#:import Window kivy.core.window
#:import Widget kivy.uix.widget
<Trial>:
id: "trial"
rect1: bar_left
canvas.before:
Color:
rgb: 1, 1, 1
Rectangle:
pos: self.pos
size: self.size
#Rectangle orange bars
Bar:
id: bar_left
pos: 0.25*self.center_x, 0.02*self.height
<Bar>:
canvas:
Color:
rgb: utils.get_color_from_hex('#F68C43')
Rectangle:
pos: 300, 300
size: 300, app.first_rect
In your statements below
TestTrial_SmallApp().first_rect = Byte_proc[0]
print(TestTrial_SmallApp().first_rect)
each TestTrial_SmallApp() is creating a new instance of TestTrial_SmallApp class.I think that is not what you want. Create an instance that you assign to a reference and then use that reference to use the instance like
app = TestTrial_SmallApp()
app.first_rect = ...
print(app.first_rect)
Related
I have a GridLayout with 8 cols, and I add 64 Buttons. (so 8x8).
I want the Buttons to ALWAYS be quadratic, so I made that in my spot_init() function.
That all works great. When I make the Window smaller or bigger, the rest of my Screen gets black and the GridLayout stays in the Corner. But I wanted it to be centered.
For leftright that works perfectly fine but when i try applying that to updown as well, it does some weird things, I really cannot explain.
Some things I (maybe) found out:
When I do it exactly like right now, but in the code, the Y coord is 3 times as high as it should be for some reason.
When I then divide it by 3, it gets 7 times as high...
It doesn't change if I do it in .kv or in .py file
Moving GridLayout without RelativeLayout also doesn't work (almost the same thing happens)
Other askers seemed to have the same problem (or a similiar one) but their fixes didn't help me.
My .kv file:
RMainBoard:
<MainBoard>:
cols:8
# height: self.minimum_height
# size_hint_y: None
# size_hint_x: None
<RMainBoard#RelativeLayout>:
pos:(self.width/2-min(self.width/8,self.height/8)*4,self.height/2-(min(self.width/8,self.height/8))*4)
MainBoard:
My .py file:
#resize window (NEEDS TO BE AT VERY TOP)
from kivy.config import Config
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '600')
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.metrics import dp
from kivy.properties import NumericProperty
class MainBoard(GridLayout):
spots = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.spot_init()
def on_size(self,*args):
for spot in self.spots:
spot_size = min(self.width/8,self.height/8)
print(min(self.width/8,self.height/8))
spot.height = spot_size
spot.width = spot_size
def spot_init(self):
for i in range(0,64):
self.spots.append(Button(size_hint=(None,None),height=self.height/8,width=self.width/8))
self.add_widget(self.spots[i])
class TestApp(App):
pass
TestApp().run()
Thanks a lot <3
Rather than writing your own code to position the GridLayout, you can use the kv language to accomplish that. Here is a modified version of your code that does this:
# resize window (NEEDS TO BE AT VERY TOP)
from kivy.config import Config
from kivy.lang import Builder
Config.set('graphics', 'width', '600')
Config.set('graphics', 'height', '600')
from kivy.app import App
from kivy.uix.gridlayout import GridLayout
from kivy.uix.button import Button
kv = '''
RMainBoard:
<RMainBoard#RelativeLayout>:
MainBoard:
cols: 8
size_hint: None, None
# make MainBoard square
width: min(root.width, root.height)
height: self.width
# position MainBoard in center of RMainBoard
pos_hint: {'center_x': 0.5, 'center_y': 0.5}
<SquareButton>:
size_hint: None, None
# make the Button square
width: min(self.parent.width/8, self.parent.height/8) if self.parent else 100
height: self.width
'''
class SquareButton(Button):
pass
class MainBoard(GridLayout):
spots = []
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.spot_init()
def spot_init(self):
for i in range(0, 64):
self.spots.append(SquareButton(text=str(i)))
self.add_widget(self.spots[i])
class TestApp(App):
def build(self):
return Builder.load_string(kv)
TestApp().run()
Note that I included the kv as a string in the python code. That was just for my own convenience, and it could just as well be in your kv file.
I have defined a SquareButton class along with a <SquareButton> rule in the kv that keeps the SquareButton square. The Buttons created in the spot_init() method are now SquareButtons.
So I want to change background color every 5 seconds with this code
#:import C kivy.utils.get_color_from_hex
<TrainingTiming>
FloatLayout:
canvas.before:
Color:
rgba: C(root.color)
Rectangle:
pos: self.pos
size: self.size
I define root.color by StringProperty in my .py file and I get this error
Exception ignored in: 'kivy.graphics.instructions.RenderContext.set_state'
Traceback (most recent call last):
File "kivy\graphics\shader.pyx", line 245, in kivy.graphics.shader.Shader.set_uniform
File "kivy\graphics\shader.pyx", line 284, in kivy.graphics.shader.Shader.upload_uniform
IndexError: list index out of range
My app works but I get this error and I don't know what to do
program example
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.properties import StringProperty
from kivy.clock import Clock
Colors = ['#f6f946', '#21ac2f', '#d31010']
class TrainingWindow(Screen):
color = StringProperty()
def on_enter(self):
self.colorsnum = 0
self.schedule = Clock.schedule_interval(self.updatelabel, 5)
def updatelabel(self, dt):
global Colors
if self.colorsnum < len(Colors):
self.color = Colors[self.colorsnum]
self.colorsnum += 1
kv = Builder.load_file("main.kv")
class MyApp(App):
def build(self):
return kv
if __name__ == "__main__":
MyApp().run()
The problem is that you are defining the color as:
color = StringProperty()
This results in a color that is an empty string, that results in an empty list produced by kivy.utils.get_color_from_hex(). The kv:
rgba: C(root.color)
then sets the rgba to [], causing the IndexError: list index out of range.
The fix is to define the root property with a default hex color string. For example:
color = StringProperty('#d31010')
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.
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.
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.