What's the proper way to disable widgets in python / Tkinter? [duplicate] - python-2.7

I've created this simple GUI:
from tkinter import *
root = Tk()
def grabText(event):
print(entryBox.get())
entryBox = Entry(root, width=60).grid(row=2, column=1, sticky=W)
grabBtn = Button(root, text="Grab")
grabBtn.grid(row=8, column=1)
grabBtn.bind('<Button-1>', grabText)
root.mainloop()
I get the UI up and running. When I click on the Grab button, I get the following error on the console:
C:\Python> python.exe myFiles\testBed.py
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python\lib\lib-tk\Tkinter.py", line 1403, in __call__
return self.func(*args)
File "myFiles\testBed.py", line 10, in grabText
if entryBox.get().strip()=="":
AttributeError: 'NoneType' object has no attribute 'get'
Why is entryBox set to None?

The grid, pack and place functions of the Entry object and of all other widgets returns None. In python when you do a().b(), the result of the expression is whatever b() returns, therefore Entry(...).grid(...) will return None.
You should split that on to two lines like this:
entryBox = Entry(root, width=60)
entryBox.grid(row=2, column=1, sticky=W)
That way you get your Entry reference stored in entryBox and it's laid out like you expect. This has a bonus side effect of making your layout easier to understand and maintain if you collect all of your grid and/or pack statements in blocks.

Change this line:
entryBox=Entry(root,width=60).grid(row=2, column=1,sticky=W)
into these two lines:
entryBox=Entry(root,width=60)
entryBox.grid(row=2, column=1,sticky=W)
Just as you already correctly do for grabBtn!

Alternative solution for Python3.8+ versions that allows to put all of this in one line using the walrus operator:
(entryBox := Entry(root, width=60)).grid(row=2, column=1, sticky=W)
Now entryBox will refer to the Entry widget and also get packed.
For characters per line management I can suggest something like this:
(var := Button(
text='fine', command=some_func, width=20, height=15, activebackground='grey'
)).grid(row=0, column=0, columnspan=0, rowspan=0, sticky='news')
But at that point might as well just do this "normally" (as suggested by other answers)
Sources:
PEP 572 -- Assignment Expressions
IMO great video explanation about walrus operator

For entryBox.get() to access get() method you need Entry object but Entry(root, width=60).grid(row=2, column=1, sticky=W) returns None.
entryBox = Entry(root, width=60) creates a new Entry Object.
Moreover, you won't need
entryBox = entryBox.grid(row=2, column=1, sticky=W) as it will rewrite entryBox with None
Just replace entryBox = entryBox.grid(row=2, column=1, sticky=W)
with
entryBox = Entry(root, width=60)
entryBox.grid(row=2, column=1, sticky=W)

Related

Trying to create an animated graph, am getting AttributeError: 'list' object has no attribute 'set_animated' error

I'm trying to plot the voltage/current coming out of a device, with these being written to a file and then displayed on the same plot, which updates in real time. Currently the code does this, but it pops up with an error message each time the graph updates which seems to be slowing the pace at which the program takes measurements.
The error seems to be occurring each time the graph updates i.e. when plt.draw() is executed within the While loop, making me think that it occurs in def animate_readings(i), though I've included all pertinent pieces of code just in case.
plt.ion()
...
fig = plt.figure()
ax1 = fig.add_subplot(1,1,1)
ax1.clear()
ax2 = ax1.twinx()
ax2.clear()
plt.xlim(-7,3)
ax1.set_ylabel('Voltage V')
ax2.set_ylabel('Current mA')
ax1.set_ylim(-0.5,27)
ax2.set_ylim(-5, 400, 10)
Vpatch = mpatches.Patch(color='blue', label='Voltage')
Cpatch = mpatches.Patch(color='red', label='Current')
plt.legend(handles=[Vpatch, Cpatch])
plt.draw()
plt.pause(0.1)
"Is used to assign properties to the graph used in FuncAnimation"
def animate_readings(i):
plt.xlim(c-8,c+2)
ax1.plot(AVdata, color='b')
ax2.plot(ACdata, color='r')
Artists = namedtuple ('Artists', ('AVdata', 'ACdata'))
returnable = Artists(
ax1.plot(AVdata, color='b'),
ax2.plot(ACdata, color='r')
)
return returnable
...
while 1:
print 1
"Below if statement names and creates file at beginning of operation"
ani = animation.FuncAnimation(fig, animate_readings, interval=200, blit=True)
...
if c % 1 == 0:
print "2b"
try:
plt.draw()
plt.pause(0.1)
print "2c"
except :
pass
print 2
c = c + 1
The error which pops up after print "2b" executes is as follows. Nominally the loop should be running ~3x a second but, due to the error it only runs every 3 seconds and, in a recent extended test, only recorded readings every 30 seconds.
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/matplotlib/cbook/__init__.py", line 388, in process
proxy(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/cbook/__init__.py", line 228, in __call__
return mtd(*args, **kwargs)
File "/usr/local/lib/python2.7/dist-packages/matplotlib/animation.py", line 1026, in _start
self._init_draw()
File "/usr/local/lib/python2.7/dist-packages/matplotlib/animation.py", line 1750, in _init_draw
self._draw_frame(next(self.new_frame_seq()))
File "/usr/local/lib/python2.7/dist-packages/matplotlib/animation.py", line 1778, in _draw_frame
a.set_animated(self._blit)
AttributeError: 'list' object has no attribute 'set_animated'

tkSimpleDialog pycharm

I am coding for a school project and was trying to use tkinter in my code, but it kept coming up with an error. I am using a mac laptop and the pycharm interface
Traceback (most recent call last):
File "/Users/-----/Desktop/python/Tkinter turtle obstacle.py", line 20, in <module>
color1()#does it automatically
File "/Users/-----/Desktop/python/Tkinter turtle obstacle.py", line 8, in color1
ac1 = Sd("Color Selector", 'Enter the color of the turtle')
TypeError: 'module' object is not callable
Here is my code, its just a simple project to test it before i delve into the final one but I cannot get it to work, can someone please tell me what is wrong with it:
import turtle # 1. import the modules
import random
import Tkinter as tk
import tkSimpleDialog as Sd
def color1():
ac1 = Sd("Color Selector", 'Enter the color of the turtle')
steve.color(ac1)
print(5)
def color2():
ac2 = Sd("Color Selector", 'Enter the color of the obstacle')
sam.color(ac2)
root = tk.Tk()
wn = turtle.Screen() # 2. Create a screen
wn.bgcolor('white')
steve = turtle.Turtle() # 3. Create two turtles
sam = turtle.Turtle()
color1()#does it automatically
color2()
red = tk.Button(root, text = "Enter String", command = color1)#this puts it on a button click
blue = tk.Button(root, text = "Enter String", command = color2)
red.grid(row=0,column=0)
blue.grid(row=1,column=0)
steve.shape('turtle')
sam.shape('circle')
steve.speed(1)
sam.speed(1)
steve.pensize(5)
sam.pensize(25)
sam.penup()
sam.pendown()
steve.penup()
steve.goto(-300,0)
sam.goto(0,0)
b = True
while b is True:
steve.pendown()
steve.forward(20)
if steve.xcor() == sam.xcor() -40:
steve.left(90)
steve.forward(30)
steve.right(90)
if steve.xcor() == sam.xcor() +40:
steve.right(90)
steve.forward(30)
steve.left(90)
if steve.xcor() == 200:
steve.write('Obstacle Avoided', font=('Arial', 20, "bold"))
break
wn.exitonclick()
tkSimpleDialog is a module, not a Class.
You probably want to create an instance of a Class in this module.
Look for the Classes in the module and use the correct Class to create the instance.

Placing an image using ttk on a grid, with Python 2.7.11

I am stuck when I try to place an image on my GUI. Based on the program I am working on, I am restricted to working with Python v2.7.11. I have a basic GUI that I pulled from elsewhere (shown below, top code). However, when I try to place an image using a similar process, my GUI goes away altogether (no other features show). Edit: The error I am receiving is "image "pyimage28" doesn't exist, even though I'm defining my image as 'bug.gif'. The full error message is shown in the second code snippet; both the code and the image are located in on the Desktop.
Based on another question on this site, my attempt is shown below, starting with the variable "label".
Ultimately, I would like to do two things.
Place an image in the upper left corner of the GUI in place of where the frame item was
Give that image properties, such that I can store x,y coordinates when I click somewhere on the image, or the coordinates show in real time outside of the image.
.
from Tkinter import *
import ttk
root = Tk()
content = ttk.Frame(root)
#frame = ttk.Frame(content, borderwidth=5, relief="sunken", width=200, height=100)
label = ttk.Label(root)
image1 = PhotoImage(file='bug.gif')
label['image'] = image1
latlbl = ttk.Label(content, text="Latitude")
latval = ttk.Entry(content)
lonlbl = ttk.Label(content, text="Longitude")
lonval = ttk.Entry(content)
onevar = BooleanVar()
twovar = BooleanVar()
threevar = BooleanVar()
onevar.set(True)
twovar.set(False)
threevar.set(True)
one = ttk.Checkbutton(content, text="One", variable=onevar, onvalue=True)
two = ttk.Checkbutton(content, text="Two", variable=twovar, onvalue=True)
three = ttk.Checkbutton(content, text="Three", variable=threevar, onvalue=True)
ok = ttk.Button(content, text="Okay")
cancel = ttk.Button(content, text="Cancel")
content.grid(column=0, row=0)
#frame.grid(column=0, row=0, columnspan=3, rowspan=2)
label.grid(column=0, row=0, columnspan=3, rowspan=2)
latlbl.grid(column=3, row=0, columnspan=1)
latval.grid(column=4, row=0, columnspan=2)
lonlbl.grid(column=3, row=1, columnspan=1)
lonval.grid(column=4, row=1, columnspan=2)
one.grid(column=0, row=3)
two.grid(column=1, row=3)
three.grid(column=2, row=3)
ok.grid(column=3, row=3)
cancel.grid(column=4, row=3)
label.pack()
root.mainloop()
The full code error is:
runfile('C:/Users/ajpung/Desktop/untitled9.py', wdir='C:/Users/ajpung/Desktop')
Traceback (most recent call last):
File "<ipython-input-1-1596c9c787bc>", line 1, in <module>
runfile('C:/Users/ajpung/Desktop/untitled9.py', wdir='C:/Users/ajpung/Desktop')
File "C:\Users\ajpung\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 699, in runfile
execfile(filename, namespace)
File "C:\Users\ajpung\AppData\Local\Continuum\Anaconda2\lib\site-packages\spyderlib\widgets\externalshell\sitecustomize.py", line 74, in execfile
exec(compile(scripttext, filename, 'exec'), glob, loc)
File "C:/Users/ajpung/Desktop/untitled9.py", line 25, in <module>
label['image'] = image1
File "C:\Users\ajpung\AppData\Local\Continuum\Anaconda2\lib\lib-tk\Tkinter.py", line 1333, in __setitem__
self.configure({key: value})
File "C:\Users\ajpung\AppData\Local\Continuum\Anaconda2\lib\lib-tk\Tkinter.py", line 1326, in configure
return self._configure('configure', cnf, kw)
File "C:\Users\ajpung\AppData\Local\Continuum\Anaconda2\lib\lib-tk\Tkinter.py", line 1317, in _configure
self.tk.call(_flatten((self._w, cmd)) + self._options(cnf))
TclError: image "pyimage1" doesn't exist
The code you posted does not give the error you say it does when running in a standard python interpreter.
That being said, there is one critical bug in your code that will prevent it from working. You are using both grid and pack in the root window. You need to remove this line:
label.pack()
I thought I'd tried this before, but the problem isn't with Spyder. Switching root = Tk() to root = Toplevel() fixed the original issue.

In Python 2.7. I am getting an error that I cannot resolve: TypeError: __init__() takes exactly 3 arguments (1 given)"

Trying to create a GUI which will move files from one directory to another. If the files have been created/modified over 24 hours from the time it will list in a text box when the files were created/modified.
import os
import wx, DB_FILE
import shutil
import time
wildcard = "All files (*.txt)|*.*"
class File_Transfer(wx.Frame):
def __init__(self, parent, id):
wx.Frame.__init__(self, parent, id, 'File Transfer', size=(420, 200))
#Add dta to the list control
self.fillListCtrl()
panel = wx.Panel(self,-1)
self.Directory = os.getcwd()
panel.SetBackgroundColour("White")
openButton = wx.Button(panel, -1, "Pull Files From:", pos=(10,0))
self.Bind(wx.EVT_BUTTON, self.onOpenFile, openButton)
placeButton = wx.Button(panel, -1, "New File Transfer to:", pos=(127,0))
self.Bind(wx.EVT_BUTTON, self.placeFile, placeButton)
trsnfrButton = wx.Button(panel, -1, "Transfer File(s)", pos=(280,0))
self.Bind(wx.EVT_BUTTON, self.trnsfrFile, trsnfrButton)
#SETUP THE TABLE UI
#SETUP TABLE AS listCtrl
self.listCtrl = wx.ListCtrl(panel, size = (100, 100), pos=(100, 40), style=wx.LC.REPORT |wx.BORDER_SUNKEN)
#Add columns to listCtrl
self.listCtrl.InsertColumn(0, "ID")
self.listCtrl.InsertColumn(1, "File_DESCRIPTION")
self.listCtrl.InsertColumn(1, "Age")
#Get dta from the database
def fillListCtrl(self):
self.allData = DB_FILE.viewAll()
#Delete old data before adding new data
self.listCtrl.DeleteAllItems()
for row in AllData:
#Loop through and append data
self.listCtrl.Append(row)
def addAge(self, event):
name = dst
age = mtime
#Adding character to database
DB_FILE.newfILE(name)
DB_FILE.newfILE(age)
print DB_FILE.viewAll()
#Update list control
self.fillListCtrl()
def onOpenFile(self,event):
dlg = wx.FileDialog(
self, message="Select FILE",
defaultDir=self.Directory,
defaultFile="",
wildcard=wildcard,
style=wx.OPEN | wx.MULTIPLE | wx.CHANGE_DIR
)
if dlg.ShowModal() == wx.ID_OK:
paths=dlg.GetPaths()
print "You chose the following file(s):"
for path in paths:
print path
global filePath
filePath=path
dlg.Destroy()
def placeFile(self, event):
#Get directory where the files will go.
dlg = wx.DirDialog(self, "Choose a directory:")
if dlg.ShowModal() == wx.ID_OK:
paths = dlg.GetPath()
print "You chose %s" % dlg.GetPath()
for path in paths:
global savePath
savePath=dlg.GetPath()
fileage_program.deleteCharacter(self.selectedId)
#Refresh the table
self.fillListCtrl()
dlg.Destroy()
#Transfer files from initial location to final location then states time
def trnsfrFile(src,dst):
src = filePath #Original File address
dst = savePath #Move to directory
#print file # testing
st=os.stat(src)
ctime=st.st_ctime #Current time
global mtime
mtime=(time.time() - ctime)/3600 #Subtract current time from last time file was touched and convert it to hours
if mtime<24: #If time from creation is less than 24 hours then move files.
shutil.move(src, dst)
newFile()
print dst
else:
print "file are: '%d' hours, since creation/modification" %mtime
#Run the program
if __name__ == "__main__":
app = wx.App()
frame = File_Transfer()
frame.Show()
app.MainLoop()
Here is my database I am connected to:
import sqlite3
# Connect to simpsons database
conn = sqlite3.connect('FILE_INFO.db')
def createTable():
conn.execute("CREATE TABLE if not exists \
FILE_INFO( \
ID INTEGER PRIMARY KEY AUTOINCREMENT, \
FILE_DESCRIPTION TEXT, \
TIME INT);")
def newfILE(name,age):
# Create values part of sql command
val_str = "'{}', {}".format(\
name, age)
sql_str = "INSERT INTO FILE_INFO \
(FILE_DESCRIPTION, TIME) \
VALUES ('{}',{});".format(val_str)
print sql_str
conn.execute(sql_str)
conn.commit()
return conn.total_changes
def viewAll():
# Create sql string
sql_str = "SELECT * from FILE_INFO"
cursor = conn.execute(sql_str)
# Get data from cursor in array
rows = cursor.fetchall()
return rows
createTable()
1-You don't really need to import rows as rows (if you import rows you will automatically be able to call the module as rows).
2-where is this .py file (rows.py) saved? Can you access the directory where it is from the directory where you are?
Just posting this answer to summarize the comments.
##############################################################################################revising my answer today, decided to edit
#
3-This error TypeError:__init__() takes exactly 3 arguments (1 given) usually happens when you miss in the argumentation. An argument, just to remember, is the word you put between () when you're making or calling a funtion. For example: __init__(self): in this case self is an argument for the __init__() function. On your case, you're calling 3 of those self, parent, id. When you call this function you will need to use this three arguments, and it could be variables determined in another function or class, that you would need to determine as global for the program identifi it as the same variable usd above, or you can just substitute it for values of data (exp.: int, float, str), like: __init__(self, 1, 42). The important thing is: you need to use the complete argumentation if it is the same function: if it has three args on it's definition, you need to call it with three args.

PyQt - Getting an error when trying to use emit

I am trying to use emit for the first time in PyQt. I have done a lot of reading and googling and I was sure I had this correct but I keep getting the errors shown below. Can anyone shed some light on what I am doing wrong.
def checkRiskDescription(obj,form):
complete = True
if str(form.txtTitle.text()) == "":
complete = False
if len(str(form.txtOverview.toPlainText())) < 50:
complete = False
bar = form.tabRiskMain.tabBar()
if complete:
#Change Risk Description tab to Green
bar.setTabTextColor(0,QtGui.QColor(38, 169, 11, 255))
form.btnSave.enabeld = True
else:
#Change risk Description tab to Red
bar.setTabTextColor(0,QtGui.QColor(255, 0, 0, 255))
form.btnSave.enabled = False
QtGui.QWidget.emit(QtCore.SIGNAL("tabsUpdated"))
Here is the error
File "D:\Development\python\PIF2\PIF\risk\risk.py", line 360, in checkRiskDescription
QtGui.QWidget.emit(QtCore.SIGNAL("tabsUpdated"))
TypeError: QObject.emit(SIGNAL(), ...): first argument of unbound method must have type 'QObject'
I normally just define the signal like this
tabsUpdated = Qt.pyqtSignal()
then fire it via
self.tabsUpdated.emit()
E.g
from PyQt4 import Qt
class SomeClass(Qt.QObject):
tabsUpdated = Qt.pyqtSignal()
def __init__(self):
Qt.QObject.__init__(self)
def something(self):
# bla bla loads of nice magic code bla bla
self.tabsUpdated.emit()
of course the signal could be defined globally in your python file.