Python - How to call a function created into a different file - python

I'm pretty new in Python. I'm trying to develop a GUI using a drag and drop designer called PAGE (http://page.sourceforge.net/html/index.html) based on Tkinter.
After having created a new project, I added a button to a window. The following code is autogenerated by PAGE and saved into a file called 'myGui.py':
import sys
import tkinter as tk
import tkinter.ttk as ttk
from tkinter.constants import *
import myGui_support
class Toplevel1:
def __init__(self, top=None):
...
self.StartButton = tk.Button(self.top)
self.StartButton.configure(command=myGui_support.StartButton_Callback)
...
def start_up():
myGui_support.main()
if __name__ == '__main__':
myGui_support.main()
PAGE creates also a second file called 'myGui_support.py', in which after some import statements, the following code is included:
import myGui
def main(*args):
'''Main entry point for the application.'''
global root
root = tk.Tk()
root.protocol( 'WM_DELETE_WINDOW' , root.destroy)
# Creates a toplevel widget.
global _top1, _w1
_top1 = root
_w1 = myGui.Toplevel1(_top1)
root.mainloop()
if __name__ == '__main__':
myGui.start_up()
def StartButton_CallBack():
_w1.DebugLabel["text"] = 'START BUTTON PRESSED'
def StopButton_CallBack():
_w1.DebugLabel["text"] = 'STOP BUTTON PRESSED'
Once I run the myGui in Spyder, an Attribute error occurres:
AttributeError: module 'myGui_support' has no attribute 'StartButton_Callback'
How can it be possible? I already defined the callback function into the 'myGui_support.py'. Any suggestions?

Related

Tkinter Class Import Module Issue

I'm trying to keep my code clean by separating the GUI from the logic.
Inside of the 'main.py' file, I'd like to call functions from other files that are imported to build the GUI.
The problem is that I cannot figure out how to build a GUI from the 'main.py' file when I try to call another file as an imported module.
Here's what I have in the 'main.py' file:
from tkinter import *
import create_btn
class Main(Tk):
def __init__(self):
super().__init__()
self.title('Main Window')
self.geometry('600x400')
self.eval('tk::PlaceWindow . center')
if __name__ == '__main__':
app = Main()
app.mainloop()
And here is what I have in the 'create_btn.py' file:
from tkinter import *
def createBTN(self):
self.b1 = Button(root, text='B1')
self.b1.pack()
So, how exactly can I build a simple button from another file that I want to import into the 'main.py', or in other words, how do I get the 'create_btn.py' file to build the button inside of the 'main.py' file? A simple example would be greatly appreciated.
I have completely rewritten your code:
# main.py
from tkinter import *
import create_btn
class Main_app:
def __init__(self):
self.root = Tk()
self.root.title("Main Window")
self.geometry("600x400")
self.eval('tk::PlaceWindow . center')
self.button = create_btn.create(self.root)
self.root.mainloop()
a = Main_app()
# create_btn.py
from tkinter import *
class create:
def __init__(self, root):
btn = Button(root, text="Button")
btn.pack()
return btn
This way you can edit the button later in main.py

Getting button input from module on tkinter python

I am working on a project that uses buttons, but I would like to make it modular. The only problem I can't seem to get pass by is getting if someone is pressing the button from a different file
-file 1
from tkinter import*
class app2:
def __init__(self):
s = Tk()
but = Button(text="Test",command=subcommand)
but.pack()
s.mainloop()
def subcommand():
x = command()
x.command
class command:
def __init__(self,int):
self.command = ()
y = app2()
file 2-
from tkinter import*
from idea2 import *
def clicked():
print("HI")
x = command()
x.command(clicked())
My code basically just takes a function from another file and loads it into the command class. So basically the button can get different commands from different files. I don't know what to put for "x = command(???)" because I am trying to get that from a different file.
Basic question:
How to make my Tkinter button modular.
just pass the callback into the app2 constructor
file1
from tkinter import*
class app2:
def __init__(self,btn_callback=subcommand):
s = Tk()
but = Button(text="Test",command=btn_callback)
but.pack()
s.mainloop()
file2
from idea import app2
def my_callback(*args,**kwargs):
print("Buttton pressed...")
app = app2(my_callback)
or better yet make use of the event system in tkinter ... something like this
import tkinter as Tkinter
import tkinter.messagebox as tkMessageBox
def helloCallBack(*a,**kw):
tkMessageBox.showinfo( "Hello Python", "Hello World")
class MyApp(Tkinter.Tk):
def __init__(self):
super().__init__()
self.b = Tkinter.Button(self, text ="Hello", command = lambda:self.event_generate("<<button_click>>"))
self.b.pack()
app = MyApp()
app.bind("<<button_click>>",helloCallBack)
app.mainloop()

Tkinter: properly pass the instance for unit test

I am trying to bring the Tkinter script to the testing. The application would be tested without opening the window, just simulate the button click. What I've done seems to be inappropriate, so how could I pass the instance properly? Thanks.
Here is the prototype of my code:
# importing Tkinter and math
from tkinter import *
import math
class calc:
def __init__(self,master):
"""Constructor method"""
master.title('Calculator')
master.geometry()
self.master = master
self.btn_equal = Button(self.master,text="=",width=11,height=3, fg="red", bg="light green",command=lambda:self.equals()).grid(row=4, column=4,columnspan=2)
self.e.grid(row=0,column=0,columnspan=6,pady=3)
def start_application():
root = Tk()
app = calc(root)
# print(app)
root.bind_class("Button", "<Button-1>", app.callback)
return root
if __name__ == "__main__":
start_application().mainloop()
Here is the testing code:
import unittest
from tkinter import *
from calculator2 import start_application
class TestCalculator2(unittest.TestCase):
# start the application, test, and destroy at the end of the test
async def _start_app(self):
self.app.mainloop()
def setUp(self):
self.app = start_application()
self._start_app()
def tearDown(self):
self.app.destroy()
class TestCalculation(TestCalculator2):
def test_startup(self):
title = self.app.winfo_toplevel().title()
expected = "Calculator"
self.assertEqual(title, expected)
def test_addition(self):
self.btn_equal.invoke() # _Tkinter.tkapp has no attribute, since root is not calc object
The short answer is that the Button widget calls the grid, leading to the NoneType. The correct way of instantiating a button inside a class with position should be:
self.btn_equal = Button(self.master,text="=",width=11,height=3, fg="red", bg="light green",command=lambda:self.equals())
self.btn_equal.grid(row=4, column=4,columnspan=2)
On the other hand, the correct way to instantiate the calc class mentioned above and write a successful unit test with invoke(), which clicks the button. The code won't open the GUI, and the testing script works (with warning):
class TestCalculator2(unittest.TestCase):
# start the application, test, and destroy at the end of the test
async def _start_app(self):
self.app.mainloop() # the root in Tkinter activates the mainloop()
def setUp(self):
self.app = start_application() # activate the root
self.calc = calc(self.app) # instantiate the calculator
self._start_app()
def tearDown(self):
self.app.destroy()
class TestCalculation(TestCalculator2):
def test_startup(self):
title = self.app.winfo_toplevel().title()
expected = "Calculator"
self.assertEqual(title, expected)
def test_addition(self):
self.calc.btn_AC.invoke() # click AC to clear the place
self.calc.btn_7.invoke() # click button 7
self.calc.btn_plus.invoke() # click button +
self.calc.btn_5.invoke() # click button 5
result = self.calc.btn_equal.invoke() # click button equal, get the value
self.assertEqual(result, 12)
Note that the code snippet just gives a brief idea of how unit testing works on Tkinter, the calc class provided is incomplete.

python program using tkinter wont run due to a tclError

I'm trying to learn how to make a GUI with tkinter the conde is rather basic but I get the following error:
Exception has occurred: TclError
no display name and no $DISPLAY environment variable
File "/home/josh/Documents/VSC/python/SECOM/mainWindow.py", line 7, in __init__
self.wind = Tk()
File "/home/josh/Documents/VSC/python/SECOM/mainWindow.py", line 12, in <module>
MW = mainWindow()
When I google such error there is only answer for raspberry pi or remote servers and stuff. Im just using ubuntu(20.04) and have a conda (4.8.3) venv with python (3.8). I'm also using VSC and have the venv as interpreter in VSC. HELP :c
MainWindow.py
from tkinter import ttk
from tkinter import *
class mainWindow:
def __init__(self):
self.title = "SECOM"
self.wind = Tk()
self.wind.title(self.title)
if __name__ == '__main__':
MW = mainWindow()
window.mainloop()
You are talking a lot about windows in your code, but not much of anything is actually a window. Some of it is nothing, at all. Try This.
import tkinter as tk
class Root(tk.Tk):
def __init__(self, **kwargs):
tk.Tk.__init__(self, **kwargs)
#PUT YOUR APP HERE
if __name__ == '__main__':
root = Root()
root.title("SECOM")
root.mainloop()
Here are the problems with your script
from tkinter import ttk
#importing like this pollutes your namespace
from tkinter import *
class mainWindow:
def __init__(self):
#there is no reason to store a reference to the title
self.title = "SECOM"
#why are you burying your root in a class property
self.wind = Tk()
#this is why you don't need a reference to title
self.wind.title(self.title)
if __name__ == '__main__':
#sure
MW = mainWindow()
#window? window where? You buried this in MW.wind
window.mainloop()

Building a tkinter GUI module, so the main program doesn't need to import tkinter

I want to create a GUI module that I can import in my main program without having to import tkinter there, letting just the module handle everything. Here's how I imagine that it might work:
main.py
import gui as g
def update():
#Update the GUI with new Data from this main program
GUI = g.gui()
gui.after(1000, update)
gui.mainloop()
gui.py
import tkinter as tk
class viewer(tk.Frame):
#Some variables
def __init__(self, parent):
tk.Frame.__init(self, parent)
self.parent = parent
self.initialize(400, 100)
def initialize(self, width, height):
#Initialize some widgets, place them on grid, etc
def start(self):
#Do some other stuff, make a main window, configurations, etc
print('Started!')
Edit: "Don't ask for opinion"
How do I make this work?
import tkinter as tk
import gui as g
root = tk.Tk()
GUI = g.gui(root)
GUI.after(1000, update)
GUI.mainloop()
The above is what I don't want.
I used a workaround that seemed plausible to me:
main.py
import gui
GUI = gui.start()
GUI.after(1000, update)
GUI.mainloop()
gui.py
import tkinter as tk
def start():
root = tk.Tk()
run = viewer(root) # <- The class provided above
return run

Categories

Resources