I tried to create a simple application using TKinter, which generally works to my liking. However, with the use of a transparent form, there was some aesthetic problem. The font I used on hover on a black background gives white pixel frames.
Is it possible to somehow get rid of such "artifacts"? With the use of cleartype "artifacts" become less, but they remain, which makes the application ugly.
Here is my fairly simple code:
from tkinter import *
import tkinter.font
import sys
import pyglet
from datetime import datetime, timedelta
import re
bgc = "#ffffff"
fgc = "#e34646"
pyglet.font.add_file("digital_7mono.ttf")
def timer(start_time):
now_time = datetime.now()
delta = now_time-start_time
delta = '{:02d}'.format(delta.days//3600) ":" \
'{:02d}'.format(delta.seconds//60) ":" \
'{:02d}'.format(delta.seconds)
#delta = delta.strftime("%H:%M:%S")
return [delta, now_time]
class timerWindows(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
self.overrideredirect(True)
self.title("Timer")
self.geometry('420x110')
self.wm_attributes("-topmost", True)
#self.wm_attributes("-disabled", True)
self.wm_attributes("-transparentcolor", "white")
self.resizable(width=False, height=False)
self.configure(bg = bgc)
font = tkinter.font.Font(family="digital-7 Mono", size=80)
#self.start_time.strftime("%H:%M:%S")
self.l1 = Label(text = "00:00:00", bg = bgc, font=font, )#fg = fgc)
self.l1.configure()
self.l1.grid(row=0, column=0, )#padx=5, sticky=NW)
self.grid_rowconfigure(0, weight=1)
self.grid_columnconfigure(0, weight=1)
self.bind("<Button-1>", self.form_click)
self.bind('<Double-Button-1>', self.double_form_click)
self.bind('<B1-Motion>', self.on_drag)
self.menu = tkinter.Menu(self, tearoff=0)
self.menu.add_command(label="Закрыть", command=self.close_time)
self.bind("<Button-3>", self.show_popup)
#self.text.grid()
self.start_time = datetime.now()
self.pause_time = self.start_time
self.checkpoint = True
self.time_delta = timedelta(0)
def on_drag(self, event):
rect = re.fullmatch(r'\d x\d \ (?P<x>-?\d )\ (?P<y>-?\d )',
self.geometry()).groupdict()
# NOTE: self.winfo_root*() is content's coordinate without window decorations
x = int(rect['x']) (event.x - self.start_x)
y = int(rect['y']) (event.y - self.start_y)
self.geometry(f' {x} {y}')
def show_popup(self, event):
self.menu.tk_popup(event.x_root, event.y_root)
def close_time(self):
self.quit()
def form_click(self, event):
self.start_x = event.x
self.start_y = event.y
if self.checkpoint==True:
self.checkpoint=False
else:
self.checkpoint = True
self.start_reading(self.checkpoint)
def double_form_click(self, event):
self.checkpoint=False
self.start_time = datetime.now()
self.pause_time = self.start_time
self.time_delta = timedelta(0)
self.l1['text']="00:00:00"
def start_reading(self, arg):
if arg:
if self.pause_time>self.start_time:
self.start_time=datetime.now()
start_time_return = timer(self.start_time-self.time_delta)
self.l1['text'] = start_time_return[0]
self.l1.update()
self.after(1000, self.start_reading, self.checkpoint) # repeat the call
if not arg:
self.pause_time=datetime.now()
self.time_delta = self.time_delta (self.pause_time-self.start_time)
def main(argv):
window = timerWindows()
window.after(1000, window.start_reading, True)
window.mainloop()
if __name__ == '__main__':
main(sys.argv)
CodePudding user response:
After looking around for a while, it seems like there's no legitimate way to remove those "artifacts."
However, I believe that if you were to set your variable bgc
to something close to, but not the same as, black (say #000001
), it would be such a small difference in color the artifacts would become unnoticeable.
Remember to also set the transparent color to the new background color.
self.wm_attributes("-transparentcolor", bgc)
Edit after comment:
I'm not certain what you mean by principle, but what I'm guessing is you want a way to dynamically change the color and still have no artifacts.
So what we'll have to do is set bgc
to always be 1 value away from fgc
.
We can do this by converting the hex value to an integer and incrementing. Then converting the new value to a hex code.
First, let's set fgc
to a hex code.
fgc = "#000000"
Next, let's configure fgc
into a new variable (fgc_
) so we can convert it to an integer. We'll remove the # with a replace()
and use int
's built-in hex to base-10 conversion. (The 16
parameter)
fgc_ = int(fgc.replace("#", ""), 16)
#output of above line
fgc_ = 0
We can use .format()
to set the variable bgc
to the incremented value:
bgc = '#{:06x}'.format(fgc_ 1)
This line ensures bgc
will only be 6 characters long (not including the #).
Note that since we are incrementing positively, the value #ffffff
will not work. But, as I mentioned above, you could use a value incredibly close to that (#fffffe
) and it will work just fine without being noticeable to the naked eye.
I hope this was closer to what you were looking for!
Here is the final code:
fgc = "#000000" #whatever you want it to be (except #ffffff)
fgc_ = int(fgc.replace("#", ""), 16) #remove pound and convert from base-16 to base-10
bgc = '#{:06x}'.format(fgc_ 1) #increment 1 and format back to hex.