Automatically resizing text with window size in tkinter calculator - python-3.x

I have been working on a tkinter calculator in Python 3.8, with basic buttons and an entry field. I want the text in the buttons and entry field to increase (or decrease) size with the window automatically, in proportion with the buttons themselves -- have yet to work on the entry field font sizes -- and, despite trying for a while, have failed. At certain sizes, the font collapses to the minimum size (see code below) or starts phasing rapidly. It also collapses to minimum size when the window is moved.
# Default font size
fontsize = tkFont.Font(size=11)
def font_change(event):
# Base size
normal_width = 418
normal_height = 295
# Screen
screen_width = event.width
screen_height = event.height
# Get percentage of screen size from Base size
percentage_width = screen_width / (normal_width / 100)
percentage_height = screen_height / (normal_height / 100)
# Make a scaling factor
scale_factor = ((percentage_width + percentage_height) / 2) / 100
# Set the fontsize based on scale_factor,
# if the fontsize is less than minimum_size
# it is set to the minimum size
# font_size is the variable to store actual size
minimum_size = 8
if scale_factor > minimum_size/18:
font_size = int(18 * scale_factor)
else:
font_size = minimum_size
fontsize.configure(size = font_size)
I bind the function to an event:
root.bind("<Configure>", font_change)
Example of a button,
decimal = Button(
root,
text=".",
command=lambda: press("."),
font = fontsize,
height = 2,
width=7)
decimal.grid(row=6, column=2, sticky=NW + NE + SW + SE)
It would be appreciated if someone can help me out.

I constructed a test GUI with two Labels. root.bind( "&LT;Configure&GT;", func ) is fired each time root or any of it's children resize. Code below. When the Labels fire the configure event the font is minimised. Which fires the configure event again, even smaller etc.
import tkinter as tk
from tkinter import font
root = tk.Tk()
root.geometry( "200x100" )
fontsize = font.Font( size = 11 )
tk.Label( root, text = 'Test', font = fontsize ).grid( padx = 5, pady = 5 )
tk.Label( root, text = 'Another Test', font = fontsize ).grid( padx = 5, pady = 5 )
def font_change(event):
print( event.widget, event ) # See what is happening
# Base size
normal_width = 200
normal_height = 100
# Screen
screen_width = event.width
screen_height = event.height
print( event.widget, event )
# Get percentage of screen size from Base size
percentage_width = screen_width / (normal_width / 100)
percentage_height = screen_height / (normal_height / 100)
minimum_size = 8
# Make a scaling factor
scale_factor = ((percentage_width + percentage_height) / 2) / 100
# Set the fontsize based on scale_factor,
# if the fontsize is less than minimum_size
# it is set to the minimum size
# font_size is the variable to store actual size
if scale_factor > minimum_size/18:
font_size = int(18 * scale_factor)
else:
font_size = minimum_size
fontsize.configure( size = font_size )
root.bind( '<Configure>', font_change )
root.mainloop()
One option is to replace the print statement in the above code with
if event.widget != root:
return None # Jump out of the function if the widget firing configure isn't root
Another option would be to read the root width and height in the font_change function, not take the width and height from event.

Related

How to revise the visualization_utils.py to show the class_name in chinese

In visualize_boxes_and_labels_on_image_array function:
class_name = category_index[classes[i]]['name']
if(class_name == 'a'):
class_name = '我我我我'
In draw_bounding_box_on_image function:
try:
font = ImageFont.truetype('Arial.ttf', 40)
except IOError:
font = ImageFont.load_default()
# If the total height of the display strings added to the top of the bounding
# box exceeds the top of the image, stack the strings below the bounding box
# instead of above.
display_str_heights = [font.getsize(ds)[1] for ds in display_str_list]
# Each display_str has a top and bottom margin of 0.05x.
total_display_str_height = (1 + 2 * 0.05) * sum(display_str_heights)
if top > total_display_str_height:
text_bottom = top
else:
text_bottom = bottom + total_display_str_height
# Reverse list and print from bottom to top.
for display_str in display_str_list[::-1]:
text_width, text_height = font.getsize(display_str)
margin = np.ceil(0.05 * text_height)
draw.rectangle(
[(left, text_bottom - text_height - 2 * margin), (left + text_width,
text_bottom)],
fill=color)
draw.text(
(left + margin, text_bottom - text_height - margin),
display_str,
fill='black',
font=font)
text_bottom -= text_height - 2 * margin
But the class_name will show:
this
How can I save this problem?
Thanks
I saved use MSfont.ttf in above try...

How to resize image by mainitaining aspect ratio in python3?

I have an image with image.shape=(20,10)and I want to resize this image so that new image size would be image.size = 90.
I want to use np.resize(image,(new_width, new_height)), but how can I calculate new_width and new_height, so that it maintains aspect_ratio as same as in original image.
Well, you choose which dimension you want to enforce and then you adjust the other one by calculating either new_width = new_height*aspect_ratio or new_height = new_width/aspect_ratio.
You might want to round those numbers and convert them to int too.
The height of your image is 20 and the width is 10, so the height is 2x the width, i.e.
h = 2 * w
You want your new image to have an area of 90 pixels, and the area (A) is:
A = h * w
90 = 2 * w * w
w = sqrt(45)
So the sides of your image need to be 6.7 and 13.4
I hope that helps, even if I doubt it will.
You can use this simple function for finding the new height of an image with width as an input
def findHeight(original_width, original_height, new_width):
area = original_width * original_height
new_height = area/new_width
return new_height

Win32 Excel: Resize image to cell maintaining aspect ratio

I'm writing a script that given an image and its containing cell should resize the image to fit that cell while preserving it's aspect ratio.
The function takes 3 parameters, the image, the width of the cell and the height of the cell.
I've written the following function so far:
def fitToCell(img, width, height):
ratioX = width / img.Width
ratioY = height / img.Height
if ratioX * img.Height > height:
ratio = ratioY
else:
ratio = ratioX
img.Width = img.Width * ratio
img.Height = img.Height * ratio
return img
My logging gives me the following result:
Original Image: (48.0, 35.26598358154297)
Desired Image: (100, 100)
Ratios: (2.0833333333333335, 2.8355936753834547)
Final Ratio: 2.0833333333333335
Final Image: (208.33331298828125, 153.0640869140625)
This doesnt seem to make any sense to me as 2 * 48 = 96, not 208. The ratio should produce the output 100, 73.
I'm using the win32com api with Python on xlsx files. I would really appreciate any suggestions.
This is my modified code, which can achieve the desired results.
My build environment is WIN10, python 3.7
from PIL import Image
def fitToCell(img, width, height):
try:
ratioX = width / img.width
ratioY = height / img.height
if ratioX * img.height > height:
ratio = ratioY
else:
ratio = ratioX
Width = img.width * ratio
Height = img.height * ratio
print("Original Image :",img.width, img.height)
print("Ratios :",ratioX, ratioY)
print("Final Ratio :",ratio)
print("Final Image :",Width, Height)
except IOError:
pass
if __name__ == "__main__":
img = Image.open("panda.jpg")
fitToCell(img, 400, 400)
Debug Result:
Original Image : 268 304
Ratios : 1.492537313432836 1.3157894736842106
Final Ratio : 1.3157894736842106
Final Image : 352.63157894736844 400.0
The difference is that I use the image module.
The Image module provides a class with the same name which is used to
represent a PIL image. The module also provides a number of factory
functions, including functions to load images from files, and to
create new images.

Scrollregions height won't go more than 4000

My scrollregion height won't go any more than 4000. It doesn't change the height when I set it to 10000.
I've tried to change the Canvas height by adding 100+ to it
from tkinter import *
from tkinter import ttk
FrameU = Tk()
FrameNU=Frame(FrameU,width=540,height=800,bg="#A0522D")
FrameNU.place(x=0,y=0,relx=.2,rely=.2)
rx = .5
ry = .5
wCanvas, hCanvas = 550, 700 # size of canvas
w1, h1 = 0, 4000 # size of scrollable area
vBar = ttk.Scrollbar(FrameNU, orient = VERTICAL)
canvas_Main = Canvas(FrameNU,bg="#A0522D" ,scrollregion = (0,0,w1,h1), width = wCanvas, height = hCanvas, yscrollcommand = vBar.set)
vBar['command'] = canvas_Main.yview
vBar.pack(side=RIGHT,fill=Y)
canvas_Main.pack()
canvas_Main.create_line(10, 10, 100, 100) #Test if it works
#Buttons setup below over 160... Only added 1
MS = Button(canvas_Main,height=3,width=6,bg="blue")
def VscrollBarMove(event):
MS.place(relx = rx, rely = ry - vBar.get()[0])
#... More placements just added one
vBar.bind('<B1-Motion>', VscrollBarMove)
mainloop()
No errors. When I changed the height from 4000 to 10000 it didn't change anything but made the scrollbar look smaller as if it had more area going down but it doesn't.
Your code is correct in the sense of the Python (and the Tkinter) syntax. I modified it slightly to proof it's correctness. (Of course, all of new lines are not obligatory.)
1. Let's open the window to a full screen:
FrameU = Tk() # The existing string
windowHeight = FrameU.winfo_screenheight()
windowWidth = FrameU.winfo_screenwidth()
FrameU.geometry('{}x{}'.format(windowWidth, windowHeight))
FrameU.state('zoomed')
2. I changed the vertical position of the second frame for full view of the vertical scrollbar (on my current 1280 x 768 screen):
FrameNU.place(x=0,y=0,relx=.2,rely=.05) # the old rely was 0.2
3. New variable for the big canvas:
w1, h1 = 0, 4000 # size of scrollable area # the exisiting string
h2 = 10000 # the new variable
And we use this new variable instead h1:
canvas_Main = Canvas(FrameNU, ... ,scrollregion = (0,0,w1,h2), ... ) # Here h2 - the only change
Reference lines for the scrollbar correct behavior proof, as Bryan Oakley adviced.
canvas_Main.create_line(10, h1-5, 100, h1-5, fill = 'green')
canvas_Main.create_line(10, h2-5, 100, h2-5, fill = 'blue') # before VscrollBarMove function definition
That's all.
When I changed the height from 4000 to 10000 it didnt change anything but made the scrollbar look smaller as if it had more area going down but it doesn't.
That's precisely what changing the scrollregion does. It changes the part of the canvas that can be scrolled into view, which in turn affects how the thumb of the scrollbar is drawn. It doesn't matter whether you've drawn in that region or not.
You can see that it works by setting the height to 10000, and then drawing something at y coordinate 9000. When you scroll, that item will come into view.

python reportlab barcode code128 size

i want to create a label (57*32mm) with a code128 barcode.
Its all fine but the barcode is to small =(
How can i make this barcode bigger ?
from reportlab.graphics.barcode import code128
from reportlab.lib.units import mm
from reportlab.pdfgen import canvas
c = canvas.Canvas("test.pdf")
c.setPageSize((57*mm,32*mm))
barcode = code128.Code128("123456789")
barcode.drawOn(c, 2*mm, 20*mm)
c.showPage()
c.save()
By looking up the source code for reportlab on GitHub, I found out that the barcode object has a width property.
By simply using
canvas.saveState()
canvas.translate(2*cm, 3*cm) # bottom left corner of the barcode
canvas.scale(15*cm / barcode.width, 2*cm / barcode.height) # resize (15 cm and 2 cm)
barcode.drawOn(canvas, 0, 0)
canvas.restoreState()
You can obtain the obtain of the exact size you desire.
The total width of the barcode is bar_width * total_char_widths + quiet space
So.. the correct barWidth can be determined by
from reportlab.graphics.barcode import code128
final_size = 100 # arbitrary
# setting barWidth to 1
initial_width = .1
barcode128 = code128.Code128(barcode_value, humanReadable=True, barWidth=initial_width,
barHeight=1)
# creates the barcode, computes the total size
barcode128._calculate()
# the quiet space before and after the barcode
quiet = barcode128.lquiet + barcode128.rquiet
# total_wid = barWidth*charWid + quiet_space
# char_wid = (total_width - quiet) / bar_width
char_width = (barcode128._width - quiet) / barcode128.barWidth
# now that we have the char width we can calculate the bar width
bar_width = (final_size - quiet) / char_width
# set the new bar width
barcode128.barWidth = bar_width
# re-calculate
barcode128._calculate()
# draw the barcode on the canvas
wid, hgt = barcode128._width, barcode128._height
x_pos = y_pos = final_size # arbitrary
barcode128.drawOn(your_canvas, x_pos, y_pos)
You can set the barcode size by barHeight and barWidth:
barcode = code128.Code128("123456789",barHeight=.9*inch,barWidth = 1.2)
I finaly found the answer to that with other bits of non-working snipet of code
from reportlab.graphics.barcode import code128
from reportlab.lib.units import mm, inch, cm, pica
from reportlab.pdfgen import canvas
code = "asdasda" #remove this if in function
c = canvas.Canvas(f"{code}.pdf")
page_width = 550 # page width
# add specific unit here as x= num*unit
# pica,mm and no unit works, I don't know why the 2 other don't
page_height = 200 # page height
# add specific unit here as x= num*unit
# pica,mm and no unit works, I don't know why the 2 other don't
margin_y = 10 # top/bottom margin
# add specific unit here as x= num*unit
# pica,mm and no unit works, I don't know why the 2 other don't
bar_height = page_height - (margin_y * 2) # barcode line height
bar_width = page_width / (11 * len(str(code)) + 55) # barcode individual width has the formula
# page width / (11*string_length) + 55 ##(I also saw +35 but in my test it was not working)
c.setPageSize((page_width, page_height)) # set page to said mesure
humanReadable = True # with or without text
barcode = code128.Code128(code,
barHeight=bar_height,
barWidth=bar_width,
humanReadable=humanReadable)
drawon_x = 0 # x value for drawing already has a margin (not like Y) bar with formula account for that
if humanReadable:
drawon_y = page_height - margin_y - bar_height # if text reduce bar height to hace the correct value
else:
drawon_y = page_height - bar_height # set draw point to the top of the page - the height of the drawn barcode
barcode.drawOn(c, drawon_x, drawon_y) # do the drawing
c.save() # save pdf
if you want multiple separate barcode pas a list of code like this
def createSinglePDFBarcode(code):
#code from above here
if __name__ == "__main__":
import random
import string
num = 5
# Generate {num} random numbers between 10 and 30
# printing uppercase
letters = string.ascii_uppercase
randomSList =[] #list of code you want as barcode
for x in range(num):
randomSList.append(''.join(random.choice(letters) for i in range(10)))
for x in randomSList: # for each code make a barcode
createSinglePDFBarcode(x)

Resources