I understand concept callback button in function and procedure.How to apply this code in class?I have problem about callback button in Tkinter for get value from class.I can't access callback method.Eror program = callback not define.
from Tkinter import *
class Program:
def __init__(self):
self.root = Tk()
self.root.title("Sample")
self.display = Entry(self.root)
self.display.grid(row=1, column=0, columnspan=5)
Button(self.root, text="Proces", width=5, foreground="blue", command=callback).grid(row=4, column=0)
def callback(self):
print hello
program = Program()
mainloop()
What you need to do is use: command=self.callback instead of command=callback.
Also, it should be print "hello"
Related
So I have some code which uses xlwings for writing data in Excel file, xlsm.
after i've done writing, I press a certain button to calculate.
sometimes, an error/message pops in the Excel, which is fine, but i want to catch this message to python, and write it later to a log/print it.
also, i need to interact with this message, in this case to press "Ok" in the message box
Attached image of the message box
So guys, I've been able to solve this with an external python library.
here is the code:
from pywinauto import application as autoWin
app = autoWin.Application()
con = app.connect(title = 'Configuration Error')
msgText = con.Dialog.Static2.texts()[0]
con.Dialog.Button.click()
con.Dialog.Button.click()
print(msgText)
basically, what it does, is connecting to the app, and searching for the title.
in this case "Configuration Error"
it needs to perform double click in order to press "Ok" to close the message.
Secondly, it gets the text from the message, and can forward it wherever i want.
important part to remember though, because this should be an automated task, it should run concurrently, which means Threading.
so, a simple Thread class below:
class ButtonClicker(Thread):
def __init__(self):
Thread.__init__(self)
self._stop_event = Event()
def stop(self):
self._stop_event.set()
def stopped(self):
return self._stop_event.is_set()
def run(self) -> None:
while True:
time.sleep(3)
try:
app = autoWin.Application()
con = app.connect(title='Configuration Error')
msg_data = con.Dialog.Static2.texts()[0]
while True:
con.Dialog.Button.click()
# con.Dialog.Button.click()
# print(msg_data)
return msg_data
except Exception as e:
print('Excel didnt stuck')
break
and of course to actually use it:
event_handle = ButtonClicker()
event_handle.start()
some manipulation is needed in order to work in different codes/scenarios, but at least I hope i will help others in the future, because this seems to be very common question.
#Danny's solution, i.e. pywinauto and Thread, works perfectly in my local machine, but it seems can't catch the message box when Excel is running in server mode, e.g. in my case, the automation is triggered in local and started by a system service installed in the server.
pywinauto.findwindows.ElementNotFoundError:
{'title': '<my-wanted-title>', 'backend': 'win32', 'visible_only': False}
It is finally solved with another python third-party library pywin32, so providing a backup solution here.
'''
Keep finding message box with specified title and clicking button to close it,
until stopped by the main thread.
'''
import time
from threading import Thread, Event
import win32gui
import win32con
class ButtonClicker(Thread):
def __init__(self, title:str, interval:int):
Thread.__init__(self)
self._title = title
self._interval = interval
self._stop_event = Event()
def stop(self):
'''Stop thread.'''
self._stop_event.set()
#property
def stopped(self):
return self._stop_event.is_set()
def run(self):
while not self.stopped:
try:
time.sleep(self._interval)
self._close_msgbox()
except Exception as e:
print(e, flush=True)
def _close_msgbox(self):
# find the top window by title
hwnd = win32gui.FindWindow(None, self._title)
if not hwnd: return
# find child button
h_btn = win32gui.FindWindowEx(hwnd, None,'Button', None)
if not h_btn: return
# show text
text = win32gui.GetWindowText(h_btn)
print(text)
# click button
win32gui.PostMessage(h_btn, win32con.WM_LBUTTONDOWN, None, None)
time.sleep(0.2)
win32gui.PostMessage(h_btn, win32con.WM_LBUTTONUP, None, None)
time.sleep(0.2)
if __name__=='__main__':
t = ButtonClicker('Configuration Error', 3)
t.start()
time.sleep(10)
t.stop()
I'm kind of a newbie to Python, and I'm writing some code to take data via a user input and put it into a .csv file. To do that, the program needs to pass data from class to class.
To teach myself how to pass data, I took code from here. I did have to alter the code a bit to get it to start up, making sure that the make_widget and print_it functions can pull the "name" variable stored in self.app_data data structure properly.
from tkinter import *
from tkinter import ttk
class MyApp(Tk):
def __init__(self):
Tk.__init__(self)
self.app_data={'name': StringVar}
container = ttk.Frame(self)
container.pack(side="top", fill="both", expand = True)
self.frames = {}
for F in (PageOne, PageTwo):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky = NSEW)
self.show_frame(PageOne)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class PageOne(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller=controller
ttk.Label(self, text='PageOne').grid(padx=(20,20), pady=(20,20))
self.make_widget(controller)
def make_widget(self, controller):
self.controller=controller
self.some_entry = ttk.Entry(self, textvariable=self.controller.app_data['name'], width=8)
self.some_entry.grid()
button1 = ttk.Button(self, text='Next Page',command=lambda: controller.show_frame(PageTwo))
button1.grid()
class PageTwo(ttk.Frame):
def __init__(self, parent, controller):
ttk.Frame.__init__(self, parent)
self.controller=controller
ttk.Label(self, text='PageTwo').grid(padx=(20,20), pady=(20,20))
button1 = ttk.Button(self, text='Previous Page',command=lambda: controller.show_frame(PageOne))
button1.grid()
button2 = ttk.Button(self, text='press to print', command= self.print_it())
button2.grid()
def print_it(self):
value=self.controller.app_data['name'].get()
print ('The value stored in StartPage some_entry = ', value)#What do I put here
#to print the value of some_input from PageOne
When I run this program, it does start up, and I can move from frame to frame, but it does not print the "name" variable.
When I close the window, I get the error:
TypeError: get() missing 1 required positional argument: 'self'
Which the traceback blames on the line:
value=self.controller.app_data['name'].get()
What am I doing wrong? For what it's worth, I'm writing the code in Python 3.5.
I really appreciate any help that you guys could give me.
I have a Python MainWindow(QMainWindow) class in a file window.py, and i import a Movimentos(Qdialog) from file exportar.py .
When i open Qdialog Movimentos, how do i use a def function that's inside Mainwindow?
Been searching and can't find an answer, sorry if it's been answered.
Would copy the code but its got around 600 lines...have to maintain a project and although i have some experience in python, PyQT is not my forte.
class Movimentos(QDialog, Ui_Movimentos):
"""
Class documentation goes here.
"""
def __init__(self, MainWindow):
"""
Constructor
"""
QDialog.__init__(self, MainWindow)
self.setupUi(self)
self.resize(750, 700)
#---
exit=QAction(self)
self.connect(exit,SIGNAL('triggered()'),SLOT('close()'))
self.dteate.setDate(QDate.currentDate())
self.dteate.setTime(QTime.currentTime())
self.dteDesde.setDate(QDate.currentDate().addDays(-1))
self.memcsv = cStringIO.StringIO()
self.row = []
this is from mainwindow where i call Movimentos
#pyqtSignature("")
def on_actionMovimentos_triggered(self):
self.ctimer.stop()
try:
self.wndmov = Movimentos(self)
self.wndmov.exec_()
except:
print "sem conexoes ou erro ao abrir janela"
pass
self.ctimer.start(60000)
So I'm currently learning pyglet for Python 2.7 and I'm trying to make a simple game that has levels. The 1st 'scene' would be the title/intro part, 2nd would be a tutorial of some sort, and the rest are the game levels themselves.
For this, I've created 7 batches(1 intro, 1 tutorial, 5 levels) namely batch, batch1, ... batch6. I've also created 7 classes for each of these batches that represent the scenes/levels. This is what I've done for the intro batch and class:
batch = pyglet.graphics.Batch()
batch1 = pyglet.graphics.Batch()
class StartState:
def __init__(self):
self.welcome = pyglet.text.Label('WELCOME TO', font_name='Arial', font_size=32, color=(200,255,255,255), x=400, y=550, anchor_x='center', anchor_y='center', batch=batch)
self.title = pyglet.text.Label("MY GAME", font_name='Arial', font_size=32, color=(100,200,170,255), x=400, y=450, anchor_x='center', anchor_y='center', batch=batch)
self.press = pyglet.text.Label("press 'SPACE' to continue", font_name='Arial', font_size=32, color=(200,255,150,255), x=400, y=250, anchor_x='center', anchor_y='center', batch=batch)
def update(self, dt):
if keymap[pyglet.window.key.SPACE]:
self.welcome.delete()
self.title.delete()
self.press.delete()
states.pop()
batch1.draw()
The other scenes would also look like that. the states list is a list that I use to store my classes/scenes. states = [Level5(), Level4(), ... , TutorialState(), StartState()]. So every time the condition to advance is fulfilled, which in this class is to press 'SPACE', the window will be 'cleared' i.e. delete the sprites/labels and proceed to the next scene by using states.pop() and batch1.draw().
After I've typed these classes, I added this at the end:
#window.event
def on_draw():
window.clear()
batch.draw()
def update(dt):
if len(states):
states[-1].update(dt)
else:
pyglet.app.exit()
states.append(Level5())
states.append(Level4())
states.append(Level3())
states.append(Level2())
states.append(Level1())
states.append(TutorialState())
states.append(StartState())
pyglet.clock.schedule_interval(update, 1.0/60.0)
window.clear()
window.flip()
window.set_visible(True)
pyglet.app.run()
The problem here is that it only loads the starting batch/scene. Whenever I press 'SPACE' to go to the tutorial scene the labels/sprites of the starting batch disappear but it doesn't draw batch1 or load the the tutorial class/scene. Any suggestions?
After creating a batch for each scene class:
import pyglet
from pyglet.window import key
class SceneTemplate(object):
"""a template with common things used by every scene"""
def __init__(self, text):
self.batch = pyglet.graphics.Batch()
self.label = pyglet.text.Label(
text,
font_name='Arial', font_size=32,
color=(200, 255, 255, 255), x=32, y=704,
batch=self.batch)
# (...)
class MainMenuScene(SceneTemplate):
def __init__(self):
super(MainMenuScene, self).__init__(text='MainMenuScene')
# (...)
class IntroScene(SceneTemplate):
def __init__(self):
super(IntroScene, self).__init__(text='Introduction')
# (...)
class Level1(SceneTemplate):
def __init__(self):
super(Level1, self).__init__(text='Level 1')
# (...)
You can control the state/scene in another class, such as a window class (personally I like to subclass the pyglet window, to keep things organized and some other reasons):
class Window(pyglet.window.Window):
def __init__(self):
super(Window, self).__init__(width=1024, height=768)
self.states = [MainMenuScene(), IntroScene(), Level1()] # and so on...
self.current_state = 0 # later you change it to get the scene you want
self.set_visible()
def on_draw(self):
self.clear()
self.states[self.current_state].batch.draw()
def on_key_press(self, symbol, modifiers):
if symbol == key.SPACE:
new_state = self.current_state + 1
new_state = new_state % len(self.states)
self.current_state = new_state
# if you want each scene to handle input, you could use pyglet's push_handlers(), or even something like:
# self.states[self.current_state].on_key_press(symbol, modifiers)
# giving them access to the window instance might be needed.
if __name__ == '__main__':
window = Window()
pyglet.app.run()
I am working on creating a LabelFrame class using Tkinter, which creates a wrapper around a group of items I wish to include one by one, by pressing an add button, that calls a function to create more of that item.
I have the code running, where I can see the LabelFrame and addbuttun. But once I press the button the function being called I get an error:
addmeter() takes exactly 1 argument (0 given)
I need to this function to add a class inside the LabelFrame, and this is where I am stuck.
I have listed my code below.
from Tkinter import *
root = Tk()
root.title("LabelFrame with embedded add voltmeters")
root.geometry("600x200+400+400")
def addmeter(self):
#Create frame for the voltmeter
voltsmet1 = LabelFrame(self.master, text = "Volts")
#add Text box for the serial output.
voltinfo = Text(voltsmet1, bg="BLACK", height=10, width =20 )
#add in reg command to find our data from queue and display it
#packs the widgets on the grid for display
voltsmet1.pack(side=LEFT, expand=True)
voltinfo.pack(side=LEFT, expand=True)
class wrapper(LabelFrame):
def __init__(self,master):
self.master = master
self.create_wrapper()
def create_wrapper(self):
wrapper = LabelFrame(self.master, text = "Volt Meters")
add_button = Button(wrapper, text="add", command=addmeter)
wrapper.pack()
add_button.pack()
new= wrapper(root)
root.mainloop()
Use lambda function:
add_button = Button(wrapper, text="add", command=lambda:addmeter(self))
EDIT:
Do you mean this ?
I use wrapper in lambda function
add_button = Button(wrapper, text="add", command=lambda:addmeter(wrapper))
and I remove .master in addmeter
Full code:
from Tkinter import *
root = Tk()
root.title("LabelFrame with embedded add voltmeters")
root.geometry("600x200+400+400")
def addmeter(parent):
#Create frame for the voltmeter
voltsmet1 = LabelFrame(parent, text = "Volts")
#add Text box for the serial output.
voltinfo = Text(voltsmet1, bg="BLACK", height=10, width =20 )
#add in reg command to find our data from queue and display it
#packs the widgets on the grid for display
voltsmet1.pack(side=LEFT, expand=True)
voltinfo.pack(side=LEFT, expand=True)
class wrapper(LabelFrame):
def __init__(self,master):
self.master = master
self.create_wrapper()
def create_wrapper(self):
wrapper = LabelFrame(self.master, text = "Volt Meters")
add_button = Button(wrapper, text="add", command=lambda:addmeter(wrapper))
wrapper.pack()
add_button.pack()
new= wrapper(root)
root.mainloop()
btw: I change name self to parent in addmeter() to make names more logical.