I have been trying to learn how to use Kivy python and I would like to
Know how to interact with the Os console/terminal to run commands and
receive results. The tutorials I have seen so far only show how to create
widgets,buttons,etc
For example how do You get the result from running the command "uname"
displayed in kivy. With such code below. using "on press". How can I let it interact with the OS run a command and display it back in the kivy app. Is there any tutorial on creating desktop apps/utilities
from kivy.app import App
from kivy.uix.button import Button
class tutap(App):
def build(self):
return Button(text="Press here")
tutap().run()
Update:
Here is example of what Im trying to achieve.This uses the easygui module:
import subprocess
from easygui import *
msg= "what you want"
out = subprocess.check_output("uname -a",shell=True)
title = "My choice"
choices=["kernel version","nothing"]
choice=boolbox(msg,title,choices)
if choice==1:
msgbox(out)
elif choice==0:
msgbox("The End")
The simplest way I can think to do this is just make a function that writes to a file at the top of your file like this
def printlog(message):
with open('./log.txt','a') as f: f.write(message+"\n")
then in your program when ever you want the print out put simply put printlog("whatever you wanted printed!")
The file will be saved in the same folder as your program.
More of a you can theoretically open it while the program is running, but this is more useful as a postmourtum.
I don't really see the point of doing something like that but if you want you can call App.run() method in separate thread so it won't block command line.
An example using cmd module:
import logging
logging.getLogger("kivy").disabled = True
from kivy.app import App
from kivy.uix.listview import ListView
from cmd import Cmd
from threading import Thread
class MyApp(App):
def build(self):
self.lv = ListView()
return self.lv
def update(self, line):
self.lv.adapter.data.append(line)
return "list updated"
class MyCmd(Cmd, object):
def __init__(self, app, *args):
super(HelloWorld, self).__init__(*args)
self.app = app
def do_EOF(self, line):
self.app.stop()
return True
def default(self, line):
ret = self.app.update(line)
print(ret)
if __name__ == '__main__':
app = MyApp()
Thread(target=app.run).start()
MyCmd(app).cmdloop()
Here I how I went about getting console command output.
The python code first:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.popup import Popup
from kivy.properties import ObjectProperty
from kivy.uix.label import Label
import subprocess
class shellcommand(BoxLayout):
first=ObjectProperty()
second=ObjectProperty()
third=ObjectProperty()
def uname(self):
v=subprocess.check_output("uname -a",shell=True)
result=Popup(title="RESULT",content=Label(text="kernel is\n" + v))
result.open()
def date(self):
d=subprocess.check_output("date",shell=True)
res=Popup(title="DATE",content=Label(text="the date today is\n" + d))
res.open()
def last(self):
last=subprocess.check_output("w",shell=True)
ls=Popup(title="LOGIN",content=Label(text="logged in \n" + last))
ls.open()
class shellApp(App):
def build(self):
return shellcommand()
shellApp().run()
And then the kivy file named shellapp.kv
<shellcommand>:
orientation: "vertical"
first:one
second:two
third:three
canvas:
Rectangle:
source: "snaps.png" #location of any picture
pos: self.pos
size: self.size
BoxLayout:
orientation: "horizontal"
Button:
id:one
text: "UNAME"
background_color: 0,0,0,1
font_size:32
size_hint:1,None
on_press: root.uname()
Button:
id:two
text: "DATE"
background_color: 1,1.5,0,1
font_size:32
size_hint:1,None
on_press: root.date()
Button:
id: three
text: "LOGGED IN"
background_color: 1,0,0,1
font_size:32
size_hint: 1,None
on_press: root.last()
If there is a way to improve this code please let Me know how to.Thanks
Related
I'm trying to make a Kivy interface that updates constantly when values imported from other files are constantly changing.
Questions:
How do I make it so, when I change the value of the "fk" variable in
test.py, that the Kivy app updates, without me having to restart the
program?
What is the use of "AnchorLayout" in class Interface(AnchorLayout): ?
I've tried to Google this, and still not 100% sure. Why put self in def build():?
What is the use of self.update in the code?
Questions 2 and 3 are unrelated to my main questions, but if anyone can help, that would be great.
What I have tried and failed:
main.py:
from kivy.app import App
from kivy.uix.anchorlayout import AnchorLayout
from kivy.lang import Builder
import test123
Builder.load_file('main.kv')
Builder.load_file('robotinformation.kv')
class Interface(AnchorLayout):
val = NumericProperty(0)
class InterfaceApp(App):
def build(self):
Clock.schedule_interval(self.update, 1)
return Interface()
def update():
val = test123.numval()
if __name__ == '__main__':
InterfaceApp().run()
main.kv:
<Interface>:
BoxLayout:
orientation: 'vertical'
StackLayout:
orientation: 'tb-rl'
RobotInformation:
id: _robot_information
...
robotinformation.kv:
<RobotInformation#BoxLayout>:
BoxLayout:
orientation:'vertical'
Label:
text: app.val
...
test123.py:
def numval():
fk = 101
return fk
First of all, I'd like to clarify that I have absolutely 0 background as a software engineer and this is the first time I'm using python for something besides API's and creating excel/plots.
My issue is that I was trying to create an app using kivy and then I imported the kivy.core.window library a blank screen appears.
I've seen that this issue is fairly common when using kivy and multiprocessing, but none of the information I found fixed my problem. Result of running my code without the kivy.core.window library:
Result when adding said library:
Also, if I wait like 10 seconds the blank screen disappears and kills the count_time process.
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
import time
from datetime import datetime
import multiprocessing as mp
from multiprocessing import Process, Queue, freeze_support
Builder.load_string('''
<TestScreen>:
BoxLayout:
orientation: "vertical" # place object vertically
Label:
size_hint: 1, 1
text: 'TITLE'
font_size: 150
color: 1, 1, 1, 1
Button:
text: 'start'
on_press: root.start_mp()
Button:
text: 'stop'
on_press: root.stop_time()
''')
def count_time(x):
for i in range(x):
print('count={}'.format(i))
time.sleep(1)
class Test(App):
def build(self):
sm.add_widget(TestScreen(name='test'))
return sm
class TestScreen(Screen):
def __init__(self, **kwargs):
super(TestScreen, self).__init__(**kwargs)
def start_mp(self):
self.p1 = mp.Process(target=count_time, args=(10, ))
self.p1.start()
def stop_time(self):
pass
if __name__ == '__main__':
mp.freeze_support()
sm = ScreenManager(transition=NoTransition())
Test().run()
The problem is that when you run Process, it starts a new python proces and imports the current .py file. On most platforms, the line:
if __name__ == '__main__':
protects the Test().run() from being executed and starting another App and is enough to protect from another window being opened. However, it appears that importing kivy.core.window is enough to open another window (on Windows platform) when the original .py file is imported for multiprocessing. You can read about it here.
A really ugly work around is to protect all kivy imports (and as a result, all the kivy code) with a if __name__ == '__main__': line. Like this:
import time
import multiprocessing as mp
def count_time(x):
for i in range(x):
print('count={}'.format(i))
time.sleep(1)
if __name__ == '__main__':
mp.freeze_support()
from kivy.core.window import Window
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen, NoTransition
Builder.load_string('''
<TestScreen>:
BoxLayout:
orientation: "vertical" # place object vertically
Label:
size_hint: 1, 1
text: 'TITLE'
font_size: 150
color: 1, 1, 1, 1
Button:
text: 'start'
on_press: root.start_mp()
Button:
text: 'stop'
on_press: root.stop_time()
''')
class Test(App):
def build(self):
sm = ScreenManager(transition=NoTransition())
sm.add_widget(TestScreen(name='test'))
return sm
class TestScreen(Screen):
def __init__(self, **kwargs):
super(TestScreen, self).__init__(**kwargs)
def start_mp(self):
self.p1 = mp.Process(target=count_time, args=(10,))
self.p1.start()
def stop_time(self):
pass
Test().run()
I have made a simple app that uses urlrequest and the Wikimedia api to get some information from Wikipedia. While this perfectly works on my computer (it shows the information), it does not on my phone (it shows nothing).
The main script:
from kivy.network.urlrequest import UrlRequest
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App
from kivy.properties import StringProperty
class WikiApp(App):
summary = StringProperty()
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.summary = ""
def results(self, req, result):
self.summary = str(result["query"]['searchinfo']['totalhits'])
def build(self):
return MainScreen()
def generate(self):
req = UrlRequest('https://en.wikipedia.org//w/api.php?action=query&format=json&list=search&srsearch=abc', self.results)
class MainScreen(BoxLayout):
"""Class for the main screen widget"""
pass
and the kv file:
<MainScreen>:
orientation: 'vertical'
BoxLayout:
Label:
id: SummaryLabel
text: app.summary
size_hint_y: None
text_size: self.width, None
height: self.texture_size[1]
BoxLayout:
Button:
id: generate
text: "Generate"
on_release: app.generate()
Why is it not working on my phone ? Is there something I need to specify in the spec file ?
Thank you for your help !
Try import certifi then add another parameter to your UrlRequest function -- ca_file=certifi.where()
For Example:
req = UrlRequest('https://en.wikipedia.org//w/api.php?action=query&format=json&list=search&srsearch=abc', self.results, ca_file=certifi.where())
You should put INTERNET permission in the buildozer.spec file:
android.permissions = INTERNET
And after launch of the app, manually give the permission for internet going to the app info. If you want the app to prompt for the permission then you need to implement request_permissions, check_permission methods in your code.
When i run the file, the buttons show up. Everything looks fine, until i click button 1 for the method Main.c() to get called. the interpreter spits out an exception claiming i haven't defined it yet, when i have. I cannot find a solution anywhere.
the .py file:
import kivy
from kivy.app import App
from kivy.uix.button import Button
from kivy.core.window import Window
from kivy.lang.builder import Builder
kivy.require("1.11.1")
class Main:
#staticmethod
def c():
print("c")
class Start(App):
def setup(self):
Builder.load_file('start.kv')
Start().run()
the .kv file:
BoxLayout:
Button:
id: btn1
text: "Button 1"
on_press: Main.c()
Button:
text: "Button 2"
on_press: print(8 * 8)
There are many problems with your code, but, one way to do what you ask for is to
Create an instance of your Main class in your App class: self.main = Main()
Call this instance from your kv code: on_press: app.main.c()
Simple problem I'm having:
When I click a button in my Kivy/Python app, I want to gain access to the ID of that button.
# Kivy code
Button:
id: position_1
on_press: app.access_button_id()
I have had various trial and error attempts but I cannot figure it out. The button is nested as follows (as part of a bigger app), if this is a factor in my problem:
FloatLayout:
AnchorLayout:
ScreenManager:
Screen:
BoxLayout:
FloatLayout:
Button:
id: position_1
on_press: app.access_button_id()
Here is my Python code, which returns all of the id's. That's as close as I have got:
# Python code
def access_button_id(name):
print(self.root.ids)
The problem I've got is that I don't even know what I should be looking at in the documentation as I do not fully understand the terminology yet, so I can't find the right information to learn from.
EDIT:
The (name) passed into the function is for some other functionality, not related to this problem.
You already know the id - you set it yourself. These are mostly used as a hard-coded values in your code:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder
Builder.load_string('''
<MyWidget>:
Button:
id: id_value_1
text: 'Print my id'
on_press: print({'id_value_1': self.proxy_ref})
Button:
id: id_value_2
text: 'Print all ids'
on_press: print(root.ids)
''')
class MyWidget(BoxLayout):
pass
class MyApp(App):
def build(self):
widget = MyWidget()
print({'id_value_1': widget.ids['id_value_1']})
return widget
if __name__ == '__main__':
MyApp().run()
Why do you need id of a Button if you already have an access to it? What are you trying to accomplish?
EDIT
An example solution to problem mentioned in the comment:
import random
import functools
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.lang import Builder
Builder.load_string('''
<MyWidget>:
Button:
text: 'B1'
on_press: root.open_popup(self)
Button:
text: 'B2'
on_press: root.open_popup(self)
''')
class MyWidget(BoxLayout):
def open_popup(self, caller):
fun = functools.partial(self.rename, caller)
popup = Popup(
title='Test popup',
content=Button(
text='rename',
on_press=fun
),
size_hint=(None, None), size=(400, 400)
)
popup.open()
def rename(self, caller, *args):
caller.text = ''.join(chr(random.randint(48, 90)) for i in range(5))
class MyApp(App):
def build(self):
return MyWidget()
if __name__ == '__main__':
MyApp().run()