Pass/Fail images in Tkinter - image

I want to show two different images when pressing two different buttons The "Show Pass" button should show an image (at a new window) with green color and text "PASS" on it while the "Show Fail" should show an image with red color and text "FAIL". However even though during creation of slave window (for PASS/FAIL images) i perform a withdraw to hide it, when i run program they are shown both images and pressing of "Show Pass" or "Show Fail" buttons have not any affect. It follows my code:
from tkinter import *
GUI_WIDTH = 500
GUI_HEIGHT = 350
resultShown = False
def showUUTResult(UUTresult, slave):
global resultShown
if (resultShown == 'True'):
slave.withdraw()
slave = Toplevel()
slave.deiconify()
slave.title("Res")
canvas_width = 185
canvas_height = 150
canvas = Canvas(slave, width=canvas_width, height=canvas_height)
canvas.grid(row=5, column=5, sticky=N)
if UUTresult == 'PASS':
img = PhotoImage(file="C:\PythonPrograms\Pass.png")
print('Result is PASS')
elif UUTresult == 'FAIL':
img = PhotoImage(file="C:\PythonPrograms\Fail.png")
print('Result is FAIL')
else:
print('Unknown UUT Result Type!')
canvas.create_image(10, 10, anchor=NW, image=img)
canvas.image = img
resultShown = 'True'
master = Tk()
gui_resolution = str(GUI_WIDTH)+'x'+str(GUI_HEIGHT)
master.geometry(gui_resolution)
master.resizable(FALSE, FALSE)
master.title("PASS FAIL Trial")
slave = Toplevel()
slave.withdraw()
passTestButton = Button(master, text="Show Pass", command=showUUTResult('PASS', slave))
passTestButton.grid(column=1, row=0, pady=5, ipadx=12)
failTestButton = Button(master, text="Show Fail", command=showUUTResult('FAIL', slave))
failTestButton.grid(column=1, row=1, pady=5, ipadx=12)
master.mainloop()

The problem is with the lines that create the buttons and assign a command to them.
failTestButton = Button(master, text="Show Fail", command=showUUTResult('FAIL', slave))
What this is saying is create a button with the text "Show Fail" and set the command to the result of the function showUUTResult when passed some arguments. showUUTResult doesn't return anything so what happens is that the window opens straight away when your program runs, showing the image, but clicking on the button does nothing.
You can solve this with a simple addition
failTestButton = Button(master, text="Show Fail", command=lambda: showUUTResult('FAIL', slave))
lambda creates an anonymous function which is called when the button is pressed.
This should fix your problem.

Related

Close all windows except for the starting window in tkinter

In this code below, I made a simple route guidance by opening defined windows each time I press a specific button e.g.) Mainmenu -> Classroom Floor -> Classroom No.
I'm trying to make a 'Home' button that will close all open windows except for the first Main Menu window with WELCOME written.
For example, after I press btn7, btn702, then I have 4 windows open. I would like to add a 'Home' button that will close 3 newly open windows and leave the first window alive. How might I make this kind of button?
from os import system
from tkinter import *
from PIL import ImageTk, Image
mainmenu = Tk()
mainmenu.title("CAU 310 GUIDE MAP")
mainmenu.geometry("1280x800+0+0")
canvas = Canvas(mainmenu, width = 1280, height = 800)
canvas.pack(fill='both', expand = True)
canvas.create_text(640, 250, text = 'WELCOME', font=times 45)
btnclassroom = Button(mainmenu, padx=5, pady=5,text="Classroom", font="times 30", command=selectfloor)
btnclassroom.place(x=140, y=570)
def selectfloor():
mainmenu = Tk()
mainmenu.title("DESTINATION")
mainmenu.geometry("1280x800+0+0")
mainmenu.config(bg='white')
canvas = Canvas(mainmenu, width = 1280, height = 800)
canvas.pack(fill='both', expand = True)
canvas.create_text(640, 150, text = 'Select floor of classroom', font='Arial 40')
btn7=Button(mainmenu, padx=4, pady=4, text="7F", font="Arial 42 bold", command=floor7)
btn7.place(x=160-5, y=490)
def floor7():
mainmenu = Tk()
mainmenu.title("FLOOR 7")
mainmenu.geometry("1280x800+0+0")
canvas = Canvas(mainmenu, width = 1280, height = 800)
canvas.pack(fill='both', expand = True)
canvas.create_text(640, 150, text = 'Select classroom No.', font='Arial 40')
btn702=Button(mainmenu, padx=3, pady=3, text="No.702", font="Arial 38 bold", command=room702)
btn702.place(x=100+220*1, y=240)
mainmenu.mainloop()
def room702():
mainmenu = Tk()
mainmenu.title("Elevator 1")
mainmenu.geometry("1280x800+0+0")
lobby = ImageTk.PhotoImage(Image.open("1F_elevator1.jpg"), master=mainmenu)
canvas = Canvas(mainmenu, width = 1280, height = 800)
canvas.pack(fill='both', expand = True)
canvas.create_image(0, 0, image=lobby,anchor = "nw")
mainmenu.mainloop()
mainmenu.mainloop()
**I've been googling around for this kind of matter, and I think I've got a hint of making the 'selectfloor', 'floor7', 'room702' window as a children widget. But I'm still not sure how to make it happen.
You can store the windows in a list, and then iterate over the list to destroy them.
Here's a simplified example. This example uses Toplevel windows rather than instances of Tk. It's not clear why you're using multiple instances of Tk, but in general you should only ever have one. This same technique works with any sort of widgets, however.
import tkinter as tk
windows = []
def delete_all_but_first():
for window in windows[1:]:
window.destroy()
def new_window():
window = tk.Toplevel(root)
windows.append(window)
window.title(f"Window #{len(windows)}")
root = tk.Tk()
windows.append(root)
del_all = tk.Button(root, text="Delete all", command=delete_all_but_first)
new = tk.Button(root, text="New window", command=new_window)
new.pack(side="top", padx=20, pady=20)
del_all.pack(side="top", padx=20, pady=20)
root.mainloop()
There's an optimization you can make if you use Toplevel instead of Tk, and if you always make the windows direct children of the root window. In that case you can just iterate over all children of root, and delete any window that is a top-level.
In this case, you don't need to maintain the windows list.
def delete_toplevels():
for child in root.winfo_children():
if child.winfo_class() == "Toplevel":
child.destroy()
def new_window():
window = tk.Toplevel(root)
window.title(f"Window #{len(windows)}")
...
del_all = tk.Button(root, text="Delete all", command=delete_toplevels)

How to create an input box with iron python using windows.forms?

For a simple Gui in Iron python I need a simple dialog box with an input text field and OK and cancel button and return value of input text, equivalent to Visual Basic input box.
So basically, dialog pops up, you enter value, hit OK an dialog box closes and returns value to calling function.
I could not find anything in the windows forms library.
I guess you need to create a form yourself from scratch, using text box, etc..?
Is there really no input box in winforms?
If so, could anyone share how to create one with winforms and iron python?
Thanks for help!
Nils
I am new to Ironpython and GUI programming, therefore the following solution might not be elegant neither complete, but it seems to work.
Any ideas for improvement?
import clr
clr.AddReference("System.Windows.Forms")
clr.AddReference("System.Drawing")
from System.Drawing import Point
from System.Windows.Forms import Button, Form, Label, TextBox, FormStartPosition, FormBorderStyle
class MyInputBoxClass(Form):
def __init__(self,message, title, defaultText):
#Creates Input Box with text Input Field
#define form
self.Text = title
self.Width = 600
self.Height = 110
self.StartPosition = FormStartPosition.CenterScreen;
self.FormBorderStyle = FormBorderStyle.FixedDialog
self.MinimizeBox = False;
self.MaximizeBox = False;
#define label
self.label = Label()
self.label.Text = message
self.label.Location = Point(10, 10)
self.label.Height = 30
self.label.Width = 250
#define text box
self.textbox = TextBox()
self.textbox.Text = defaultText
self.textbox.Location = Point(10, 40)
self.textbox.Width = 500
#define button
self.button1 = Button()
self.button1.Text = 'ok'
self.button1.Location = Point(510, 40)
self.AcceptButton = self.button1
#define dialog result
self.button1.DialogResult = DialogResult.OK;
#add controls to form
self.Controls.Add(self.label)
self.Controls.Add(self.textbox)
self.Controls.Add(self.button1)
#Todo: Handel Close Input Box Event
def MyInputBox(message, title, defaultText):
form = MyInputBoxClass(message, title, defaultText)
form.ShowDialog()
#Application.Run(form2) #this is not working, you need ShowDialog for modal form
return form.textbox.Text
def TestGui(analysis_obj):
#This function is beeing called from API
inputTextFromDialogBox = MyInputBox("Please Enter Example Text","ExampleInputBox","Its working but I'm not convinced")
print ("Input Box Return Value is '%s'"%inputTextFromDialogBox)
#ExtAPI.Log.WriteMessage("Input Box Return Value is '%s'"%inputTextFromDialogBox)

Display text on another process' screen (overlay)

I have a question, its more an OS-based one.
I'm playing a video game and I want to be able to put a textual timer ontop of the game's screen as if it was a part of the game itself.
Now, I can write a program in any language that displays a TextBox with a timer on the screen, but if I run it, the game's process (lets call it game.exe) "loses" its focus and I get my TextBox focused and interactive by the OS.
Is there any option to display that text "ontop" of the game.exe that comes from an entire different process? as if there were "layers" to the screen. Also, this text shouldn't be intractable, clickable or make the game.exe process lose its focus.
Here's a very simple example I drew:
Thanks a lot!
Solved this using a window trick with python and tkinter with some windows api stuff.
The trick is to create a transparent non-clickable window and keep it always on top.
I've basically combined this answer with a bunch of simpler stuff like removing window's border and set to auto fullscreen.
from tkinter import *
import time
import win32gui
import win32api
from win32api import GetSystemMetrics
# WIDTH = 500
# HEIGHT = 500
WIDTH = GetSystemMetrics(0)
HEIGHT = GetSystemMetrics(1)
LINEWIDTH = 1
TRANSCOLOUR = 'gray'
title = 'Virtual whiteboard'
global old
old = ()
global HWND_t
HWND_t = 0
tk = Tk()
# tk.title(title)
tk.lift()
tk.wm_attributes("-topmost", True)
tk.wm_attributes("-transparentcolor", TRANSCOLOUR)
tk.attributes('-fullscreen', True)
state_left = win32api.GetKeyState(0x01) # Left button down = 0 or 1. Button up = -127 or -128
canvas = Canvas(tk, width=WIDTH, height=HEIGHT, highlightthickness=0)
canvas.pack()
canvas.config(cursor='tcross')
canvas.create_rectangle(0, 0, WIDTH, HEIGHT, fill=TRANSCOLOUR, outline=TRANSCOLOUR)
canvas.create_text(WIDTH/2,HEIGHT/2,fill="white",font="Arial 20", text="TEXT GOES HERE")
def putOnTop(event):
event.widget.unbind('<Visibility>')
event.widget.update()
event.widget.lift()
event.widget.bind('<Visibility>', putOnTop)
def drawline(data):
global old
if old !=():
canvas.create_line(old[0], old[1], data[0], data[1], width=LINEWIDTH)
old = (data[0], data[1])
def enumHandler(hwnd, lParam):
global HWND_t
if win32gui.IsWindowVisible(hwnd):
if title in win32gui.GetWindowText(hwnd):
HWND_t = hwnd
win32gui.EnumWindows(enumHandler, None)
tk.bind('<Visibility>', putOnTop)
tk.focus()
running = 1
while running == 1:
try:
tk.update()
time.sleep(0.01)
if HWND_t != 0:
windowborder = win32gui.GetWindowRect(HWND_t)
cur_pos = win32api.GetCursorPos()
state_left_new = win32api.GetKeyState(0x01)
if state_left_new != state_left:
if windowborder[0] < cur_pos[0] and windowborder[2] > cur_pos[0] and windowborder[1] < cur_pos[1] and windowborder[3] > cur_pos[1]:
drawline((cur_pos[0] - windowborder[0] - 5, cur_pos[1] - windowborder[1] - 30))
else:
old = ()
except Exception as e:
running = 0
print("error %r" % (e))

Add an image button to top level window Tkinter

I'm building a small GUI application, that once a button is clicked a new top level window will open and it should display images for buttons.
I can get the image button to work on the root window, but not on the top level window. Only a blackbox appears.
I have a generic button on both windows and they do work.
I'm new to Python.
import Tkinter
from Tkinter import *
from PIL import ImageTk, Image
root = Tkinter.Tk()
root.title("First Window")
root.configure(background = "black")
def new_window():
win2 = Toplevel(root)
win2.geometry("650x350+50+40")
win2.title("Second Window!")
win2.configure(background = "white")
def close1():
win2.destroy()
img1 = ImageTk.PhotoImage(Image.open("./images/close.gif"))
c1 = Button(win2, image = img1, bg ="black", command = close1)
c1.grid(row = 1)
c2= Tkinter.Button(win2, text='close', command = close1)
c2.grid(row = 2)
nw = Tkinter.Button(root, text = 'New Window' , command = new_window)
nw.grid(row = 1)
def close3():
root.destroy()
img3 = ImageTk.PhotoImage(Image.open("./images/close.gif"))
c3 = Button(root, image = img3, bg ="black", command = close3)
c3.grid(row = 2)
root.mainloop()
When you create the new toplevel, you are using a local variable to refer to the image. Because of this, when the method exits, the garbage collector will delete the image. You need to save a reference in a global variable, or some other way to protect it from the garbage collector
A common way to save a reference is to make it an attribute of the button:
img1 = ImageTk.PhotoImage(...)
c1 = Button(...)
c1.image = img1

How to make buttons stay pressed using corona

I am trying to get my buttons to stay "pressed" once it is released. Right now I am using the improved Buttons Module for corona and I have the default image being the button looking unpressed, and the over image being replaced by an image that looks pressed.
What I am trying to do is once the button is pressed, it stays on the over image. Here is how my code is set up for the button I am testing it on.
local digButton = buttons.newButton{
default = "digButton.png",
over = "digButtonPressed.png",
onEvent = digButtonFunction,
id = "dig"
}
digButton:setReferencePoint(display.CenterReferencePoint)
digButton.x = display.contentWidth/5
digButton.y = display.contentHeight/1.9
Also, I have a function (digButtonFunction) that sets the id of this button to a variable to be used to run an if statement for when the user pushes a button following this one.
This sounds to me like what you really want is a switch. Buttons are not really designed from a UI perspective to do that. The down-state is there just to give feedback to the user that some action happened.
If it were me, I'd not use the button bit at all, but load in to images using display.newImageRect() and draw the downstate first, then the upstate. Built a touch event listener on each one that will hide one or the other. I do this in my games for my sound on/off buttons.
local soundOn = true
local soundOnBtn, soundOffBtn
local function soundToggle(event)
if soundOn then
soundOn = false
soundOnBtn.isVisible = false
soundOffBtn.isVisible = true
else
soundOn = true
soundOnBtn.isVisible = true
soundOffBtn.isVisible = false
end
return true
end
soundOnBtn = display.newImageRect("images/switch_on.png", 46, 36)
soundOnBtn.x = display.contentWidth / 2 + 25
soundOnBtn.y = display.contentHeight / 2 - 15
group:insert(soundOnBtn)
soundOnBtn:addEventListener("tap", soundToggle)
soundOffBtn = display.newImageRect("images/switch_off.png", 46, 36)
soundOffBtn.x = display.contentWidth / 2 + 25
soundOffBtn.y = display.contentHeight / 2 - 15
group:insert(soundOffBtn)
soundOffBtn:addEventListener("tap", soundToggle)
soundOffBtn.isVisible = false

Resources