Home > Net >  Is it possible to somehow smooth the font and get rid of "artifacts" when using the transp
Is it possible to somehow smooth the font and get rid of "artifacts" when using the transp

Time:08-03

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.
  • Related