Why use different approaches rather than direct, when connecting signals? - python

I am working with Python 3.3 and PyQt 4.10.1. Below figure is from PyQt book.
Assume that there are 5 buttons as shown below. When clicked on each, they will change label's text a context that includes their button number. For example, when user clicks on the button with caption "Four" on it, it will change the label to You clicked button 'Four'
Instead of creating a signal slot for each of the buttons, a generalised method is created which accepts a paramater and partial() method is used:
...
self.label = QLabel("Click on a button.")
self.button1 = QPushButton("One")
...
self.button5 = QPushButton("Five")
self.connect(self.button1, SIGNAL("clicked()")
, partial(self.anyButton, "One"))
...
self.connect(self.button5, SIGNAL("clicked()")
, partial(self.anyButton, "Five"))
...
def anyButton(self, buttonNumber):
self.label.setText("You clicked button '%s'" % buttonNumber)
Whenever I want to change partial(self.anyButton, "One") to self.anyButton("One"), I get an error like below.
Traceback (most recent call last):
File "C:\Users\abdullah\Desktop\test.py", line 47, in <module>
form = Form()
File "C:\Users\abdullah\Desktop\test.py", line 20, in __init__
, self.anyButton("One"))
TypeError: arguments did not match any overloaded call:
QObject.connect(QObject, SIGNAL(), QObject, SLOT(), Qt.ConnectionType=Qt.AutoC
onnection): argument 3 has unexpected type 'NoneType'
QObject.connect(QObject, SIGNAL(), callable, Qt.ConnectionType=Qt.AutoConnecti
on): argument 3 has unexpected type 'NoneType'
QObject.connect(QObject, SIGNAL(), SLOT(), Qt.ConnectionType=Qt.AutoConnection
): argument 3 has unexpected type 'NoneType'
What is the reason for this? Why I cannot directly call the function? Also, why partial() method works?

partial returns you the function anyButton where the argument is substituted.
self.anyButton("One") gives you the value returned by the function.

Related

Getting "TypeError: insertstop() takes 0 positional arguments but 1 was given" when there are no arguments in my function calls

I'm very new to Python and I'm trying to put my first application together that takes in trip information and inserts it into a text box for export out to a document. It's gone pretty good until today when I tried to implement multiple ways of inserting text from an entrybox into a text block with tkinter.
I have an entry widget that inserts text into a text widget when a button is pressed. That's simple enough but I wanted to make it to where you could simply hit the enter key to do the same thing.
When I implement this function I get the error:
"Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\Spyder\pkgs\tkinter_init_.py", line 1892, in __ call __
return self.func(*args)
TypeError: insertstop() takes 0 positional arguments but 1 was given"
I've looked the error up and it seems like it would pop up if I put in arguments in my function call but I don't have any arguments in any of my function calls. Also it seems like maybe this error is related to a class or something? I haven't learned about classes yet and only have a basic idea of what they are. Do I need a class to do this?
Coincidentally I also added the argument(self) in my function and that made pressing enter work but it made my insert stop button quit working.
I'm sure I've missed something very basic but I just can't figure out what.
Thanks for any help!
import time
import os
import sys
from tkinter import *
# Creates the Tkinter form named "screen"
screen = Tk()
screen.geometry("550x645")
screen.title("Test")
# Initialize frames
menuframe = Frame(screen,
height=60,width=600,bg="gray",pady=5)
inputframe = Frame(screen,
height=300,width=600,pady=5)
outputframe = Frame(screen,
height=290,width=600,pady=5)
# Packs the frames so they will display
menuframe.pack()
inputframe.pack()
outputframe.pack()
#==STOPBOX==#
stopbox=Text(inputframe,yscrollcommand=1,height= 10,width=20,
padx=3,pady=3,relief=GROOVE,bg="gray79")
stopbox.place(x=345, y=90)
def insertstop():
global stop_vanconv
stop_vanconv=(stop_entry.get())
stopbox.insert(END, stop_vanconv + "\n")
stop_entry.delete("0","end")
stoplist_label = Label(inputframe,
text="Type stop locations and press" + '\n' +
"the Add Stop button to insert a new stop.")
stoplist_label.place(x=100, y=150)
stop_entry = Entry(inputframe,
textvariable = " ")
stop_entry.place(x=150, y=190)
addstopbutton = Button(inputframe,text="Add Stop",padx=20,pady=0,
activebackground="darkslategray4",command=insertstop)
addstopbutton.place(x=160, y=220)
stop_entry.bind('<Return>',insertstop)
screen.mainloop()

binding two buttons to the same widget tkinter [duplicate]

This question already has answers here:
Binding Tkinter button: function takes exactly 1 positional argument (0 given)
(2 answers)
Closed 2 years ago.
Is it possible to bind two diff keys to the same widget and call a different function. I am getting error that dbase() missing positional argument event even though i have passed in event as an argument
UPDATE: So the actual error is when i bind 'Return' to an entry widget and then i try clicking the button, then i get the error:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Users\nihaa\AppData\Local\Programs\Python\Python37-32\lib\tkinter\__init__.py", line 1705, in __call__
return self.func(*args)
TypeError: dbase() missing 1 required positional argument: 'event'
Code:
def search():
log = Toplevel(root)
log.title('Search Book')
def dbase(event):
.....
def clicker(event):
....
def key_pressed(event):
....
entry1.bind_all('<Key>',key_pressed)
button1.bind('<Button-1>',clicker)
entry1.bind('<Return>',dbase)
When you press the button, it will call the function dbase.
But your function dbase need to pass an argument event, but at this time, it won't pass any arguments.That's why it will raise Exception(If you call the dbase by the .bind, it will pass a argument).To solve this issue, you need to bind a default argument for your event:
import tkinter
def dbase(event=None):
print("you are passing")
r = tkinter.Tk()
b = tkinter.Button(r,command=dbase)
r.bind_all("<Return>", dbase)
b.pack()
r.mainloop()
Or if you don't need the argument,use lambda in the bind:
import tkinter
def dbase():
print("you are passing")
r = tkinter.Tk()
b = tkinter.Button(r,command=dbase)
r.bind_all("<Return>", lambda e: dbase())
b.pack()
r.mainloop()
This could work when you press the button directly or press <Enter>.

Errors when trying to clear Tkinter Entry Widget

I am working on a project that will eventually simulate a filter for Twitter posts. I am trying to make a page in Tkinter that will allow the user to enter a Twitter account, and press a button that will add the string to a list and clear the entry field (have yet to code the append function). Code is as follows:
def Add():
F.title('Twitter Filter: Add to Filter')
def h_delete():
Entry.delete(h,first=0,last=END) # should clear entry, instead returns NoneType error
for widget in F.winfo_children():
widget.destroy() # clears widgets of previous window
global a1
a1=tk.StringVar() # declares a variable that will be used to append a list with the text in the Entry
h=tk.Entry(F,textvariable=a1).grid(row=1,column=1) # creates the entry I want cleared
EntryButton=tk.Button(F,text='Add this account',command=h_delete).grid(row=2,column=1) # initiates the entry clearing function
BackButton=tk.Button(F,text='Back to Home',command=Home).grid(row=3,column=1) # returns to home screen
However, when I run the code, I receive a NoneType error, as follows:
Exception in Tkinter callback
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 1550, in __call__
return self.func(*args)
File "/Users/skor8427/Desktop/Twitter Filter/TwitterFilter.py", line 22, in h_delete
Entry.delete(h,first=0,last=END) # should clear entry, instead returns NoneType error
File "/Library/Frameworks/Python.framework/Versions/3.5/lib/python3.5/tkinter/__init__.py", line 2519, in delete
self.tk.call(self._w, 'delete', first, last)
AttributeError: 'NoneType' object has no attribute 'tk'
I have read various help sections and nothing is working. Anyone have a solution?
h = tk.Entry(F, textvariable=a1)
h.grid(row=1, column=1)
You have to grid h in other line else it will become NoneType
Try this snippet of code instead of
h = tk.Entry(F, textvariable=a1).grid(row=1, column=1)

How can the variable be used by other functions in TkfileDialog?

I intended to write a GUI to import URLs data then process these data,
so I had 2 buttons. Below is my code.
from Tkinter import *
root=Tk()
root.title('Videos Episodes')
root.geometry('500x300')
def OpenFile(): # import URLs data from local machine
paths=tkFileDialog.askopenfilename()
return paths
def read_files(paths): #read data from the directory from OpenFile
with open(paths) as myfile:
return data
Button(root,text='Input',command=OpenFile).pack()
Button(root,text='Process',command=read_files).pack()
root.mainloop()
My problem is that when 'Process' button clicked, error happened:
Exception in Tkinter callback Traceback (most recent call last):
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1532, in __call__
return self.func(*args) TypeError: read_files() takes exactly 1 argument (0 given)
How can I fix the bug?
If you want to pass an argument (you didn't specify what), use a lambda:
Button(root,text='Process',command=lambda: read_files('whatever')).pack()
Perhaps, this is what you wanted to do (?):
Button(root,text='Process',command=lambda: read_files(OpenFile())).pack()
or alternatively, you meant to store the result of OpenFile (from clicking the other button) in a global variable, and pass that as argument of read_files...?

Can I use wxPython wx.ItemContainer in a derived class?

I'm trying to make a new wx.Choice-like control (actually a replacement for wx.Choice) which uses the wx.ItemContainer to manage the list of items. Here is a minimal example showing the error:
import wx
class c(wx.ItemContainer):
def __init__(my): pass
x = c()
x.Clear()
This fails with:
Traceback (most recent call last):
File "", line 1, in
File "c:\python25\lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 1178
7, in Clear
return _core_.ItemContainer_Clear(*args, **kwargs)
TypeError: in method 'ItemContainer_Clear', expected argument 1 of type 'wxItemContainer *'
The other controls using ItemContainer seem to be internal to wxWindows, so it may not be possible for me to use it this way. However, it would certainly be convenient.
Any ideas on what I'm doing wrong?
wx.ItemContainer can't be instantiated directly e.g. try
x = wx.ItemContainer()
it throws error
Traceback (most recent call last):
File "C:\<string>", line 1, in <module>
File "D:\Python25\Lib\site-packages\wx-2.8-msw-unicode\wx\_core.py", line 11812, in __init__
def __init__(self): raise AttributeError, "No constructor defined"
AttributeError: No constructor defined
Reason being it is a type of interface(if we can call that in python) and you can not call __init__ on it, instead use it as second base and override the methods you use e.g.
class C(wx.PyControl, wx.ItemContainer):
def __init__(self, *args, **kwargs):
wx.PyControl.__init__(self, *args, **kwargs)
def Clear(self):
pass
app = wx.PySimpleApp()
frame = wx.Frame(None,title="ItemContainer Test")
x = C(frame)
x.Clear()
frame.Show()
app.SetTopWindow(frame)
app.MainLoop()
Your suspicions are on the right track. You can't subclass any of the wxWidgets types, because they're in the C++ domain and only nominally wrapped in Python. Instead, you need a Py* class, which you can subclass. The explanation is given in this Wiki entry on writing custom controls.
For ItemContainer, there doesn't appear to be such a wrapper - and the fact that ItemContainer is used as a parent in a multiple inheritance pattern may even complicate matters.
I suspect that from within wxPython, it may not be possible to replace ItemContainer--and if you do need it, it will have to be integrated at the C++ level.

Categories

Resources