Passing a python function as an arg to a function in PyQt5 - python-3.x

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.

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?

Resize image in Tkinter

So, I need to resize an image in tkinter. Before you do anything - this is not a duplicate. I have gone through every other question on this site and none have helped me. The thing with me is - I don't wan't to save the image. I need to load the image, resize it, then display it with PhotoImage in a label. I tried to use ImageTk, but for some reason it won't work.
Here's my code with ImageTk:
from tkinter import *
import PIL
from PIL import Image, ImageTk
root = Tk()
left_nose_path_white = Image.open(r'C:\Users\User\Documents\Python stuff\Other apps\Veteris\Dog photos\Advanced\Sides\GIF\Nose\Nose (left) - White.gif')
def resize_image():
global left_nose_path_white
total_screen_width = root.winfo_screenwidth()
total_screen_height = root.winfo_screenheight()
frame_width, frame_height = left_nose_path_white.size
dog_new_width = int(frame_width / 3)
dog_new_height = int(frame_height / 3)
left_nose_path_white = left_nose_path_white.resize((dog_new_width, dog_new_height), Image.LANCZOS)
resize_image()
left_nose_img_white = ImageTk.PhotoImage(file = left_nose_path_white)
label = Label(image = left_nose_img_white)
label.pack()
root.mainloop()
This returns the error:
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\PIL\ImageTk.py", line 124, in __del__
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
My code should find the width and height of the original image, divide it by 3, and then show it. The reason I don't want to have to save the image is because the user will open the application several times.
I'm new to using PILL/Pillow, so the answer may be obvious.
I have Pillow installed using pip.
I only have one version of Python on my computer (Python 3.7)
Full Error:
Traceback (most recent call last):
File "C:\Users\User\Documents\Python stuff\Other apps\Veteris\Scripts\Veteris_program.py", line 230, in <module>
left_nose_img_white = ImageTk.PhotoImage(file = left_nose_path_white)
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\PIL\ImageTk.py", line 95, in __init__
image = _get_image_from_kw(kw)
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\PIL\ImageTk.py", line 64, in _get_image_from_kw
return Image.open(source)
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\PIL\Image.py", line 2779, in open
prefix = fp.read(16)
AttributeError: 'Image' object has no attribute 'read'
Exception ignored in: <function PhotoImage.__del__ at 0x000002B0A8A49950>
Traceback (most recent call last):
File "C:\Users\User\AppData\Local\Programs\Python\Python37\lib\site-packages\PIL\ImageTk.py", line 124, in __del__
name = self.__photo.name
AttributeError: 'PhotoImage' object has no attribute '_PhotoImage__photo'
Thanks for the help!

Python cmd shell: handling undefined commands

I'm writing a shell that must be able to take an unlimited number of commands. I can't figure out from the docs (https://docs.python.org/3.6/library/cmd.html) which say:
Cmd.default(line) Method called on an input line when the command
prefix is not recognized. If this method is not overridden, it prints
an error message and returns.
I must be writing the default() method incorrectly?
I've tried this:
import cmd
class MyShell(cmd.Cmd):
def default():
print('you entered this unknown command: ')
if __name__ == '__main__':
MyShell().cmdloop()
but get this (when I enter 'hi' in the shell):
(Cmd) hi
Traceback (most recent call last):
File "/Users/david/anaconda/lib/python3.6/cmd.py", line 214, in onecmd
func = getattr(self, 'do_' + cmd)
AttributeError: 'MyShell' object has no attribute 'do_hi'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "bitmessage_shell.py", line 9, in <module>
MyShell().cmdloop()
File "/Users/david/anaconda/lib/python3.6/cmd.py", line 138, in cmdloop
stop = self.onecmd(line)
File "/Users/david/anaconda/lib/python3.6/cmd.py", line 216, in onecmd
return self.default(line)
TypeError: default() takes 0 positional arguments but 2 were given
def default():
print('you entered this unknown command: ')
that doesn't work in a class. You need at least the object argument (self), or make the method static/class using #staticmethod or #classmethod decorators (but not very convenient, you may need the object state at some point)
Moreover, the parent class seems to pass the line, so now you need 2 arguments:
def default(self,line):
print('you entered this unknown command: ',line)

something about pygame:'Group' object has no attribute to 'rect'

It's my first time to ask questions.I'm making a game called "Alien Invasion" in python.When I want to click the "Play",it does't work.I keep on getting this error:
Traceback (most recent call last):
File "alien_invasion.py", line 30, in <module>
File "alien_invasion.py", line 24, in run_game
Flie "D:\python_work\alien_invasion\game_function.py", line 38, in check_events
Flie "D:\python_work\alien_invasion\game_function.py", line 41, in check_play_button
AttributeError:'Group' object has no attribute 'rect'
This is my code about game_function:
def check_events(ai_settings,stats,play_button,screen,ship,aliens,bullets):
for event in pygame.event.get():
if event.type==pygame.QUIT:
sys.exit()
elif event.type==pygame.KEYDOWN:
check_keydown_events(event,ai_settings,screen,ship,bullets)
elif event.type==pygame.KEYUP:
check_keyup_events(event,ship)
elif event.type==pygame.MOUSEBUTTONDOWN:
mouse_x,mouse_y=pygame.mouse.get_pos()
check_play_button(ai_settings,screen,ship,aliens,bullets,stats,play_button,mouse_x,mouse_y)
def check_play_button(ai_settings,screen,stats,play_button,ship,aliens,bullets,mouse_x,mouse_y):
button_clicked=play_button.rect.collidepoint(mouse_x,mouse_y)
if button_clicked and not stats.game_active:
pygame.mouse.set_visible(False)
stats.reset_stats()
stats.game_active=True
aliens.empty()
bullets.empty()
create_fleet(ai_settings,screen,ship,aliens)
ship.center_ship()
I want to know why this is happening and how to correct it.Thanks for your help.
You are passing the arguments in the wrong order. They need to be in the same order as in the function definition:
check_play_button(ai_settings,screen,stats,play_button,ship,aliens,bullets,mouse_x,mouse_y)
The error occurs because you pass aliens, which is obviously a sprite group, as the fourth argument. Then in the check_play_button function this aliens group gets assigned to the local variable play_button and since it has no rect attribute, Python raises the AttributeError.

Tkinter error messages - redrawing buttons

I write chess on Python3, use Tkinter. I have a problem with bot-mode. Player correctly play: click on buttons and figures move. After player's turn bot should play.
def main():
start_position()
root.mainloop()
while king_alive:
global bot_turn
if bot_turn:
cells = l.bot_move(log_field)
replace(cells[0], cells[1])
bot_turn = False
this is function replace() which change condition of cells on the field
def replace(first_cell, second_cell):
if second_cell.figure.type != 'nofig':
delete_fig(second_cell.figure)
first_cell.clicked = False
second_cell.clicked = False
second_cell.fig_name = first_cell.fig_name
second_cell.fig_owner = first_cell.fig_owner
second_cell.figure = second_cell.get_figure()
first_cell.figure = l.NoFigure(first_cell.x, first_cell.y, "")
first_cell.fig_name = ""
first_cell.fig_owner = ""
field[second_cell.x][second_cell.y].configure(fg=second_cell.fig_owner, text=second_cell.fig_name)
field[first_cell.x][first_cell.y].configure(text="")
demark_cells()
people can easily play and move figures, but bot can't do it, however he use the same functions of movement - replace() (input for method replace() are correct. I can't understand the traceback
Traceback (most recent call last):
File "C:/Users/Даша/Desktop/python/task chess/graphics.py", line 176, in <module>
main()
File "C:/Users/Даша/Desktop/python/task chess/graphics.py", line 171, in main
replace(cells[0], cells[1])
File "C:/Users/Даша/Desktop/python/task chess/graphics.py", line 138, in replace
field[second_cell.x][second_cell.y]['fg'] = second_cell.fig_owner
File "C:\Python34\lib\tkinter\__init__.py", line 1275, in __setitem__
self.configure({key: value})
File "C:\Python34\lib\tkinter\__init__.py", line 1268, in configure
return self._configure('configure', cnf, kw)
File "C:\Python34\lib\tkinter\__init__.py", line 1259, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
_tkinter.TclError: invalid command name ".36689776"
how to solve the problem?
P.S. log_field is matrix of every cell conditions
field is matrix of tkinter buttons
You have a problem in the line:
field[second_cell.x][second_cell.y]['fg'] = second_cell.fig_owner
Because you have destroyed, or assigned a different variable to a widget that is called in that line. I don't know exactly what your variables are, but it is probably field[second_cell.x][second_cell.y]['fg'] or second_cell.

Resources