When using the Button object in Tkinter I get an error - python-3.x

When running this code:
import tkinter as tk
class MyApplication(tk.Tk):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.title('Programma')
self.geometry('500x400')
self.button = tk.Button(self, text='Execute', command=self.fun)
self.button.grid(row=0, column=4, stick=tk.W)
def fun(self):
print('Hello')
app = MyApplication()
app.mainloop()
I get the following error:
Traceback (most recent call last): File "C:/Users/Andrea/Desktop/hfhfhg.py", line 17, in <module>
app = MyApplication() File "C:/Users/Andrea/Desktop/hfhfhg.py", line 10, in __init__
self.button = tk.Button(self, text='Execute', command=self.fun) File "C:\WPy64-3910\python-3.9.1.amd64\lib\tkinter\__init__.py", line 2346, in __getattr__
return getattr(self.tk, attr) AttributeError: '_tkinter.tkapp' object has no attribute 'fun'
I understand that the code is not optimal for a GUI but I would like to understand how Tkinter works without using a frame object. Please can you help me?

Related

Python script doesn't recognize 'self' argument in PyQt MainWindow

I'm trying to get a PyQt lineEdit widget to place its' contents within a variable in the module 'followup' but for some reason the module does not recognize the PyQt MainWindow as being properly instantiated.
#workbot_main.py
import gspread
import os
import sys
sys.path.append(os.path.abspath(r"C:\Users\leamy\Desktop\work bot\workbot.py"))
sys.path.append(os.path.abspath(r"C:\Users\leamy\Desktop\work bot\initial.py"))
sys.path.append(os.path.abspath(r"C:\Users\leamy\Desktop\work bot\followup.py"))
import threading
import followup
import initial
from PyQt5 import QtWidgets
from PyQt5 import QtCore
from PyQt5.QtWidgets import QMainWindow, QApplication
from workbot import *
import workbot
#workbot.py is the QTdesigner file containing the widgets,
class MainWindow(QtWidgets.QMainWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.ui = Ui_MainWindow()
self.ui.setupUi(self)
followup_start_button = self.ui.followup_start_button
followup_start_button.clicked.connect(threads.begin_initialize)
def followup_starting_number(self):
num = self.ui.lineEdit.text()
return num
def begin_initialize(self):
t1 = threading.Thread(target = followup.initialize, args = ())
t1.start()
threads = Threads()
if __name__ == '__main__':
app = QtWidgets.QApplication([])
widget = MainWindow()
widget.show()
app.exec_()
#followup.py
import workbot_main
def initialize():
row_number.number = workbot_main.MainWindow.followup_starting_number()
print(row_number.number)
I get this error
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\leamy\anaconda3\lib\threading.py", line 973, in _bootstrap_inner
self.run()
File "C:\Users\leamy\anaconda3\lib\threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\leamy\Desktop\work bot\followup.py", line 313, in initialize
row_number.number = workbot_main.MainWindow.followup_starting_number()
TypeError: followup_starting_number() missing 1 required positional argument: 'self'
I can't understand why it doesn't work.
Edit:
If I try to use
row_number.number = workbot_main.widget.followup_starting_number()
instead of
row_number.number = workbot_main.MainWindow.followup_starting_number()
I get this error
Exception in thread Thread-1:
Traceback (most recent call last):
File "C:\Users\leamy\anaconda3\lib\threading.py", line 973, in _bootstrap_inner
self.run()
File "C:\Users\leamy\anaconda3\lib\threading.py", line 910, in run
self._target(*self._args, **self._kwargs)
File "C:\Users\leamy\Desktop\work bot\followup.py", line 314, in initialize
row_number.number = workbot_main.widget.followup_starting_number()
AttributeError: module 'workbot_main' has no attribute 'widget'
I don't know if that is related.

Ttk style layout not found how to fix?

I am making my own custom Menubar.My work is in process but i recently came across one confusion.
Here is my code:-
from tkinter import *
from tkinter.ttk import Style,Frame as fp
class menu():
def __init__(self,parent,bg="#ffffcc"):
self.parent = parent
self.bg = bg
#this is a image in base 64 encoded format
borderImageData='''
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAIAAAAlC+aJAAAABmJLR0QA/wD/
AP+gvaeTAAACZ0lEQVRoge2aPU/TURSHn/MvpbYYKa9qQQnlTSOJRBzoYBDi
YEwcdPFD+PIFHHRxcCXxO7gxmBgXSTcxMYQEE4spoEWIvBcDBfp2HVqlxRhK
TDwtuc947vJ7cnPvGc6R/v5+KhlHO8C/YgW0sQLaWAFtqg4WxKEjJMGQaQyK
txbHpZGqmGzG7GzKyoyZfcfsOCZbeChFjaz+vAw/oq6V1K75HiERJ5v+33H/
xKnC55czF3CfYD1mxkbY+Pb7sECguUtuPQbMh5d8eksmpZL2r7jccvEGV++B
Ma+fsRzNlwOBAID3lNx+gjHm1VNiEweuqSwwWZajxCak85oEQ3wOk0my/4j7
7uD1m7ERNuY1Ux7KeozwC3x+uXI3V3AAXFXSPcjCFAtTmuFKw8xPsviRrsHc
B+MANHVS7WPuvXK0kjGz43hqaOogL3CyASC+oJrqKMQXAWoayQmI2wuY1J5q
qKOQ2gXE4+MYdGIroI0V0MYKaGMFtLEC2lgBbayANlZAGyugjRXQxgpoYwW0
sQLaWAFtrIA2DmCSCQC3RzlL6VR7AZIJ8jewtQaIv0Uz05GoPQuYrVXyAqsz
JBO0D+imKh0JhtjbYmWGvEAmbabDtPTSelk5Wimc6yNwiekw2Qz7j3hylERc
hh9S36YZ7jCkoU2GHpjtdTM5mqv8mtSnkyxFpHtQeoZIJ1n7UnbDelc1vTfl
+n1EePOcH0u5cvGyR11r/hJSeyxFzPZGmSx7SE09p3twe1j7asZGCifCcnDt
UhzaBwgOSHMnZbNuw86mWY7K3Lg5ZN2mAjkWnbiisQLaWAFtKl7gJzIjtMOb
uqQwAAAAAElFTkSuQmCC
'''
self.borderImage = PhotoImage( data=borderImageData,master=self.parent)
self.TP_style=Style()
self.TP_style.element_create("RoundedFrame",
"image", self.borderImage,
border=14, sticky="nsew")
self.TP_style.layout("RoundedFrame",
[("RoundedFrame", {"sticky": "nsew"})])
self.frame_one = fp(parent, style="RoundedFrame", padding=10,width=100,height=100)
self.frame_one.pack()
l1=Label(parent,image=self.borderImage).pack()
def popup(self,x,y,width=110,height=120):
self.width=width
self.height=height
self.app = Tk()
self.app.config(bg=self.bg)
self.app.geometry(f"{self.width}x{self.height}+{x}+{y}")
self.app.wm_attributes("-topmost",True)
self.app.overrideredirect(True)
self.app.focus_force()
#self.frame_one = fp(self.app, style="RoundedFrame", padding=10,width=100,height=100)
#self.frame_one.pack()
#l1=Label(self.app,image=self.borderImage).pack()
#self.m.pack_propagate(0)
def destroy(event):
self.app.destroy()
self.app.bind("<FocusOut>",destroy)
if __name__ == "__main__":
root = Tk()
menu = menu(root)
def evt(evt):
menu.popup(evt.x_root,evt.y_root,width=200,height=400)
root.bind("<Button-3>",evt)
root.mainloop()
If i write style for frame like
self.frame_one = fp(parent, style="RoundedFrame", padding=10,width=100,height=100)
in the init() method every thing works fine. If same thing i write in popup methon(where i have just commented out),i got the following error.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:\Users\mishra\P_Menu.py", line 64, in evt
menu.popup(evt.x_root,evt.y_root,width=200,height=400)
File "C:\Users\mishra\P_Menu.py", line 51, in popup
self.frame_one = fp(self.app, style="RoundedFrame", padding=10,width=100,height=100)
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\ttk.py", line 740, in __init__
Widget.__init__(self, master, "ttk::frame", kw)
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\ttk.py", line 557, in __init__
tkinter.Widget.__init__(self, master, widgetname, kw=kw)
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 2567, in __init__
self.tk.call(
_tkinter.TclError: Layout RoundedFrame not found
Same thing for Lable
l1=Label(self.app,image=self.borderImage).pack()
In the init() section everything works fine but in popup method I got following error.
Traceback (most recent call last):
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 1883, in __call__
return self.func(*args)
File "C:\Users\mishra\P_Menu.py", line 64, in evt
menu.popup(evt.x_root,evt.y_root,width=200,height=400)
File "C:\Users\mishra\P_Menu.py", line 53, in popup
l1=Label(self.app,image=self.borderImage).pack()
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 3143, in __init__
Widget.__init__(self, master, 'label', cnf, kw)
File "C:\Users\mishra\AppData\Local\Programs\Python\Python38-32\lib\tkinter\__init__.py", line 2567, in __init__
self.tk.call(
_tkinter.TclError: image "pyimage1" doesn't exist
I want to know how to fix it,cause i want to know logic behind it and use in popup() method.
Any help will be appriciated.
Thank You!
Maybe it's because popup creates a new Tk instance as self.app, but the style belongs to the first Tk instance created by root = Tk(). So a child of the second Tk instance cannot recognize it. Maybe you can try changing self.app = Tk() to self.app = Toplevel() to see if it works?

kivy mapview on screenmanager

I have tried first my mapview function with only the mapview in the build which worked, but I had to return in the build mapview. Then I tried having the mapview on my first screen, and I face problems with it:
import kivy
from kivy.app import App
from kivy.uix.label import Label as label
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.button import Button as button
from kivy.uix.gridlayout import GridLayout as gl
from kivy.uix.textinput import TextInput as ti
from kivy.garden.mapview import MapView
from kivy.garden.mapview import MapMarkerPopup
import os
kivy.require("1.11.1")
#first screen page
class Mapspage(Screen,MapView,gl):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols=1
marker=MapMarkerPopup(lat=55.6928595,lon=12.5992828)
self.abouting=button(text="lil'mermaid")
self.abouting.bind(on_press=self.pressbutton())
marker.add_widget(self.abouting)
mapview=MapView(zoom=12, lat=55.6712674, lon=12.5938239)
mapview.add_marker(marker)
def pressbutton(self):
chatapp.screenmanager.current="About"
#button leads to about page
class Aboutpage(Screen,gl):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.cols=1
self.message=label(text="yup dissapointingly small",halign="center",valign="middle",fontsize=30)
self.message.bind(width=self.utw())
self.add_widget(self.message)
def utw(self, *_):
self.message.text_size=(self.message.width*0.9,None)
#updatetextwidth
class Epicapp(App):
def build(self):
self.screenmanager=ScreenManager()
self.mapspage=Mapspage()
screen=Screen(name="places")
screen.add_widget(self.mapspage)
self.screenmanager.add_widget(screen)
self.aboutpage=Aboutpage()
screen=Screen(name="About")
screen.add_widget(self.aboutpage)
self.screenmanager.add_widget(screen)
return self.screenmanager
if __name__=="__main__":
chatapp=Epicapp()
chatapp.run()
I get as an error message this:
[INFO ] [Window ] virtual keyboard not allowed, single mode, not docked
Traceback (most recent call last):
File "<ipython-input-1-4a0782fed14b>", line 1, in <module>
runfile('/home/pi/Documents/learningkivy.py', wdir='/home/pi/Documents')
File "/usr/lib/python3/dist-packages/spyder_kernels/customize/spydercustomize.py", line 678, in runfile
execfile(filename, namespace)
File "/usr/lib/python3/dist-packages/spyder_kernels/customize/spydercustomize.py", line 106, in execfile
exec(compile(f.read(), filename, 'exec'), namespace)
File "/home/pi/Documents/learningkivy.py", line 70, in <module>
chatapp.run()
File "/usr/local/lib/python3.7/dist-packages/kivy/app.py", line 829, in run
root = self.build()
File "/home/pi/Documents/learningkivy.py", line 54, in build
self.mapspage=Mapspage()
File "/home/pi/Documents/learningkivy.py", line 28, in __init__
super().__init__(**kwargs)
File "/usr/local/lib/python3.7/dist-packages/kivy/uix/relativelayout.py", line 265, in __init__
super(RelativeLayout, self).__init__(**kw)
File "/usr/local/lib/python3.7/dist-packages/kivy/uix/floatlayout.py", line 65, in __init__
super(FloatLayout, self).__init__(**kwargs)
File "/home/pi/.kivy/garden/garden.mapview/mapview/view.py", line 526, in __init__
self.add_widget(self._scatter)
File "/usr/local/lib/python3.7/dist-packages/kivy/uix/floatlayout.py", line 139, in add_widget
pos_hint=self._trigger_layout)
File "kivy/_event.pyx", line 419, in kivy._event.EventDispatcher.bind
AssertionError: None is not callable
Not really helpfull error message, but I am guessing it is not happy with the
super.__init__
function, yet without it, it will not know about the about page.
Here is a version of your code that mostly works:
import kivy
from kivy.app import App
from kivy.uix.label import Label as label
from kivy.uix.screenmanager import Screen, ScreenManager
from kivy.uix.button import Button as button
from kivy.uix.gridlayout import GridLayout
from kivy.garden.mapview import MapView
from kivy.garden.mapview import MapMarkerPopup
kivy.require("1.11.1")
# first screen page
class Mapspage(Screen):
def __init__(self, **kwargs):
super(Mapspage, self).__init__(**kwargs)
gl = GridLayout(cols=1)
marker = MapMarkerPopup(lat=55.6928595, lon=12.5992828)
self.abouting = button(text="lil'mermaid")
self.abouting.bind(on_press=self.pressbutton)
mapview = MapView(zoom=12, lat=55.6712674, lon=12.5938239)
mapview.add_marker(marker)
gl.add_widget(mapview)
gl.add_widget(self.abouting)
self.add_widget(gl)
def pressbutton(self, *args):
chatapp.screenmanager.current = "About"
# button leads to about page
class Aboutpage(Screen):
def __init__(self, **kwargs):
super(Aboutpage, self).__init__(**kwargs)
gl = GridLayout(cols=1)
self.message = label(text="yup dissapointingly small", halign="center", valign="middle", font_size=30)
self.message.bind(width=self.utw)
gl.add_widget(self.message)
self.add_widget(gl)
def utw(self, *_):
self.message.text_size = (self.message.width * 0.9, None)
# updatetextwidth
class Epicapp(App):
def build(self):
self.screenmanager = ScreenManager()
self.mapspage = Mapspage(name="places")
self.screenmanager.add_widget(self.mapspage)
self.aboutpage = Aboutpage(name="About")
self.screenmanager.add_widget(self.aboutpage)
return self.screenmanager
if __name__ == "__main__":
chatapp = Epicapp()
chatapp.run()
A couple notes about errors encountered in your original code:
When you use bind or on_press (or any event binding) you should bind to a method. If you bind to something like self.utw(), you are executing the self.utw() method and trying to bind to whatever that method returns. You should bind to the method, not its return, like this: self.message.bind(width=self.utw).
In a Label, the font size is set using font_size not fontsize.
In the above code, MapsPage is a Screen that contains a GridLayout. That GridLayout contains a MapView and a Button.
The AboutPage is also a Screen, and it contains a GridLayout that contains a Label.
The build() method is simplified, since both MapsPage and AboutPage are Screens, there is no need to create additional Screens just to contain them.
The error message in your post is caused by the self.pressbutton() call in the __init__() method of MapsPage.

Passing a python function as an arg to a function in PyQt5

Sorry for the long post but wished to give as much as poss
There is a lot of code not shown here but I'm trying to clean up a huge function of buttons in a PyQt5 Gui
I have a GUI output and all is working well and I'm now making an attempt to remove the repeated code and so creating a function to create the buttons.
In a functioned name initUI I have around 20 buttons. As can be seen from the code, the old way was creating each one separately.
What I have done is to create a function that the parameters are sent to and this then creates them.
This does work apart from defRun arg sent to button.
This is passing a call to another function I've highlighted with >>>>arg<<<< this isn't really in the code
class iac2tf(QMainWindow):
def __init__(self):
super(iac2tf, self).__init__()
self.initUI()
self.setGeometry(0, 0, 1700, 1000)........
def button (self, buttonName, buttonText, >>>>defRun<<<<, buttonWidth, buttonHeight, buttonx, buttony):
self.buttonName = QtWidgets.QPushButton(buttonText,self)
>>>>self.buttonName.clicked.connect(lambda:self.defRun)<<<<
self.buttonName.resize(buttonWidth,buttonHeight)
self.buttonName.move(buttonx,buttony)
self.buttonName.show()
def initUI(self):
#passed style
self.openFilebutton = self.button('openFile', 'Open File', >>>'open()'<<<< ,110,30,5,50)
#Old style
self.ProcessFile = QtWidgets.QPushButton('Process File',self)
self.ProcessFile.clicked.connect(self.processFile)
self.ProcessFile.resize(110,30)
self.ProcessFile.move(5, 80)
/......
....../
def open(self):
options = QFileDialog.Options()
options |= QFileDialog.DontUseNativeDialog
file, _ = QFileDialog.getOpenFileNames(self, 'Ope.......
app = QApplication(sys.argv)
win = iac2tf()
win.show()
I've tried passing Knowing some would fail but wanted to cover all bases and was exasperated
str(open)
GUI opens with
<built-in function open>
On clicking button
File "/home/bob/present/proj/WorksArea/gui.py", line 38, in <lambda>
self.buttonName.clicked.connect(lambda:self.defRun)
AttributeError: 'iac2tf' object has no attribute 'defRun'
str(open())
self.openFilebutton = self.button('openFile', 'Open File', str(open()) ,110,30,5,50)
TypeError: Required argument 'file' (pos 1) not found
str(self.open)
GUI opens with
<bound method iac2tf.open of <__main__.iac2tf object at 0x7f87e73da948>>
On clicking button
Traceback (most recent call last):
File "/home/bob/present/proj/WorksArea/gui.py", line 38, in <lambda>
self.buttonName.clicked.connect(lambda:self.defRun)
AttributeError: 'iac2tf' object has no attribute 'defRun'
str(self.open())
Open file selection menu ie starts open func
self.open
GUI starts
<bound method iac2tf.open of <__main__.iac2tf object at 0x7fdcb2dee948>>
On clicking button
Traceback (most recent call last):
File "/home/bob/present/proj/WorksArea/gui.py", line 38, in <lambda>
self.buttonName.clicked.connect(lambda:self.defRun)
AttributeError: 'iac2tf' object has no attribute 'defRun'
'self.open'
'self.open()'
'open()'
'open'
opens GUI without error
on clicking button
Traceback (most recent call last):
File "/home/bob/present/proj/WorksArea/gui.py", line 38, in <lambda>
self.buttonName.clicked.connect(lambda:self.defRun)
AttributeError: 'iac2tf' object has no attribute 'defRun'
open
opens GUI with
<built-in function open>
on clicking button
Traceback (most recent call last):
File "/home/bob/present/proj/WorksArea/gui.py", line 38, in <lambda>
self.buttonName.clicked.connect(lambda:self.defRun)
AttributeError: 'iac2tf' object has no attribute 'defRun'
open()
self.openFilebutton = self.button('openFile', 'Open File', open() ,110,30,5,50)
TypeError: Required argument 'file' (pos 1) not found
passing to a local to func var all of above but is as is :(
Here is an example of passing functions as arguments.
class Template(QWidget):
def __init__(self):
super().__init__()
self.vbox = QVBoxLayout(self)
self.create_button('Open', self.open)
self.create_button('Close', self.close)
def create_button(self, text, slot):
btn = QPushButton(text)
btn.clicked.connect(slot)
self.vbox.addWidget(btn)
def open(self):
QFileDialog.getOpenFileName(self)
Also worth noting that the arg buttonName is never actually used in this function:
def button (self, buttonName, buttonText, >>>>defRun<<<<, buttonWidth, buttonHeight, buttonx, buttony):
self.buttonName = QtWidgets.QPushButton(buttonText,self)
. . .
That variable only exists in the local scope of the function, and self.buttonName refers to another object entirely. That is to say, if you wanted to refer to a button you created where you passed 'openFile' for the buttonName arg, it would not be called self.openFile, it would be called literally self.buttonName. You could however, use exec() to achieve this, although it is generally discouraged.

GUI under embedded Linux / python 3.3.2

I'm writing a GTK+ app using embedded/extended Python3 as a scripting language. What I'd like do is make it possible for those scripts to include menus, but, so far, things aren't cooperating.
I do the usual python initialisation with:
PyImport_AppendInittab("gfig", &PyInit_gfig);
Py_SetProgramName (L"gfig");
Py_Initialize();
and then some setup with:
PyRun_SimpleString (
"import gfig\n"
"import sys\n" ........ )
(gfig is the app I'm writing, as well as the name of extension module.)
Then I run the app using
PyRun_File (fp, pyfile, Py_file_input, global_dict, local_dict);
to run the script:
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
def on_button_clicked(self, widget):
print("Hello World")
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
This results in:
[0] /mnt/disk5/personal/tinkering/gf3/src >./gf py4
Traceback (most recent call last): File "py4", line 3, in
from gi.repository import Gtk File "",
line 1567, in _find_and_load File "",
line 1534, in _find_and_load_unlocked File "/usr/lib64/python3.3/site-packages/gi/importer.py",
line 68, inload_module dynamic_module._load() File "/usr/lib64/python3.3/site-packages/gi/module.py",
line 289, in _load self._overrides_module = importlib.import_module('gi.overrides.' +
self._namespace) File "/usr/lib64/python3.3/importlib/init.py",
line 90, in import_module return _bootstrap._gcd_import(name[level:], package, level) File "/usr/lib64/python3.3/site-packages/gi/overrides/Gtk.py",
line 1523,in initialized, argv = Gtk.init_check(sys.argv)
AttributeError 'module' object has no attribute 'argv'
Here's the script:
from gi.repository import Gtk
class MyWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self, title="Hello World")
self.button = Gtk.Button(label="Click Here")
self.button.connect("clicked", self.on_button_clicked)
self.add(self.button)
def on_button_clicked(self, widget):
print("Hello World")
win = MyWindow()
win.connect("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()
which works fine when from the command line:
[0] /mnt/disk5/personal/tinkering/gf3/src >python3 py4
I see that the script ends with "Gtk.main()" which, since I'm running python embedded under GTK+, looks like it may give me trouble in the future.
(I've tried Tk, wx, and, I think, Qt. None of them worked, but I didn't explore why not in any detail. I'd like to use Gtk.)
Any help greatly appreciated.

Resources