New FigureCanvasTkAgg always keeps a black border - python-3.x

I want to show some figures using tkinter, but new FigureCanvasTkAgg always keeps a black border. For example, I want to build two figures with red borders, but the new one has a black border, just like this:
enter image description here
But when the display window is not active, the black border disappear:
enter image description here
How to solve this problem? Thank you!
Here's the code:
import tkinter as tk
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
class display_window:
def __init__(self, width = 1024, height = 768):
self.figure_dict = {}
self.display_level = tk.Tk()
screen_width = self.display_level.winfo_screenwidth()
screen_height = self.display_level.winfo_screenheight()
init_position_x = int((screen_width - width) / 2)
init_position_y = int((screen_height - height) / 2)
position = str(width) + 'x' + str(height) + '+' + str(init_position_x) + '+' + str(init_position_y)
self.display_level.geometry(position)
self.x_offset = 120
self.y_offset = 10
self.figures_interval = 10
new_figure_button = tk.Button(self.display_level, text='new figure', command=self.new_figure_callback)
new_figure_button.place(x=5, y=5)
def new_figure_callback(self):
fig = Figure(figsize=(3, 2), dpi=100)
fig_plot = fig.add_subplot(111)
fig_plot.grid()
figure_canvas = FigureCanvasTkAgg(fig, self.display_level)
figure_widget = figure_canvas.get_tk_widget()
figure_widget.config(highlightthickness = 2, highlightbackground = "red", cursor='cross')
self.figure_dict[figure_widget] = {
"fig": fig,
"fig_plot": fig_plot,
"figure_canvas": figure_canvas,
}
self.arrange_figures(self.x_offset, self.y_offset, self.figures_interval)
def arrange_figures(self, x_offset, y_offset, figures_interval):
figures_area_width = self.display_level.winfo_width() - x_offset - figures_interval
figures_area_height = self.display_level.winfo_height() - y_offset - figures_interval
figure_count = len(self.figure_dict)
figure_width = figures_area_width
figure_height = (figures_area_height - figures_interval * (figure_count - 1)) / figure_count
for i, it in enumerate(self.figure_dict.keys()):
it.config(height = figure_height, width = figure_width)
it.place(x = x_offset, y = y_offset + i * (figure_height + figures_interval))
if __name__ == '__main__':
display_window()
tk.mainloop()
I want all the figures' borders display as in the config function.

Related

Display full function output's in tkinter Message widget and not partial output

I am new to tkinter and I am building password generator. The function is running perfectly outside tkinter algorithm.
A clear example of my actual issue: If you try to output more than one password, let's say 3 passwords, tkinter Message widget will only output the last one and not the 3 passwords, the rest 2 passwords are printed in terminal.
To give you pre-debug for fast troubleshooting, the main issue reside in paStr variable (line 61) which holds randompassword function's output (line 63). The tkinter message widget is from line 153 to 162.
While it's a long code to post on stackoverflow but actually I am posting only 1/3 of the full project and exactly where my issue reside.
Instructions:
Using python 3.8
For password length please input minimum 8 for the smooth of the function.
For password number or how many password, input more than 1. Input 2 or more to show up the actual issue.
PS: Please try the code in your computer interpreter, it is not possible to troubleshoot it using smartphone or random thoughts without trying it in interpreter.
Thank you very much for your professional support.
import tkinter as tk
import tkinter.font as tkFont
from tkinter import *
from tkinter import ttk
import random
import string
root = tk.Tk()
root.title("P-GEN")
width=600
height=550
screenwidth = root.winfo_screenwidth()
screenheight = root.winfo_screenheight()
alignstr = '%dx%d+%d+%d' % (width, height, (screenwidth - width) / 2, (screenheight - height) / 2)
root.geometry(alignstr)
root.resizable(width=False, height=False)
passLen = IntVar()
passNum = IntVar()
paStr = StringVar()
def randompassword():
uchars = int(passLen.get() / 4)
lchars = int(passLen.get() / 4)
dchars = int(passLen.get() / 4)
schars = int(passLen.get() / 4)
str_uchars, str_lchars, str_dchars, str_schars = '', '', '', ''
for i in range(uchars):
str_uchars += random.SystemRandom().choice(string.ascii_uppercase)
for i in range(lchars):
str_uchars += random.SystemRandom().choice(string.ascii_lowercase)
for i in range(dchars):
str_uchars += random.SystemRandom().choice(string.digits)
for i in range(schars):
str_uchars += random.SystemRandom().choice(string.punctuation)
random_str = str_uchars + str_lchars + str_dchars + str_schars
random_str = ''.join(random.sample(random_str, len(random_str)))
l = list(random_str)
random.shuffle(l)
result = ''.join(l)
paStr.set(result)
return result
def output():
n = 0
while n < passNum.get():
print(randompassword())
n=n+1
enter_chars=tk.Label(root)
ft = tkFont.Font(family='Arial',size=10)
enter_chars["font"] = ft
enter_chars["fg"] = "#333333"
enter_chars["justify"] = "left"
enter_chars["text"] = "Enter Chars Length"
enter_chars["relief"] = "groove"
enter_chars.place(x=20,y=170,width=169,height=31)
pass_length=tk.Entry(root)
pass_length["bg"] = "#d2f4d4"
pass_length["borderwidth"] = "3px"
ft = tkFont.Font(family='Times',size=10)
pass_length["font"] = ft
pass_length["fg"] = "#333333"
pass_length["justify"] = "center"
pass_length["text"] = "Entry"
pass_length["relief"] = "sunken"
pass_length.place(x=220,y=170,width=142,height=30)
pass_length["textvariable"] = passLen
enter_passN=tk.Label(root)
ft = tkFont.Font(family='Arial',size=10)
enter_passN["font"] = ft
enter_passN["fg"] = "#333333"
enter_passN["justify"] = "left"
enter_passN["text"] = "Enter Passwords Number"
enter_passN["relief"] = "groove"
enter_passN.place(x=20,y=240,width=169,height=31)
pass_num=tk.Entry(root)
pass_num["bg"] = "#d2f4d4"
pass_num["borderwidth"] = "3px"
ft = tkFont.Font(family='Arial',size=10)
pass_num["font"] = ft
pass_num["fg"] = "#333333"
pass_num["justify"] = "center"
pass_num["text"] = "Entry"
pass_num["relief"] = "sunken"
pass_num.place(x=220,y=240,width=142,height=30)
pass_num["textvariable"] = passNum
gen_pass=tk.Button(root)
gen_pass["activebackground"] = "#7ff14e"
gen_pass["bg"] = "#efefef"
ft = tkFont.Font(family='Arial',size=10)
gen_pass["font"] = ft
gen_pass["fg"] = "#000000"
gen_pass["justify"] = "center"
gen_pass["text"] = "Generate Passwords"
gen_pass["relief"] = "raised"
gen_pass.place(x=20,y=310,width=169,height=31)
gen_pass["command"] = output
#this is the message widget where the generated passwords will be displayed
generated_pass=tk.Message(root)
generated_pass["bg"] = "#d2f4d4"
generated_pass["borderwidth"] = "3px"
ft = tkFont.Font(family='Arial',size=10)
generated_pass["font"] = ft
generated_pass["fg"] = "#333333"
generated_pass["justify"] = "center"
generated_pass["relief"] = "sunken"
generated_pass.place(x=220,y=310,width=346,height=192)
generated_pass["textvariable"] = paStr # paStr is the variable which holds the generated passwords from randompasword function
if __name__ == "__main__":
root.mainloop()
Just move passstr.set(result) to above return result:
def random_pwd(uchars = 3, lchars = 3, dchars = 3, schars = 3):
..... #your same code
passstr.set(result)
return result
Code placed after return wont be executed, so you have to change the order of the lines a bit.
Make sure to change the last part of your code to:
#this is the message widget where the generated passwords will be displayed
generated_pass=tk.Text(root,bg='#d2f4d4',borderwidth=3,font=('arial',10),fg='#333333',relief='sunken')
generated_pass.place(x=220,y=310,width=346,height=192)
Changed from Messagbox to Text widget, and reduced the unnecessary amount of code.
Then, change your output() to:
def output():
n = 0
while n < passNum.get():
print(randompassword())
n=n+1
generated_pass.insert('1.0',randompassword()+'\n')

Adding GUI into the python scripts

I've tried to add the GUI (tkinter) into my script, but to no avail. If anyone can help me, i would be so grateful. I'm using Python 3.6 and i think the latest opencv?
I have only started programming 2 weeks ago. So, kinda new into all this. Basically, I want to create a window that just pick the image from my folder and then process it through the script so that whenever i want to use another image, i don't have to change the script. I hope that make sense..
this is the script that i took from Chris Dahms from youtube, and managed to change it to what I want.
import cv2
import numpy as np
import os
import DetectChars
import DetectPlates
import PossiblePlate
SCALAR_BLACK = (0.0, 0.0, 0.0)
SCALAR_WHITE = (255.0, 255.0, 255.0)
SCALAR_YELLOW = (0.0, 255.0, 255.0)
SCALAR_GREEN = (0.0, 255.0, 0.0)
SCALAR_CYAN = (255.0, 255.0, 0.0)
showSteps = False
def main():
blnKNNTrainingSuccessful = DetectChars.loadKNNDataAndTrainKNN()
if blnKNNTrainingSuccessful == False:
print ("\nerror: KNN training was not successful\n")
return
imgOriginalScene = cv2.imread("CAR/Malaysia/22.jpg")
if imgOriginalScene is None:
print ("\nerror: image not read from file \n\n")
os.system("pause")
return
if imgOriginalScene is None:
print ("\nerror: image not read from file \n\n")
os.system("pause")
return
listOfPossiblePlates = DetectPlates.detectPlatesInScene(imgOriginalScene)
listOfPossiblePlates = DetectChars.detectCharsInPlates(listOfPossiblePlates)
cv2.imshow("imgOriginalScene", imgOriginalScene)
if len(listOfPossiblePlates) == 0:
print ("\nno license plates were detected\n")
else:
listOfPossiblePlates.sort(key = lambda possiblePlate: len(possiblePlate.strChars), reverse = True)
licPlate = listOfPossiblePlates[0]
cv2.imshow("Image Plate", licPlate.imgPlate)
cv2.imshow("Image Threshold", licPlate.imgThresh)
if len(licPlate.strChars) == 0:
print ("\nno characters were detected\n\n")
return
drawRedRectangleAroundPlate(imgOriginalScene, licPlate)
print ("\nlicense plate read from image = " + licPlate.strChars + "\n")
print ("----------------------------------------")
writeLicensePlateCharsOnImage(imgOriginalScene, licPlate)
cv2.imshow("imgOriginalScene", imgOriginalScene)
cv2.imwrite("imgOriginalScene.png", imgOriginalScene)
cv2.waitKey(0)
return
def drawRedRectangleAroundPlate(imgOriginalScene, licPlate):
p2fRectPoints = cv2.boxPoints(licPlate.rrLocationOfPlateInScene)
cv2.line(imgOriginalScene, tuple(p2fRectPoints[0]), tuple(p2fRectPoints[1]), SCALAR_RED, 2)
cv2.line(imgOriginalScene, tuple(p2fRectPoints[1]), tuple(p2fRectPoints[2]), SCALAR_RED, 2)
cv2.line(imgOriginalScene, tuple(p2fRectPoints[2]), tuple(p2fRectPoints[3]), SCALAR_RED, 2)
cv2.line(imgOriginalScene, tuple(p2fRectPoints[3]), tuple(p2fRectPoints[0]), SCALAR_RED, 2)
def writeLicensePlateCharsOnImage(imgOriginalScene, licPlate):
ptCenterOfTextAreaX = 0
ptCenterOfTextAreaY = 0
ptLowerLeftTextOriginX = 0
ptLowerLeftTextOriginY = 0
sceneHeight, sceneWidth, sceneNumChannels = imgOriginalScene.shape
plateHeight, plateWidth, plateNumChannels = licPlate.imgPlate.shape
intFontFace = cv2.FONT_HERSHEY_SIMPLEX
fltFontScale = float(plateHeight) / 30.0
intFontThickness = int(round(fltFontScale * 2))
textSize, baseline = cv2.getTextSize(licPlate.strChars, intFontFace, fltFontScale, intFontThickness)
( (intPlateCenterX, intPlateCenterY), (intPlateWidth, intPlateHeight), fltCorrectionAngleInDeg ) = licPlate.rrLocationOfPlateInScene
intPlateCenterX = int(intPlateCenterX)
intPlateCenterY = int(intPlateCenterY)
ptCenterOfTextAreaX = int(intPlateCenterX)
if intPlateCenterY < (sceneHeight * 0.75):
ptCenterOfTextAreaY = int(round(intPlateCenterY)) + int(round(plateHeight * 1.6))
else:
ptCenterOfTextAreaY = int(round(intPlateCenterY)) - int(round(plateHeight * 1.6))
textSizeWidth, textSizeHeight = textSize
ptLowerLeftTextOriginX = int(ptCenterOfTextAreaX - (textSizeWidth / 2))
ptLowerLeftTextOriginY = int(ptCenterOfTextAreaY + (textSizeHeight / 2))
cv2.putText(imgOriginalScene, licPlate.strChars, (ptLowerLeftTextOriginX, ptLowerLeftTextOriginY), intFontFace, fltFontScale, SCALAR_CYAN, intFontThickness)
if __name__ == "__main__":
main()
cv2.waitKey()
cv2.destroyAllWindows()
Pre-processing stage
# Preprocess.py
import numpy as np
import math
# module level variables ##########################################################################
GAUSSIAN_SMOOTH_FILTER_SIZE = (5, 5)
ADAPTIVE_THRESH_BLOCK_SIZE = 19
ADAPTIVE_THRESH_WEIGHT = 9
def preprocess(imgOriginal):
imgGrayscale = extractValue(imgOriginal)
imgMaxContrastGrayscale = maximizeContrast(imgGrayscale)
height, width = imgGrayscale.shape
grayscaled = cv2.cvtColor(imgOriginal,cv2.COLOR_BGR2GRAY)
imgBlurred = np.zeros((height, width, 1), np.uint8)
imgBlurred, otsu = cv2.threshold(grayscaled,125,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
imgThresh = cv2.medianBlur(otsu,5)
return imgGrayscale, imgThresh
# end function
def extractValue(imgOriginal):
height, width, numChannels = imgOriginal.shape
imgHSV = np.zeros((height, width, 3), np.uint8)
imgHSV = cv2.cvtColor(imgOriginal, cv2.COLOR_BGR2HSV)
imgHue, imgSaturation, imgValue = cv2.split(imgHSV)
return imgValue
# end function
def maximizeContrast(imgGrayscale):
height, width = imgGrayscale.shape
imgTopHat = np.zeros((height, width, 1), np.uint8)
imgBlackHat = np.zeros((height, width, 1), np.uint8)
structuringElement = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
imgTopHat = cv2.morphologyEx(imgGrayscale, cv2.MORPH_TOPHAT, structuringElement)
imgBlackHat = cv2.morphologyEx(imgGrayscale, cv2.MORPH_BLACKHAT, structuringElement)
imgGrayscalePlusTopHat = cv2.add(imgGrayscale, imgTopHat)
imgGrayscalePlusTopHatMinusBlackHat = cv2.subtract(imgGrayscalePlusTopHat, imgBlackHat)
return imgGrayscalePlusTopHatMinusBlackHat
# end function
If all you are wanting is a window to select a file then this should work.
import Tkinter
from Tkinter import *
import tkSimpleDialog
from tkFileDialog import askopenfilename
master = Tk()
master.withdraw()
my_file = askopenfilename()
mainloop()
i recommend Gtk3 for your GUI.
here's a simple Gtk window with button:
#!/usr/bin/env python3
import gi
gi.require_version( 'Gtk', '3.0' )
from gi.repository import Gtk
class Window( Gtk.Window ):
def __init__( self ):
Gtk.Window.__init__( self )
self.connect( 'destroy', lambda q: Gtk.main_quit() )
button = Gtk.Button( "Gtk.Button" )
button.connect( "clicked", self.on_button_clicked )
grid = Gtk.Grid( )
grid.attach( button, 0, 0, 1, 1 )
self.add( grid )
self.show_all()
def on_button_clicked( self, button ):
print( "Gtk.Button was clicked" )
w = Window()
Gtk.main()

Image won't display on tkinter canvas

I'm really hoping for some help on this as it has me absolutely stumped. I have the code working on its own as per below:
from tkinter import *
from PIL import ImageTk
dam_level = [75]
c = Canvas(width = 200, height = 235, relief = "sunken", borderwidth = 2)
c.grid(row = 11, rowspan = 8, column = 4, columnspan = 2)
c_width = 200
c_height = 250
y_stretch = 1.9
y_gap = 35
x_stretch = 15
x_width = 90
x_gap = 30
for x, y in enumerate(dam_level):
x0 = x * x_stretch + x * x_width + x_gap
y0 = c_height - (y * y_stretch + y_gap)
x1 = x * x_stretch + x * x_width + x_width + x_gap
y1 = c_height - y_gap
c.create_rectangle(x0, y0, x1, y1, fill = "#008ae8")
y = (str(y))
c.create_text(x0 + 10, y0, anchor = SW, text = (y, "%"))
c.create_text(x0 + 60, y1 + 5, anchor = N, text = "Catchment")
photo = ImageTk.PhotoImage(file =
"/Users/Name/Desktop/python3.4/water.png")
c.create_image(10, 10, image = photo, anchor = NW)
mainloop()
However when I put it in my main application in its own function (with the rest of my code), the image won't display. The graph and canvas displays, just not the water.png image. There's no error log or anything. The only change I make when I put this in my app is adding 'self' to this line. (And I remove the 'mainloop()' of course).
c = Canvas(self, width = 200, height = 235, relief = "sunken", borderwidth = 2)
Any suggestions would be greatly appreciated.
Thanks Bryan, for pointing me in the right direction.
Fixed with:
c.image = photo

Draw a scale which ranges from red to green in Tkinter

I would like to draw a scale which ranges from red to green. I managed to do a scale which ranges from green to yellow. Now I have 2 possible solutions :
Either drawing 2 gradients : one from red to yellow and one from yellow to green. Then I can link the 2 drawings.
Or the better solution I think : Drawing one gradient from red to green with a checkpoint on the yellow.
How to implement this second solution ?
Here is my code from green to yellow. You can test it.
import tkinter as tk
class Example(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
f = GradientFrame(root)
f.pack(fill="both", expand=True)
class GradientFrame(tk.Canvas):
'''A gradient frame which uses a canvas to draw the background'''
def __init__(self, parent, borderwidth=1, relief="sunken"):
tk.Canvas.__init__(self, parent, borderwidth=borderwidth, relief=relief)
self._color1 = "green"
self._color2 = "yellow"
self._color3 = "red"
self.bind("<Configure>", self._draw_gradient)
def _draw_gradient(self, event=None):
'''Draw the gradient'''
self.delete("gradient")
width = 200
height = 50
limit = width
(r1,g1,b1) = self.winfo_rgb(self._color1)
(r2,g2,b2) = self.winfo_rgb(self._color2)
(r3,g3,b3) = self.winfo_rgb(self._color3)
r_ratio = float((r2-r1)) / limit
g_ratio = float((g2-g1)) / limit
b_ratio = float((b2-b1)) / limit
for i in range(limit):
nr = int(r1 + (r_ratio * i))
ng = int(g1 + (g_ratio * i))
nb = int(b1 + (b_ratio * i))
color = "#%4.4x%4.4x%4.4x" % (nr,ng,nb)
self.create_line(0,i,height,i, tags=("gradient",), fill=color)
self.lower("gradient")
for i in range(limit):
nr = int(r1 + (r_ratio * i))
ng = int(g1 + (g_ratio * i))
nb = int(b1 + (b_ratio * i))
color = "#%4.4x%4.4x%4.4x" % (nr,ng,nb)
self.create_line(0,i,height,i, tags=("gradient",), fill=color)
self.lower("gradient")
if __name__ == "__main__":
root = tk.Tk()
Example(root).pack(fill="both", expand=True)
root.mainloop()
Without the generalization or general aesthetics of the above code, I offer you a simple solution (implemented against the red to green gradient) here:
import tkinter
def rgb(r, g, b):
return "#%s%s%s" % tuple([hex(c)[2:].rjust(2, "0") for c in (r, g, b)])
root = tkinter.Tk()
root.title("Gradient")
gradient1 = tkinter.Canvas(root, width=255*2, height=50)
gradient1.pack()
gradient2 = tkinter.Canvas(root, width=255*2, height=50)
gradient2.pack()
for x in range(0, 256):
r = x
g = 255-x
gradient1.create_rectangle(x*2, 0, x*2 + 2, 50, fill=rgb(r, g, 0),
outline=rgb(r, g, 0))
for x in range(0, 256):
r = x*2 if x < 128 else 255
g = 255 if x < 128 else 255 - (x-128)*2
gradient2.create_rectangle(x*2, 0, x*2 + 2, 50, fill=rgb(r, g, 0),
outline=rgb(r, g, 0))
I believe it's what you meant by "yellow checkpoints". Thanks for the challenge! :^)

Slider won't change value in VPython

My slider won't change the value of the parameter I give it. The slider moves, but the value doesn't change. Of import here is 'temperature' which I need to vary with slider 2.
Also, winsound won't play anything and my sliders aren't labeled. What the heck is going on here?
import winsound
import pygame
import time
from visual.controls import *
from visual.graph import *
from math import *
temperature = 50
funct1 = gcurve(color=(temperature*0.04, (temperature*0.04)-2, (temperature*0.04)-2))
for x in arange (0., 100.1, 0.1):
funct1.plot(pos=(x,5.*cos(2.*x)))
def setdir(direction):
cube.dir = direction
def setrate(obj): # called on slider drag events
cuberate(obj.value) # value is min-max slider position
def cuberate(value):
cube.dtheta = 2*value*pi/1e3
def woosh(sound):
winsound.playsound('%s.wav' % sound, winsound.sphere.wav)
x=0
y=0
z=0
w = 350
display(x=w, y=0, width=w, height=w, range=1.5, forward=-vector(0,0,1), newzoom=1)
c = controls(x=0, y=0, width=w, height=w, range=60)
ctrl = slider(pos=(-50,20), width=7, length=100, axis=(1,0,0), text='Temperature', min=0., max=100., value=temperature)
s1 = slider(pos=(-50,40), width=7, length=100, axis=(1,0,0), text='Angular Velocity', action=lambda: setrate(s1))
cube = sphere(color=(temperature*0.04, (temperature*0.04)-2, (temperature*0.04)-2), material=materials.rough, pos=(x,y,z))
sphere.velocity = vector(x,y,z)
setrate(s1)
setdir(-1)
side = .4
thk = 0.3
t=0
dt=0.1
while True:
rate(100)
cube.p = vector (sin(t*0.02*temperature),sin(t*0.03*temperature),sin(t*0.04*temperature))
cube.rotate(axis=(0,1,0), angle=cube.dir*cube.dtheta)
t = t + dt
cube.pos = cube.p*sin(t*temperature/100)/5
woosh
if not (side > cube.x > -side):
cube.p.x = -cube.p.x
if not (side > cube.y > -side):
cube.p.y = -cube.p.y
if not (side > cube.z > -side):
cube.p.z = -cube.p.z
I think it was an oversight of the letter "s" in the word value. Replace value with values ​​in line ctrl:
ctrl = slider(pos=(-50,20), width=7, length=100, axis=(1,0,0), text='temperature', min=0, max=50, values = temperature)

Resources