I have a kivy program that has a ‘sqlite’ database containing details of a golf competition which displays information & warning messages via a standard Pop-up function - pop_mess()
For testing purposes I open an alternative ‘testing’ database in a function – set_test_db(). When this is done I would like to change the background colour of the pop-up to warn the user that the main database is not being used.
I have tried to do this (code at end of 'set_test_db'). However although the routine retrieves the current background colour correctly it will not change it.
Can someone point me in the direction of a solution. The coding method works fine for changing the text properties of a widget. (similar questions usually refer to text properties). I have used both list & tuple for colour values.
In .ky file
<CustomPopup>:
popup_message: popup_message
size_hint: .98, .75
id: popup_id
title: "Casual and Ancient"
title_align: 'center'
title_color: 1,.5,.3,1
BoxLayout:
id: contentbox
orientation: 'vertical'
TextInput:
id: popup_message
color: .3,.4,1.0,1
background_color: [.7,1.0,.2,1]
text: "text message goes here"
font_size: 16
font_name: 'RobotoMono-Regular'
…..
CaaRoot:
<CaaRoot>:
orientation: 'lr-tb'
padding: 10
etc
...
in main.py
(self = CaaRoot)
...
def pop_mess(self,message):
p_up=CustomPopup()
lab=p_up.ids['popup_message']
lab.text=message
p_up.open()
...
def set_test_db(self):
# on button in CaaRoot
# open test data base instead of real
if self.db != None:
print 'Cannot Open Test Data Base - already running'
else:
# open ‘test’ database
# set background colour of popup to warn user.
fn='/home/.... caatestdb.db
self.op_db(fn)
self.testing='TEST database'
p_up=CustomPopup()
lab=p_up.ids['popup_message']
x=lab.background_color
new_col=[.9,.3,.3,1]
lab.background_color=new_col
self.pop_mess('color set to : '+str(new_col)+ ' was : '+str(x))
the popup displays
color set to : [0.9, 0.3, 0.3, 1] was : [0.7, 1.0, 0.2, 1]
(with background still set to [0.7, 1.0, 0.2, 1])
Have a look at kivymd, which solves issues like that very well. It is basically a very elegant template for kivy based on Google's Material Design.
For me it makes all the coloring stuff and appearance in general much easier, especially as I am not a designer but a programmer.
The Demo has also a very complete sets of examples including popups.
On further investigation of my problem I came across the similar question (Changing Background of Kivy Popup )
The fact that the solution given to that was “non-intuitive” involving the properties of the ‘inherited’ Canvas element(?) made me realise (remember ?) than some widgets do not have the full range of modifiable properties.
The 'background_color' property that I was retrieving was a property inherited from the Canvas which cannot be easily changed.
I have avoided the problem by creating a ‘popup’ widget whenever I wish to use it rather than modifying an existing widget. I still cannot (simply) change the background_color of the popup but I can change the background color of the parent element so that the user’s eye immeditely sees something different. I can also change the text color when calling the popup message function.
def pop_mess(self,message,colour=(.9,.6,.9,1)):
#
# text color can ve overridden by the 'colour' parameter
# self.backc can be set as required to set the color behind the
# popup depending on circumstances
popup=Popup(title='Casual & Ancient', \
content=Label(text=message,color=colour,\
font_name = 'RobotoMono-Regular'),\
size_hint=(.98,.75),background_color=self.backc)
popup.open()
I'm not completely sure that the analysis is correct or that there may be some side-effects but it seems to work ok (and was somewhat simpler to code)
Related
I'm working on a Kivy app which should generate plots when the user clicks on an item from a menu. When the user clicks the item, it opens a new screen which should generate the plot. My problem is that I can't seem to get Kivy to show the plot. My code executes without errors so I'm not sure where I'm going wrong.
I've looked for questions on this issue and the best I could find is here (Real-time plotting using matplotlib and kivy in Python) but that didn't work for me.
I also have a secondary question about re-defining the on_enter method of the Screen class so that it can use the App method for creating the plot. Is this possible?
Python code (function defined as part of the App class)
def grp_enter(self):
grid = GridLayout(rows = 1, cols = 1)
#grid.add_widget(FigureCanvasKivyAgg(plt.gcf())) should have prepared a canvas but one didn't appear
self.track_instance.associations() # generates the plot
KV code
<GroupScreen>:
on_enter: app.grp_enter()
name: 'groups_screen'
Button:
on_release:
app.root.transition = SlideTransition(direction = "right")
app.root.current = 'main'
text: 'back to the home screen'
font_size: 50
I could be wrong as I haven't been able to test your code but I believe that your screen doesn't get updated when you try to display your plot. You should try to use the schedule function:
clock.schedule_once(function_showing_plot).
So in your grp_enter function, you would call your track_instance.associations() function as such:
clock.schedule_once(track_instance.associations)
Hope this helps.
I'm new to Kivy and having trouble specifying the background color of a Button. Here's my simple example:
# custombutton.py
from kivy.app import App
from kivy.uix.widget import Widget
class MyWidget(Widget):
pass
class CustomButtonApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
CustomButtonApp().run()
And the accompanying kv file custombutton.kv:
#:kivy 1.7.2
<MyWidget>:
canvas:
Color:
rgb: (0.93, 0.93, 0.93)
Rectangle:
pos: self.pos
size: self.size
Button:
center: self.parent.center
font_size: 14
height: 28
background_color: (1.0, 0.0, 0.0, 1.0)
text: "I'm a Button"
I'm sure I'm missing something obvious, but I've been messing with this for over an hour now and getting nowhere. The button seems to get colored a hint of very dark red:
Is this not the way to specify the background color for a Button in Kivy?
Thanks!
It's been a while since this was first posted so maybe with updates they came up with a better solution:
Button:
background_normal: ''
background_color: 1, .3, .4, .85
Since the Button has a default grey, adding background color will only tint the button. By setting background_normal to '' that resets the default to white. From the white canvas the background_color works as you would expect.
Documentation
1) https://kivy.org/docs/api-kivy.uix.button.html?highlight=button#module-kivy.uix.button
Ah, this is a common confusion. The problem is that Button.background_color really works as a kind of tint, not just a block colour. Since the default background is a grey image (the one you normally see if you make an unstyled button), what you end up seeing is a red tint to that grey image - which comes out as the dark red you observe.
You can get the behaviour you want by replacing the background image to just one that's plain white (it doesn't have to be more than a few pixels), or by otherwise playing with the background_normal and background_down properties. When your background_color tints the new pure white image, you get the pure red you're after.
I guess this isn't so clear in the docs, I'll try to improve it.
The problem with using background_normal = '' is that it blows away the kivy button image with raised edges/shadowing and setback. One way to get a raised button of a specific color would be to make your own atlas using gimp or other editors. However, by some trial and error I found that the Button background_color attribute can implement a tint as well as the documented shade. In other words, it can have 'RGB' values > 1. So to get an exact button color with the kivy button defaulttheme for raised edges, use:
import numpy as np
# the defaulttheme for kivy buttons is grey 88,88,88
kivy_defaulttheme_color = np.array([88,88,88,256])/256
desired_button_color = np.array([78,101,115,256])/256
tintshade_color = desired_button_color / kivy_defaulttheme_color
Button(background_color = tintshade_color)
which demonstrates both a tint and a shade.
I've made a rule in my kv for the Button class to have a specific background (provided in an image). When I created an ActionBar that contains ActionPrevious and ActionButton widgets, they both seemed to get the same background.
And I would understand that ActionButton instance got that background, since it inherits from Button and ActionItem classes, but why did the ActionPrevious get the same background? It inherits from BoxLayout and ActionItem, neither of which have anything to do with the Button class. What's the reason behind it?
Also, a side question
The ActionPrevious has a property with_previous which, when set to True, adds a clickable arrow. However, the title of the widget remains unclickable. But the docs say that this property would make the whole widget clickable. While it's not a big deal, I'd rather want the entire ActionPrevious widget background to change on press. Is it possible to achieve this?
So what I mean is that when you press the Back arrow, only the space around it and the app icon turns blue, but the text doesn't, as if it's part of a different widget.
Here is the code to visualize the question:
from kivy.base import runTouchApp
from kivy.lang import Builder
from kivy.uix.actionbar import ActionBar
Builder.load_string('''
<Button>:
background_normal: 'some_file.png'
<MenuBar>:
ActionView:
ActionPrevious:
title: "Log out"
with_previous: True
ActionButton:
text: "Settings"
''')
class MenuBar(ActionBar):
pass
runTouchApp(MenuBar())
Okay, so the truth was in the style.kv file. Basically, ActionPrevious widget has the following structure:
<ActionPrevious>:
GridLayout:
ActionPreviousButton:
GridLayout:
ActionPreviousImage:
id: prev_icon_image # the "back" arrow
ActionPreviousImage:
id: app_icon_image # the app icon
Widget:
# perhaps something to split the title from the GridLayout
Label:
id: title # the title
And the ActionPreviousButton inherits from Button, so that's why the ActionPrevious arrow part was getting that background.
Here also lies the answer to the side question. Since the clickable part is the ActionPreviousButton, and the title is kept in a Label, that is not a child of it, the text is unclickable. So to fix that, one has to create a custom class and put the Label as a child of the ActionPreviousButton.
Hopefully this will be an easy question for some of you. So I am working on some code to interface with a heater controller. The GUI is written mostly in Kivy language (to compartmentalize the various screens), but I have a .py file that ties all the Kivy files together. Within one my Kivy files, there are a few TextInput fields that are for a user to define a few numerical values. Once the text fields are filled, the user clicks on the "Start" button to begin the heater test.
Now, my question is when using the "Start" button as my flag, how can I get Python to read the numerical values that are in the fields? I've looked online and posts about using the .get and raw_input methods, but nothing that has Python retrieving and interpreting values from Kivy code. Any help would be much appreciated!
This is part pf my .py file, which where I need the user-input values to be evaluated...
class ControllerScreen(Screen):
def build(self):
return ControllerScreen()
def CreateExcelFile(self):
wb = Workbook()
ws = wb.active
ws.cell('A1').value = 'Timestamp'
ws.cell('B1').value = 'Temperature'
ws.cell('C1').value = 'Batch 1'
ws.cell(row=2, column=1).value = 000
wb.save("Spreadsheet1.xlsx")
This is an excerpt from the Kivy file, containing the code for a single text field that a user types a number into...
<ControllerScreen>:
TextInput: #Ramp time increment field
id: ramp_time
font_size: 25
size_hint: 0.1,0.06
pos_hint: {"right":0.575, 'y':0.67}
Button: #Start analysis button
on_release: app.root.current = "home"
text: "Start"
font_size: 25
color: 0,1,0.5,1
size_hint: 0.29,0.075
pos_hint: {'x':0.35, 'y':0.1}
And lastly, here is a picture of the GUI to give some reference to the text fields I am regarding (the one circled in red is the one I reference in the code above)...
To access value of TextInput you need to use TextInput's property text, therefore to get a number you need to:
n = int(self.ids.ramp_time.text) #or float or whatever you need
However if you won't access the text in your ControllerScreen, then you need to manage a communication between your classes, so that you could use variables between them. You can achieve it with these answers: 1, 2 for example.
There's an option for you to set a filtering for your input so your user won't screw something up(e.g. inputs letter/s)
I've looked online and posts about using the .get and raw_input methods, but nothing that has Python retrieving and interpreting values from Kivy code.
I think the problem is that you looked for getting user's input directly from python and not from Kivy. I'd say Kivy is quite new, so there will be no mention in old tutorials/websites. There are tutorials and docs directly for kivy either on official website or youtube.
I'm currently struggling with a memory usage problem in Kivy.
When a popup is created and opened, memory usage goes up a little (which is normal), but when the user closes it (with the dismiss() method, which closes the popup and removes it from its parent), the memory isn't released.
So, if the user decides to open the popup a lot of times, the program will eventually use a lot of memory. Here is a part of my code that shows the problem by creating, opening and then dismissing a popup 500 times.
# py file
class OptionsView(Screen):
def popupLoop(self):
for x in range(0, 500):
popup = self.MyPopup()
popup.open()
popup.dismiss()
class MyPopup(Popup):
pass
# kv file
<OptionsView>:
BoxLayout:
orientation: "vertical"
Button:
text: "Popup Loop"
on_press: root.popupLoop()
<MyPopup>:
size_hint: (.6, .6)
title: "Confirmation"
BoxLayout:
Button:
text: "Cancel"
on_press: root.dismiss()
Pressing the "Popup Loop" button in the OptionView screen causes the program to jump from 1.2% memory usage to 11.7% (according to top). Resizing the window (which calls gc.collect()) does bring this number down a little bit, but it remains really high.
How can I prevent this from happening? (Bear in mind that I'm far from being a Python/Kivy expert, so even if the solution is really obvious to you, please try to explain it to me!)
popup.dismiss() will not remove the popup from memory immediately.
Maybe this will help How to force deletion of a python object?
Second; on why sometimes your popups get dismissed and sometimes they don't, you have to understand that UI frameworks need to be programmed using events. Events/progression do not happen in linear fashion.
Better test for what you are trying to check would be using Clock
self.pops = 0
Clock.schedule_once(self.test_pops)
def test_pops(self, dt):
if self.pops > 10:
return
self.pops += 1
pup = self.MyPopup()
pup.bind(on_parent=self.dismiss_pup)
pup.open()
def dismiss_pup(self, pup, parent)
# popup was opened, please close it now
pup.unbind(on_parent=self.dismiss_pup)
pup.dismiss()
Clock.schedule_once(self.test_pops)
It would be a lot simpler to just use the web debugger module geared towards this instead though.
http://kivy.org/docs/api-kivy.modules.webdebugger.html