Kivy call function in other screen - python

So I'm working on a kivy project and also learning the language for it (I mean python) and I have this little program here. So there are some language button on my first screen but I also have text to change in the second page. How can I call an other class' function in a class, or should I use a different way to change the textes? Any tipp would be helpful :) thanks
class ScreenOne(Screen):
def d_language(self):
self.hellolabel.text='Hallo'
def fr_language(self):
self.hellolabel.text='Bonjour'
class ScreenTwo(Screen):
def d_languagetwo(self):
self.otherlabel.text='Zweite seite'
def fr_languagetwo(self):
self.otherlabel.text='Deuxième page'

You can use the screen manager to get to the other screen
def d_language(self):
self.hellolabel.text = 'Hallo'
#now change the other label
s2 = self.manager.get_screen('name of the other screen')
#or ...
#s2 = self.manager.screens[1] # will also work...
s2.otherlabel.text = 'Zweite seite'
#or ...
#s2.d_languagetwo()
...

Related

Python - TypeError: Cannot create graphics instruction outside the main Kivy thread

I'm trying to change the screen after running this function which is a thread. but it gives me the error
TypeError: Cannot create graphics instruction outside the main Kivy thread
I researched online regarding this and they told me to use clock property but I don't know how I can use it here. I just want to be able to change graphic instructions from this command. but if I don't thread it the app goes into not responding.
This is my code:
class Notice(Screen):
def thread_notice(self):
t1 = Thread(target= Notice.sendNotice, args =(self,))
t1.daemon = True
t1.start()
def sendNotice(self):
my_big_chunk_of_code()
kv.current = 'menu'
You cannot do any kivy instructions outside of the main thread, which means you cant run sendNotice on a diffrent thread becuase it has kivy code in it... if my_big_chunk_of_code() takes time then remove the kv.current = 'menu' line and move it to, for example the thread_notice function.
By the way in the thread I suggest making the target: self.sendNotice instead of Notice.sendNotice which i think creates another instance of that class (not sure tho), it should work the same
I am late but well I am posting this answer so that It will help other in future , So Because you can not create graphics instruction outside the main Kivy thread, so you have to be bit tricky about it, I was facing the same problem while ago, So here is how I solve it, So you should first create a popup before starting a thread and than start your thread and if you want to pass argument in your function inside thread, you should use a lambda function like this.
self.showLoadingPopUp() # showing pop up before starting thread
try:
# Using lambda function for passing arguments in function inside thread
threading.Thread(target=lambda : self.yourFunction(argument)).start()
except:
print("Error: unable to start thread")
This will not block your UI and when you create popup function make sure to use a class variable for that, So you can able to close that popup from your thread function, here is the exaple -
class MyApp(App):
def __init__(self):
super().__init__()
self.window = None
self.loading = None
# Main Build function
def build(self):
self.window = GridLayout()
self.window.cols = 2
return self.window
def showLoadingPopUp(self):
content = BoxLayout(orientation='vertical')
self.loading = Popup(title="Loading", title_color='#FFFFFF', content=content, size=('700dp', '200dp'),
size_hint=(None, None),
auto_dismiss=False,
background='#FFFFFF')
content.add_widget(Label(text="Loading...", color="#FFFFFF"))
def _on_d(*args):
self.loading.is_visable = False
self.loading.bind(on_dismiss=_on_d)
self.loading.is_visable = True
self.loading.open()
while not self.loading.is_visable:
EventLoop.idle()
def yourFunction(self, argument):
for i in list:
# code
self.loading.dismiss() # dismissing old popup
So In short this function will first create a popup and than it will start a thread and when our work is done the thread will just close the popup with class variable in the end. Hope it's help.

Python CLR WinForms - Opening another from from an existing form

I am having some extreme difficulty with something so simple. All I am trying to do is launch another Windows Form from an existing Windows Form in Python. I've tried everything I can think of and I cannot figure out. Below is a example program:
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
clr.AddReference("System.ComponentModel")
from System.Windows.Forms import *
from System.Drawing import *
class MyForm(Form):
def __init__(self):
self.StartPosition = FormStartPosition.CenterScreen
self.btnTest = Button()
self.btnTest.Name = 'btnTest'
self.btnTest.Text = "Test"
self.btnTest.Size = Size(80, 30)
self.Controls.Add(self.btnTest)
self.btnTest.Click += self.Add_Control_Limits_Form_Click
def Add_Control_Limits_Form_Click(self, sender, args):
Application.Run(MySecondForm())
class MySecondForm(Form):
def __init__(self2):
self2.StartPosition = FormStartPosition.CenterScreen
self2.AutoScaleMode = AutoScaleMode.Font
self2.ClientSize = Size(800, 450)
self2.Text = "Form2"
Application.EnableVisualStyles()
Application.SetCompatibleTextRenderingDefault(False)
Application.Run(MyForm())
Which, when I run it, it gives me this error message:
InvalidOperationException : Starting a second message loop on a single thread is not a valid operation. Use Form.ShowDialog instead.
I don't think it's as simple as just putting MySecondForm.ShowDialog() since I have this as a class. What am I missing?
I figured it out.
So, within the button click event, add these lines of code:
self.TopLevel = False
YF = YourForm()
YF.ShowDialog()
self.TopLevel = True
...if you want it modal. I did.
You don't need the Application.Run(MySecondForm()) code within the button click event.
Then, within your second form class, just initialize your form the way you want.

How to execute a class method from another class with the method passed a parameter in Python

I'm a beginner in learning python..
I'm looking for help in solving an OOP problem
My main program has something simplified like below:
class abc(Frame):
def _init_(self, master)
Frame.__init__(self)
self.B1 = Mybutton(self.master, self.cmd)
def cmd(self):
print("hello world")
In the main program, I import Mybutton class in another file, which is simplified as below:
class Mybutton():
def _init_(self, parent, command):
self.command = command
def A_ramdom_fcn(self):
...
self.command() ------------------>> here I want to execute the command
in class abc, not in class Mybutton.
How to execute a method from another class that is passed as an instance method, you may ask why not just execute it in class abc, but I have event attached to button press, it needs to do a roundabout to achieve this..
First, fix the typos: missing : in abc's init method, and it should be __init__ (with two underscores) for both classes.
It seems like you've gotten yourself turned around. You've set things up correctly using composition: an abc has a Mybutton, and it looks like you correctly pass the function to Mybutton so that it can execute it. In fact, your code will work as written if you do, for example
a = abc(master) # no context for what master is, but I assume you have it
a.B1.A_ramdom_fcn()
With the way you've set things up, you don't want to import and make instances of Mybutton in your main program (what abc would they belong to?). You want to import and make instances of abc. You then access their internal Mybutton like I've shown in the example above. This works because when you pass self.cmd to the Mybutton constructor while inside the abc constructor, it's already a bound method of the abc you're constructing.
As an addendum, it looks like you might be having an XY problem with regards to why you need such a roundabout method. Is there any reason why you can't simply pass abc.cmd to the button press handler?
Theoretically, what you are trying is possible, you can capture the object method into variable and call it later (python 3):
class Window:
def __init__(self):
self.my_button = Mybutton(self.cmd)
def cmd(self):
print("hello world")
class Mybutton:
def __init__(self, command):
self.command = command
def a_ramdom_fcn(self):
self.command.__call__()
win = Window()
win.my_button.a_ramdom_fcn()
I assume you are trying to make the generic Button class which doesn't know what to do when it's clicked and you want to put the actual logic into your Window class.
That makes sense, but it would be even better to extract the logic into the third, Command class. This allows us to limit the Window responsibility and also avoid the trick with method-as-variable (the command we pass to the button object is just another object):
class HelloWorldCommand:
def execute(self):
print("Hello world")
class Window:
def __init__(self):
self.my_button = Mybutton(
HelloWorldCommand()
)
class Mybutton:
def __init__(self, command):
self.command = command
def a_ramdom_fcn(self):
self.command.execute()
win = Window()
win.my_button.a_ramdom_fcn()

Tkinter entry widget get is undefined, not updating to my main function,

i'm following a few different guides to re-learn Tkinter by writing a little application that grabs stock prices. My issue that I am up a wall against is calling the .get() method from my entry widget variable. I've seen a couple other suggestions to put all the widget creating inside a function and then call the function in the init method, however I'm getting the same error, even when using the self argument in front of my entry variables. I know it's an issue with the way i'm passing data from function to function, but I can't wrap my head around it. Here's the code, sorry for the wall of text:
class MyApp:
def __init__(self, parent):
self.myParent = parent
self.myContainer1 = Frame(parent)
self.myContainer1.pack()
self.createWidgets()
button1 = Button(self.myContainer1, command = self.button1Click)
button1.configure(text = "get quote")
button1.pack()
def createWidgets(self):
root.title("Stock App")
self.symbol = Entry(self.myContainer1)
self.symbol.pack()
self.symbol.focus_set()
def button1Click(self):
stock = symbol.get()
print stock
I've taken it down to simplest form even and just had the button1Click call a callback function-
def button1Click(self):
print callback()
def callback():
print symbol.get()
This returns the exact same error:
NameError: global name 'symbol' is not defined
Is it getting destroyed too early? how do I fix this?
I've referenced multiple documents for tkinter and have seen some great fixes but none are extensible, or um unable to see how they relate to me using it inside of an object.
Thanks in advance for the help.
As far as I can tell inside of your button1Click method you need to add self as in:
def callback():
print self.symbol.get()
You're missing self. to make the callback:
def callback():
print self.symbol.get()
instead.

Why can't I update wxPython's StaticText?

I'm writing a calculator using wxPython for the GUI. I've made a class called display to use StaticText to display the text. Anyways, when I try to update the screen, it raises an exception.
Here's the code:
class display:
def __init__(self,parent, id):
print "display class is working"
global string1
self.view = wx.StaticText(frame, -1, "Waiting", (30,7), style = wx.ALIGN_CENTRE)
#staticmethod
def update(self):
global string1
self.view.SetLabel(string1)
Whenever I try to run the Update() function, it raises this exception:
AttributeError: 'function' object has no attribute 'view'
When I wrote "self.view = wx. etc etc", I tried to set the StaticText to a variable name, so I could use the SetLabel function. The text seems to work until I try to update it. Why can't I update it? How do I fix it?
#staticmethods take no arguments ... so its not actually getting self ... you need to either make it a #classmethod which gets cls or you need to just make it a normal method
class display:
view = None
def __init__(self,parent, id):
print "display class is working"
global string1
display.view = wx.StaticText(frame, -1, "Waiting", (30,7), style = wx.ALIGN_CENTRE)
#classmethod
def update(cls):
global string1
cls.view.SetLabel(string1)

Categories

Resources