for my application I designed a simple on screen keyboard (OSK), it is needed on touchscreens but may be used also with the mouse. Initially the happlication had to run on 1920x1080 screens only, but now I have many requests to port on different resolutions. The problem is that the OSK was designed in the simplest way to fulfill the 1920x1080 screen so I adapted the font to obtain the right width for the buttons set to 4, where 4 is the number of chars may be shown in the button. But now, to adapt the OSK to every resolution I should calculate the width of the buttons. The OSK has 14 columns, special buttons as Shift, Enter, Backspace, Tab etc. have a width of 2 columns (they extend on 2 columns) and there is an horizontal padding of 10 piels between the buttons and the external limit of the OSK, so there are 15 "spacers" for 14 columns of buttons. I am able to compute the buttons width in pixels but I am not able to set the buttons width in pixels... only in number of characters. Is there anything I missed? Or does exist a workaround? If may help I can set the font to a common non proprotional one. I made a little test program to see if is possible to set the width in pixels of a ttk.Button, seems I am not able to do it:
def testButtonsType():
def select(choice):
choice = choice
if choice=="yes":
print("yes")
else:
print("no")
#---------------------------------------------------------------------------
mainWin = Tk()
mainWin.title("Main Window")
mainWin.geometry('400x250')
pixel = tk.PhotoImage(width=1, height=1)
s = ttk.Style()
s.configure("osk.TButton",foreground="black",
background="white",
height=50,
# padding=[10, 10, 10, 10],
font = "None 14 bold")
btnYes = ttk.Button(mainWin, text='SI', image=pixel, compound='c', width=200, style="osk.TButton", command=lambda: select("yes"))
btnYes.grid(pady=(20,30), sticky='n', column=1, row=0)
btnNo = tk.Button(mainWin, text='NO', image=pixel, compound='c', width=100, height=50, font = ("None 14 bold"), command=lambda: select("no"))
btnNo.grid(padx=(20,20), pady=(20,30), sticky='n', column=0, row=0)
mainWin.mainloop()
#-------------------------------------------------------------------------
This is a simplified implementation of OSK class, it manages only the first row of buttons and assumes they have all the same width. The OSK is done for a 1600x900 screen but the width of the button is larger so only 11 and one third of the 12st button are visible. Obviously something is wrong but I do not understand what is wrong.
class OSK(Toplevel):
__metaclass__ = Singleton
def __init__(self, attach, rootWin, flgCloseOnEnter=True):
super().__init__()
self.title('On Screen Keyboard')
self.flgCloseOnEnter = flgCloseOnEnter
rW = 1600
rH = 900
oskHeight = 260
keyColsCount = 14
keysRowCount = 5
padXleft = 10
padYleft = 10
self.btnW = 5
self.btnH = 32
self.style = ttk.Style()
self.theme = "dark"
self.Theme()
self.geometry('%dx%d+%d+%d' % (rW, oskHeight, 0, rH-oskHeight))
self.frmTop = Frame(self, style="osk.TFrame")
self.grid_columnconfigure(0,weight=0)
# self.frmTop.grid(padx=(padXleft,padXleft), pady=(padYleft,padYleft), sticky='nwse')
self.frmTop.grid(sticky='nwse')
for i in range(15):
self.frmTop.grid_columnconfigure(i, minsize=self.btnW, weight=0)
for i in range(5):
self.frmTop.grid_rowconfigure(i, minsize=self.btnH)
self.mainWin = self
self.btnPadX = 10
self.btnPadY = 4
# showing all data in display
self.exp = " "
self.is_shift = False
self.attach = attach
self.overrideredirect(True)
tick = Button(self.frmTop, text='`', command=lambda: self.press('`'), style="osk.TButton")
tick.grid(row=0, column=0, sticky='nwes')
num1 = Button(self.frmTop, text='1', command=lambda: self.press('1'), style="osk.TButton")
num1.grid(row=0, column=1, sticky='nwes')
num2 = Button(self.frmTop, text='2', command=lambda: self.press('2'), style="osk.TButton")
num2.grid(row=0, column=2, sticky='nwes')
num3 = Button(self.frmTop, text='3', command=lambda: self.press('3'), style="osk.TButton")
num3.grid(row=0, column=3, sticky='nwes')
num4 = Button(self.frmTop, text='4', command=lambda: self.press('4'), style="osk.TButton")
num4.grid(row=0, column=4, sticky='nwes')
num5 = Button(self.frmTop, text='5', command=lambda: self.press('5'), style="osk.TButton")
num5.grid(row=0, column=5, sticky='nwes')
num6 = Button(self.frmTop, text='6', command=lambda: self.press('6'), style="osk.TButton")
num6.grid(row=0, column=6, sticky='nwes')
num7 = Button(self.frmTop, text='7', command=lambda: self.press('7'), style="osk.TButton")
num7.grid(row=0, column=7, sticky='nwes')
num8 = Button(self.frmTop, text='8', command=lambda: self.press('8'), style="osk.TButton")
num8.grid(row=0, column=8, sticky='nwes')
num9 = Button(self.frmTop, text='9', command=lambda: self.press('9'), style="osk.TButton")
num9.grid(row=0, column=9, sticky='nwes')
numA = Button(self.frmTop, text='A', command=lambda: self.press('A'), style="osk.TButton")
numA.grid(row=0, column=10, sticky='nwes')
numB = Button(self.frmTop, text='B', command=lambda: self.press('B'), style="osk.TButton")
numB.grid(row=0, column=11, sticky='nwes')
numC = Button(self.frmTop, text='C', command=lambda: self.press('C'), style="osk.TButton")
numC.grid(row=0, column=12, sticky='nwes')
numD = Button(self.frmTop, text='D', command=lambda: self.press('D'), style="osk.TButton")
numD.grid(row=0, column=13, sticky='nwes')
numE = Button(self.frmTop, text='E', command=lambda: self.press('E'), style="osk.TButton")
numE.grid(row=0, column=14, sticky='nwes')
#---------------------------------------------------------------------------
# Needed functions
def getAttach(self):
return self.attach
#---------------------------------------------------------------------------
def setAttach(self, org):
self.attach = org
#---------------------------------------------------------------------------
def press(self, num):
print(num)
#---------------------------------------------------------------------------
def Backspace(self):
n = len( self.attach.get() )
self.attach.delete(n-1)
#---------------------------------------------------------------------------
def Enter(self):
if self.flgCloseOnEnter == True:
self.destroy()
else:
self.attach.insert(END, '\n')
#---------------------------------------------------------------------------
def Shift(self):
if True:
self.is_shift = not self.is_shift
self.display()
else:
self.is_shift = not self.is_shift
self.display()
#---------------------------------------------------------------------------
def Clear(self):
self.attach.delete(0, END)
#---------------------------------------------------------------------------
def Theme(self):
font = (None, 16)
if True:
if self.theme == "dark":
self.configure(bg='gray27')
self.style.configure('osk.TButton', background='gray21', foreground='black', font=font)
self.style.configure('osk.TEntry', background='gray21', foreground='black')
self.style.configure('osk.TFrame', bg='gray27')
self.theme = "light"
elif self.theme == "light":
self.configure(bg='gray99')
self.style.configure('osk.TButton', background='azure', foreground='black', font=font)
self.style.configure('osk.TEntry', background='azure', foreground='black')
self.style.configure('osk.TFrame', bg='gray99')
self.theme = "dark"
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
#---------------------------------------------------------------------------
if __name__ == '__main__':
def testMinOSK():
mainWin = Tk()
top = OSK(None, mainWin)
mainWin.mainloop()
#-------------------------------------------------------------------------
testMinOSK()
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
#-------------------------------------------------------------------------
If you give the button an image, the width
and height
parameters are treated as pixels rather than a number of characters. So, you can create a 1x1 transparent pixel (eg: tk.PhotoImage(width=1, height=1)
) and add that to a button along with the text (and setting compound
to something reasonable). That will let you define the size of a button in pixels.
Alternately, you can add a single button to a frame with no borders, and use place
with options to cause it to fully fill the frame. You can then set the frame width and height in pixels, and the button will fill that frame.